wpa_ft.c

Go to the documentation of this file.
00001 
00016 #include "includes.h"
00017 
00018 #include "common.h"
00019 #include "config.h"
00020 #include "wpa.h"
00021 #include "aes_wrap.h"
00022 #include "ieee802_11.h"
00023 #include "wme.h"
00024 #include "defs.h"
00025 #include "wpa_auth_i.h"
00026 #include "wpa_auth_ie.h"
00027 
00028 
00029 #ifdef CONFIG_IEEE80211R
00030 
00031 struct wpa_ft_ies {
00032         const u8 *mdie;
00033         size_t mdie_len;
00034         const u8 *ftie;
00035         size_t ftie_len;
00036         const u8 *r1kh_id;
00037         const u8 *gtk;
00038         size_t gtk_len;
00039         const u8 *r0kh_id;
00040         size_t r0kh_id_len;
00041         const u8 *rsn;
00042         size_t rsn_len;
00043         const u8 *rsn_pmkid;
00044         const u8 *ric;
00045         size_t ric_len;
00046 };
00047 
00048 
00049 static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
00050                             struct wpa_ft_ies *parse);
00051 
00052 
00053 static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
00054                            const u8 *data, size_t data_len)
00055 {
00056         if (wpa_auth->cb.send_ether == NULL)
00057                 return -1;
00058         return wpa_auth->cb.send_ether(wpa_auth->cb.ctx, dst, ETH_P_RRB,
00059                                        data, data_len);
00060 }
00061 
00062 
00063 static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth,
00064                               const u8 *dst, const u8 *data, size_t data_len)
00065 {
00066         if (wpa_auth->cb.send_ft_action == NULL)
00067                 return -1;
00068         return wpa_auth->cb.send_ft_action(wpa_auth->cb.ctx, dst,
00069                                            data, data_len);
00070 }
00071 
00072 
00073 static struct wpa_state_machine *
00074 wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
00075 {
00076         if (wpa_auth->cb.add_sta == NULL)
00077                 return NULL;
00078         return wpa_auth->cb.add_sta(wpa_auth->cb.ctx, sta_addr);
00079 }
00080 
00081 
00082 int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
00083 {
00084         u8 *pos = buf;
00085         u8 capab;
00086         if (len < 2 + sizeof(struct rsn_mdie))
00087                 return -1;
00088 
00089         *pos++ = WLAN_EID_MOBILITY_DOMAIN;
00090         *pos++ = MOBILITY_DOMAIN_ID_LEN + 1;
00091         os_memcpy(pos, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN);
00092         pos += MOBILITY_DOMAIN_ID_LEN;
00093         capab = RSN_FT_CAPAB_FT_OVER_DS;
00094         *pos++ = capab;
00095 
00096         return pos - buf;
00097 }
00098 
00099 
00100 static int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
00101                           size_t r0kh_id_len,
00102                           const u8 *anonce, const u8 *snonce,
00103                           u8 *buf, size_t len, const u8 *subelem,
00104                           size_t subelem_len)
00105 {
00106         u8 *pos = buf, *ielen;
00107         struct rsn_ftie *hdr;
00108 
00109         if (len < 2 + sizeof(*hdr) + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
00110             subelem_len)
00111                 return -1;
00112 
00113         *pos++ = WLAN_EID_FAST_BSS_TRANSITION;
00114         ielen = pos++;
00115 
00116         hdr = (struct rsn_ftie *) pos;
00117         os_memset(hdr, 0, sizeof(*hdr));
00118         pos += sizeof(*hdr);
00119         WPA_PUT_LE16(hdr->mic_control, 0);
00120         if (anonce)
00121                 os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
00122         if (snonce)
00123                 os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
00124 
00125         /* Optional Parameters */
00126         *pos++ = FTIE_SUBELEM_R1KH_ID;
00127         *pos++ = FT_R1KH_ID_LEN;
00128         os_memcpy(pos, conf->r1_key_holder, FT_R1KH_ID_LEN);
00129         pos += FT_R1KH_ID_LEN;
00130 
00131         if (r0kh_id) {
00132                 *pos++ = FTIE_SUBELEM_R0KH_ID;
00133                 *pos++ = r0kh_id_len;
00134                 os_memcpy(pos, r0kh_id, r0kh_id_len);
00135                 pos += r0kh_id_len;
00136         }
00137 
00138         if (subelem) {
00139                 os_memcpy(pos, subelem, subelem_len);
00140                 pos += subelem_len;
00141         }
00142 
00143         *ielen = pos - buf - 2;
00144 
00145         return pos - buf;
00146 }
00147 
00148 
00149 struct wpa_ft_pmk_r0_sa {
00150         struct wpa_ft_pmk_r0_sa *next;
00151         u8 pmk_r0[PMK_LEN];
00152         u8 pmk_r0_name[WPA_PMK_NAME_LEN];
00153         u8 spa[ETH_ALEN];
00154         /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
00155         int pmk_r1_pushed;
00156 };
00157 
00158 struct wpa_ft_pmk_r1_sa {
00159         struct wpa_ft_pmk_r1_sa *next;
00160         u8 pmk_r1[PMK_LEN];
00161         u8 pmk_r1_name[WPA_PMK_NAME_LEN];
00162         u8 spa[ETH_ALEN];
00163         /* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
00164 };
00165 
00166 struct wpa_ft_pmk_cache {
00167         struct wpa_ft_pmk_r0_sa *pmk_r0;
00168         struct wpa_ft_pmk_r1_sa *pmk_r1;
00169 };
00170 
00171 struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void)
00172 {
00173         struct wpa_ft_pmk_cache *cache;
00174 
00175         cache = os_zalloc(sizeof(*cache));
00176 
00177         return cache;
00178 }
00179 
00180 
00181 void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache)
00182 {
00183         struct wpa_ft_pmk_r0_sa *r0, *r0prev;
00184         struct wpa_ft_pmk_r1_sa *r1, *r1prev;
00185 
00186         r0 = cache->pmk_r0;
00187         while (r0) {
00188                 r0prev = r0;
00189                 r0 = r0->next;
00190                 os_memset(r0prev->pmk_r0, 0, PMK_LEN);
00191                 os_free(r0prev);
00192         }
00193 
00194         r1 = cache->pmk_r1;
00195         while (r1) {
00196                 r1prev = r1;
00197                 r1 = r1->next;
00198                 os_memset(r1prev->pmk_r1, 0, PMK_LEN);
00199                 os_free(r1prev);
00200         }
00201 
00202         os_free(cache);
00203 }
00204 
00205 
00206 static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
00207                                const u8 *spa, const u8 *pmk_r0,
00208                                const u8 *pmk_r0_name)
00209 {
00210         struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
00211         struct wpa_ft_pmk_r0_sa *r0;
00212 
00213         /* TODO: add expiration and limit on number of entries in cache */
00214 
00215         r0 = os_zalloc(sizeof(*r0));
00216         if (r0 == NULL)
00217                 return -1;
00218 
00219         os_memcpy(r0->pmk_r0, pmk_r0, PMK_LEN);
00220         os_memcpy(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
00221         os_memcpy(r0->spa, spa, ETH_ALEN);
00222 
00223         r0->next = cache->pmk_r0;
00224         cache->pmk_r0 = r0;
00225 
00226         return 0;
00227 }
00228 
00229 
00230 static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
00231                                const u8 *spa, const u8 *pmk_r0_name,
00232                                u8 *pmk_r0)
00233 {
00234         struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
00235         struct wpa_ft_pmk_r0_sa *r0;
00236 
00237         r0 = cache->pmk_r0;
00238         while (r0) {
00239                 if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
00240                     os_memcmp(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN)
00241                     == 0) {
00242                         os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN);
00243                         return 0;
00244                 }
00245 
00246                 r0 = r0->next;
00247         }
00248 
00249         return -1;
00250 }
00251 
00252 
00253 static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
00254                                const u8 *spa, const u8 *pmk_r1,
00255                                const u8 *pmk_r1_name)
00256 {
00257         struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
00258         struct wpa_ft_pmk_r1_sa *r1;
00259 
00260         /* TODO: add expiration and limit on number of entries in cache */
00261 
00262         r1 = os_zalloc(sizeof(*r1));
00263         if (r1 == NULL)
00264                 return -1;
00265 
00266         os_memcpy(r1->pmk_r1, pmk_r1, PMK_LEN);
00267         os_memcpy(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
00268         os_memcpy(r1->spa, spa, ETH_ALEN);
00269 
00270         r1->next = cache->pmk_r1;
00271         cache->pmk_r1 = r1;
00272 
00273         return 0;
00274 }
00275 
00276 
00277 static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
00278                                const u8 *spa, const u8 *pmk_r1_name,
00279                                u8 *pmk_r1)
00280 {
00281         struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
00282         struct wpa_ft_pmk_r1_sa *r1;
00283 
00284         r1 = cache->pmk_r1;
00285         while (r1) {
00286                 if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
00287                     os_memcmp(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN)
00288                     == 0) {
00289                         os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN);
00290                         return 0;
00291                 }
00292 
00293                 r1 = r1->next;
00294         }
00295 
00296         return -1;
00297 }
00298 
00299 
00300 static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth,
00301                               const u8 *s1kh_id, const u8 *r0kh_id,
00302                               size_t r0kh_id_len, const u8 *pmk_r0_name)
00303 {
00304         struct ft_remote_r0kh *r0kh;
00305         struct ft_r0kh_r1kh_pull_frame frame, f;
00306 
00307         r0kh = wpa_auth->conf.r0kh_list;
00308         while (r0kh) {
00309                 if (r0kh->id_len == r0kh_id_len &&
00310                     os_memcmp(r0kh->id, r0kh_id, r0kh_id_len) == 0)
00311                         break;
00312                 r0kh = r0kh->next;
00313         }
00314         if (r0kh == NULL)
00315                 return -1;
00316 
00317         wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
00318                    "address " MACSTR, MAC2STR(r0kh->addr));
00319 
00320         os_memset(&frame, 0, sizeof(frame));
00321         frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
00322         frame.packet_type = FT_PACKET_R0KH_R1KH_PULL;
00323         frame.data_length = host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN);
00324         os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
00325 
00326         /* aes_wrap() does not support inplace encryption, so use a temporary
00327          * buffer for the data. */
00328         if (os_get_random(f.nonce, sizeof(f.nonce))) {
00329                 wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
00330                            "nonce");
00331                 return -1;
00332         }
00333         os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
00334         os_memcpy(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
00335         os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
00336 
00337         if (aes_wrap(r0kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
00338                      f.nonce, frame.nonce) < 0)
00339                 return -1;
00340 
00341         wpa_ft_rrb_send(wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame));
00342 
00343         return 0;
00344 }
00345 
00346 
00347 int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
00348                            struct wpa_ptk *ptk, size_t ptk_len)
00349 {
00350         u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
00351         u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
00352         u8 ptk_name[WPA_PMK_NAME_LEN];
00353         const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
00354         const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
00355         size_t r0kh_len = sm->wpa_auth->conf.r0_key_holder_len;
00356         const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder;
00357         const u8 *ssid = sm->wpa_auth->conf.ssid;
00358         size_t ssid_len = sm->wpa_auth->conf.ssid_len;
00359 
00360 
00361         if (sm->xxkey_len == 0) {
00362                 wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
00363                            "derivation");
00364                 return -1;
00365         }
00366 
00367         wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
00368                           r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name);
00369         wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
00370         wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
00371         wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name);
00372 
00373         wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
00374                           pmk_r1, pmk_r1_name);
00375         wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
00376         wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
00377         wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, pmk_r1_name);
00378 
00379         wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
00380                           sm->wpa_auth->addr, pmk_r1_name,
00381                           (u8 *) ptk, ptk_len, ptk_name);
00382         wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
00383         wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
00384 
00385         return 0;
00386 }
00387 
00388 
00389 static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
00390                                       const u8 *addr, int idx, u8 *seq)
00391 {
00392         if (wpa_auth->cb.get_seqnum == NULL)
00393                 return -1;
00394         return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
00395 }
00396 
00397 
00398 #ifdef CONFIG_IEEE80211W
00399 static inline int wpa_auth_get_seqnum_igtk(struct wpa_authenticator *wpa_auth,
00400                                            const u8 *addr, int idx, u8 *seq)
00401 {
00402         if (wpa_auth->cb.get_seqnum_igtk == NULL)
00403                 return -1;
00404         return wpa_auth->cb.get_seqnum_igtk(wpa_auth->cb.ctx, addr, idx, seq);
00405 }
00406 #endif /* CONFIG_IEEE80211W */
00407 
00408 
00409 static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
00410 {
00411         u8 *subelem;
00412         struct wpa_group *gsm = sm->group;
00413         size_t subelem_len, pad_len;
00414         const u8 *key;
00415         size_t key_len;
00416         u8 keybuf[32];
00417 
00418         key_len = gsm->GTK_len;
00419         if (key_len > sizeof(keybuf))
00420                 return NULL;
00421 
00422         /*
00423          * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
00424          * than 16 bytes.
00425          */
00426         pad_len = key_len % 8;
00427         if (pad_len)
00428                 pad_len = 8 - pad_len;
00429         if (key_len + pad_len < 16)
00430                 pad_len += 8;
00431         if (pad_len) {
00432                 os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
00433                 os_memset(keybuf + key_len, 0, pad_len);
00434                 keybuf[key_len] = 0xdd;
00435                 key_len += pad_len;
00436                 key = keybuf;
00437         } else
00438                 key = gsm->GTK[gsm->GN - 1];
00439 
00440         /*
00441          * Sub-elem ID[1] | Length[1] | Key Info[1] | Key Length[1] | RSC[8] |
00442          * Key[5..32].
00443          */
00444         subelem_len = 12 + key_len + 8;
00445         subelem = os_zalloc(subelem_len);
00446         if (subelem == NULL)
00447                 return NULL;
00448 
00449         subelem[0] = FTIE_SUBELEM_GTK;
00450         subelem[1] = 10 + key_len + 8;
00451         subelem[2] = gsm->GN & 0x03; /* Key ID in B0-B1 of Key Info */
00452         subelem[3] = gsm->GTK_len;
00453         wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 4);
00454         if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 12)) {
00455                 os_free(subelem);
00456                 return NULL;
00457         }
00458 
00459         *len = subelem_len;
00460         return subelem;
00461 }
00462 
00463 
00464 #ifdef CONFIG_IEEE80211W
00465 static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
00466 {
00467         u8 *subelem, *pos;
00468         struct wpa_group *gsm = sm->group;
00469         size_t subelem_len;
00470 
00471         /* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] |
00472          * Key[16+8] */
00473         subelem_len = 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN + 8;
00474         subelem = os_zalloc(subelem_len);
00475         if (subelem == NULL)
00476                 return NULL;
00477 
00478         pos = subelem;
00479         *pos++ = FTIE_SUBELEM_IGTK;
00480         *pos++ = subelem_len - 2;
00481         WPA_PUT_LE16(pos, gsm->GN_igtk);
00482         pos += 2;
00483         wpa_auth_get_seqnum_igtk(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
00484         pos += 6;
00485         *pos++ = WPA_IGTK_LEN;
00486         if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
00487                      gsm->IGTK[gsm->GN_igtk - 4], pos)) {
00488                 os_free(subelem);
00489                 return NULL;
00490         }
00491 
00492         *len = subelem_len;
00493         return subelem;
00494 }
00495 #endif /* CONFIG_IEEE80211W */
00496 
00497 
00498 static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
00499                                 const u8 *ies, size_t ies_len)
00500 {
00501         struct ieee802_11_elems parse;
00502         struct rsn_rdie *rdie;
00503 
00504         wpa_printf(MSG_DEBUG, "FT: Resource Request: id=%d descr_count=%d",
00505                    id, descr_count);
00506         wpa_hexdump(MSG_MSGDUMP, "FT: Resource descriptor IE(s)",
00507                     ies, ies_len);
00508 
00509         if (end - pos < (int) sizeof(*rdie)) {
00510                 wpa_printf(MSG_ERROR, "FT: Not enough room for response RDIE");
00511                 return pos;
00512         }
00513 
00514         *pos++ = WLAN_EID_RIC_DATA;
00515         *pos++ = sizeof(*rdie);
00516         rdie = (struct rsn_rdie *) pos;
00517         rdie->id = id;
00518         rdie->descr_count = 0;
00519         rdie->status_code = host_to_le16(WLAN_STATUS_SUCCESS);
00520         pos += sizeof(*rdie);
00521 
00522         if (ieee802_11_parse_elems((u8 *) ies, ies_len, &parse, 1) ==
00523             ParseFailed) {
00524                 wpa_printf(MSG_DEBUG, "FT: Failed to parse request IEs");
00525                 rdie->status_code =
00526                         host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
00527                 return pos;
00528         }
00529 
00530 #ifdef NEED_AP_MLME
00531         if (parse.wmm_tspec) {
00532                 struct wmm_tspec_element *tspec;
00533                 int res;
00534 
00535                 if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) {
00536                         wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE "
00537                                    "(%d)", (int) parse.wmm_tspec_len);
00538                         rdie->status_code =
00539                                 host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
00540                         return pos;
00541                 }
00542                 if (end - pos < (int) sizeof(*tspec)) {
00543                         wpa_printf(MSG_ERROR, "FT: Not enough room for "
00544                                    "response TSPEC");
00545                         rdie->status_code =
00546                                 host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
00547                         return pos;
00548                 }
00549                 tspec = (struct wmm_tspec_element *) pos;
00550                 os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
00551                 res = wmm_process_tspec(tspec);
00552                 wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res);
00553                 if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS)
00554                         rdie->status_code =
00555                                 host_to_le16(WLAN_STATUS_INVALID_PARAMETERS);
00556                 else if (res == WMM_ADDTS_STATUS_REFUSED)
00557                         rdie->status_code =
00558                                 host_to_le16(WLAN_STATUS_REQUEST_DECLINED);
00559                 else {
00560                         /* TSPEC accepted; include updated TSPEC in response */
00561                         rdie->descr_count = 1;
00562                         pos += sizeof(*tspec);
00563                 }
00564                 return pos;
00565         }
00566 #endif /* NEED_AP_MLME */
00567 
00568         wpa_printf(MSG_DEBUG, "FT: No supported resource requested");
00569         rdie->status_code = host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
00570         return pos;
00571 }
00572 
00573 
00574 static u8 * wpa_ft_process_ric(u8 *pos, u8 *end, const u8 *ric, size_t ric_len)
00575 {
00576         const u8 *rpos, *start;
00577         const struct rsn_rdie *rdie;
00578 
00579         wpa_hexdump(MSG_MSGDUMP, "FT: RIC Request", ric, ric_len);
00580 
00581         rpos = ric;
00582         while (rpos + sizeof(*rdie) < ric + ric_len) {
00583                 if (rpos[0] != WLAN_EID_RIC_DATA || rpos[1] < sizeof(*rdie) ||
00584                     rpos + 2 + rpos[1] > ric + ric_len)
00585                         break;
00586                 rdie = (const struct rsn_rdie *) (rpos + 2);
00587                 rpos += 2 + rpos[1];
00588                 start = rpos;
00589 
00590                 while (rpos + 2 <= ric + ric_len &&
00591                        rpos + 2 + rpos[1] <= ric + ric_len) {
00592                         if (rpos[0] == WLAN_EID_RIC_DATA)
00593                                 break;
00594                         rpos += 2 + rpos[1];
00595                 }
00596                 pos = wpa_ft_process_rdie(pos, end, rdie->id,
00597                                           rdie->descr_count,
00598                                           start, rpos - start);
00599         }
00600 
00601         return pos;
00602 }
00603 
00604 
00605 u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
00606                                  size_t max_len, int auth_alg,
00607                                  const u8 *req_ies, size_t req_ies_len)
00608 {
00609         u8 *end, *mdie, *ftie, *rsnie, *r0kh_id, *subelem = NULL;
00610         size_t mdie_len, ftie_len, rsnie_len, r0kh_id_len, subelem_len = 0;
00611         int res;
00612         struct wpa_auth_config *conf;
00613         struct rsn_ftie *_ftie;
00614         struct wpa_ft_ies parse;
00615         u8 *ric_start;
00616 
00617         if (sm == NULL)
00618                 return pos;
00619 
00620         conf = &sm->wpa_auth->conf;
00621 
00622         if (sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
00623             sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_PSK)
00624                 return pos;
00625 
00626         end = pos + max_len;
00627 
00628         /* RSN */
00629         res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name);
00630         if (res < 0)
00631                 return pos;
00632         rsnie = pos;
00633         rsnie_len = res;
00634         pos += res;
00635 
00636         /* Mobility Domain Information */
00637         res = wpa_write_mdie(conf, pos, end - pos);
00638         if (res < 0)
00639                 return pos;
00640         mdie = pos;
00641         mdie_len = res;
00642         pos += res;
00643 
00644         /* Fast BSS Transition Information */
00645         if (auth_alg == WLAN_AUTH_FT) {
00646                 subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
00647                 r0kh_id = sm->r0kh_id;
00648                 r0kh_id_len = sm->r0kh_id_len;
00649 #ifdef CONFIG_IEEE80211W
00650                 if (sm->mgmt_frame_prot) {
00651                         u8 *igtk;
00652                         size_t igtk_len;
00653                         u8 *nbuf;
00654                         igtk = wpa_ft_igtk_subelem(sm, &igtk_len);
00655                         if (igtk == NULL) {
00656                                 os_free(subelem);
00657                                 return pos;
00658                         }
00659                         nbuf = os_realloc(subelem, subelem_len + igtk_len);
00660                         if (nbuf == NULL) {
00661                                 os_free(subelem);
00662                                 os_free(igtk);
00663                                 return pos;
00664                         }
00665                         subelem = nbuf;
00666                         os_memcpy(subelem + subelem_len, igtk, igtk_len);
00667                         subelem_len += igtk_len;
00668                         os_free(igtk);
00669                 }
00670 #endif /* CONFIG_IEEE80211W */
00671         } else {
00672                 r0kh_id = conf->r0_key_holder;
00673                 r0kh_id_len = conf->r0_key_holder_len;
00674         }
00675         res = wpa_write_ftie(conf, r0kh_id, r0kh_id_len, NULL, NULL, pos,
00676                              end - pos, subelem, subelem_len);
00677         os_free(subelem);
00678         if (res < 0)
00679                 return pos;
00680         ftie = pos;
00681         ftie_len = res;
00682         pos += res;
00683 
00684         _ftie = (struct rsn_ftie *) (ftie + 2);
00685         _ftie->mic_control[1] = 3; /* Information element count */
00686 
00687         ric_start = pos;
00688         if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) {
00689                 pos = wpa_ft_process_ric(pos, end, parse.ric, parse.ric_len);
00690                 _ftie->mic_control[1] += ieee802_11_ie_count(ric_start,
00691                                                              pos - ric_start);
00692         }
00693         if (ric_start == pos)
00694                 ric_start = NULL;
00695 
00696         if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 6,
00697                        mdie, mdie_len, ftie, ftie_len,
00698                        rsnie, rsnie_len,
00699                        ric_start, ric_start ? pos - ric_start : 0,
00700                        _ftie->mic) < 0)
00701                 wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
00702 
00703         return pos;
00704 }
00705 
00706 
00707 static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
00708                              struct wpa_ft_ies *parse)
00709 {
00710         const u8 *end, *pos;
00711 
00712         parse->ftie = ie;
00713         parse->ftie_len = ie_len;
00714 
00715         pos = ie + sizeof(struct rsn_ftie);
00716         end = ie + ie_len;
00717 
00718         while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
00719                 switch (pos[0]) {
00720                 case FTIE_SUBELEM_R1KH_ID:
00721                         if (pos[1] != FT_R1KH_ID_LEN) {
00722                                 wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
00723                                            "length in FTIE: %d", pos[1]);
00724                                 return -1;
00725                         }
00726                         parse->r1kh_id = pos + 2;
00727                         break;
00728                 case FTIE_SUBELEM_GTK:
00729                         parse->gtk = pos + 2;
00730                         parse->gtk_len = pos[1];
00731                         break;
00732                 case FTIE_SUBELEM_R0KH_ID:
00733                         if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
00734                                 wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
00735                                            "length in FTIE: %d", pos[1]);
00736                                 return -1;
00737                         }
00738                         parse->r0kh_id = pos + 2;
00739                         parse->r0kh_id_len = pos[1];
00740                         break;
00741                 }
00742 
00743                 pos += 2 + pos[1];
00744         }
00745 
00746         return 0;
00747 }
00748 
00749 
00750 static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
00751                             struct wpa_ft_ies *parse)
00752 {
00753         const u8 *end, *pos;
00754         struct wpa_ie_data data;
00755         int ret;
00756         const struct rsn_ftie *ftie;
00757         int prot_ie_count = 0;
00758 
00759         os_memset(parse, 0, sizeof(*parse));
00760         if (ies == NULL)
00761                 return 0;
00762 
00763         pos = ies;
00764         end = ies + ies_len;
00765         while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
00766                 switch (pos[0]) {
00767                 case WLAN_EID_RSN:
00768                         parse->rsn = pos + 2;
00769                         parse->rsn_len = pos[1];
00770                         ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
00771                                                    parse->rsn_len + 2,
00772                                                    &data);
00773                         if (ret < 0) {
00774                                 wpa_printf(MSG_DEBUG, "FT: Failed to parse "
00775                                            "RSN IE: %d", ret);
00776                                 return -1;
00777                         }
00778                         if (data.num_pmkid == 1 && data.pmkid)
00779                                 parse->rsn_pmkid = data.pmkid;
00780                         break;
00781                 case WLAN_EID_MOBILITY_DOMAIN:
00782                         parse->mdie = pos + 2;
00783                         parse->mdie_len = pos[1];
00784                         break;
00785                 case WLAN_EID_FAST_BSS_TRANSITION:
00786                         if (pos[1] < sizeof(*ftie))
00787                                 return -1;
00788                         ftie = (const struct rsn_ftie *) (pos + 2);
00789                         prot_ie_count = ftie->mic_control[1];
00790                         if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
00791                                 return -1;
00792                         break;
00793                 case WLAN_EID_RIC_DATA:
00794                         if (parse->ric == NULL)
00795                                 parse->ric = pos;
00796                 }
00797 
00798                 pos += 2 + pos[1];
00799         }
00800 
00801         if (prot_ie_count == 0)
00802                 return 0; /* no MIC */
00803 
00804         /*
00805          * Check that the protected IE count matches with IEs included in the
00806          * frame.
00807          */
00808         if (parse->rsn)
00809                 prot_ie_count--;
00810         if (parse->mdie)
00811                 prot_ie_count--;
00812         if (parse->ftie)
00813                 prot_ie_count--;
00814         if (prot_ie_count < 0) {
00815                 wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
00816                            "the protected IE count");
00817                 return -1;
00818         }
00819 
00820         if (prot_ie_count == 0 && parse->ric) {
00821                 wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
00822                            "included in protected IE count");
00823                 return -1;
00824         }
00825 
00826         /* Determine the end of the RIC IE(s) */
00827         pos = parse->ric;
00828         while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
00829                prot_ie_count) {
00830                 prot_ie_count--;
00831                 pos += 2 + pos[1];
00832         }
00833         parse->ric_len = pos - parse->ric;
00834         if (prot_ie_count) {
00835                 wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
00836                            "frame", (int) prot_ie_count);
00837                 return -1;
00838         }
00839 
00840         return 0;
00841 }
00842 
00843 
00844 static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
00845                                    int vlan_id,
00846                                    wpa_alg alg, const u8 *addr, int idx,
00847                                    u8 *key, size_t key_len)
00848 {
00849         if (wpa_auth->cb.set_key == NULL)
00850                 return -1;
00851         return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
00852                                     key, key_len);
00853 }
00854 
00855 
00856 static void wpa_ft_install_ptk(struct wpa_state_machine *sm)
00857 {
00858         wpa_alg alg;
00859         int klen;
00860 
00861         /* MLME-SETKEYS.request(PTK) */
00862         if (sm->pairwise == WPA_CIPHER_TKIP) {
00863                 alg = WPA_ALG_TKIP;
00864                 klen = 32;
00865         } else if (sm->pairwise == WPA_CIPHER_CCMP) {
00866                 alg = WPA_ALG_CCMP;
00867                 klen = 16;
00868         } else
00869                 return;
00870 
00871         /* FIX: add STA entry to kernel/driver here? The set_key will fail
00872          * most likely without this.. At the moment, STA entry is added only
00873          * after association has been completed. Alternatively, could
00874          * re-configure PTK at that point(?).
00875          */
00876         if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
00877                              sm->PTK.tk1, klen))
00878                 return;
00879 
00880         /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
00881         sm->pairwise_set = TRUE;
00882 }
00883 
00884 
00885 static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
00886                                    const u8 *ies, size_t ies_len,
00887                                    u8 **resp_ies, size_t *resp_ies_len)
00888 {
00889         struct rsn_mdie *mdie;
00890         struct rsn_ftie *ftie;
00891         u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
00892         u8 ptk_name[WPA_PMK_NAME_LEN];
00893         struct wpa_auth_config *conf;
00894         struct wpa_ft_ies parse;
00895         size_t buflen, ptk_len;
00896         int ret;
00897         u8 *pos, *end;
00898 
00899         *resp_ies = NULL;
00900         *resp_ies_len = 0;
00901 
00902         sm->pmk_r1_name_valid = 0;
00903         conf = &sm->wpa_auth->conf;
00904 
00905         wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs",
00906                     ies, ies_len);
00907 
00908         if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
00909                 wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
00910                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
00911         }
00912 
00913         mdie = (struct rsn_mdie *) parse.mdie;
00914         if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
00915             os_memcmp(mdie->mobility_domain,
00916                       sm->wpa_auth->conf.mobility_domain,
00917                       MOBILITY_DOMAIN_ID_LEN) != 0) {
00918                 wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
00919                 return WLAN_STATUS_INVALID_MDIE;
00920         }
00921 
00922         ftie = (struct rsn_ftie *) parse.ftie;
00923         if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
00924                 wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
00925                 return WLAN_STATUS_INVALID_FTIE;
00926         }
00927 
00928         os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
00929 
00930         if (parse.r0kh_id == NULL) {
00931                 wpa_printf(MSG_DEBUG, "FT: Invalid FTIE - no R0KH-ID");
00932                 return WLAN_STATUS_INVALID_FTIE;
00933         }
00934 
00935         wpa_hexdump(MSG_DEBUG, "FT: STA R0KH-ID",
00936                     parse.r0kh_id, parse.r0kh_id_len);
00937         os_memcpy(sm->r0kh_id, parse.r0kh_id, parse.r0kh_id_len);
00938         sm->r0kh_id_len = parse.r0kh_id_len;
00939 
00940         if (parse.rsn_pmkid == NULL) {
00941                 wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE");
00942                 return WLAN_STATUS_INVALID_PMKID;
00943         }
00944 
00945         wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name",
00946                     parse.rsn_pmkid, WPA_PMK_NAME_LEN);
00947         wpa_derive_pmk_r1_name(parse.rsn_pmkid,
00948                                sm->wpa_auth->conf.r1_key_holder, sm->addr,
00949                                pmk_r1_name);
00950         wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
00951                     pmk_r1_name, WPA_PMK_NAME_LEN);
00952 
00953         if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1) <
00954             0) {
00955                 if (wpa_ft_pull_pmk_r1(sm->wpa_auth, sm->addr, sm->r0kh_id,
00956                                        sm->r0kh_id_len, parse.rsn_pmkid) < 0) {
00957                         wpa_printf(MSG_DEBUG, "FT: Did not have matching "
00958                                    "PMK-R1 and unknown R0KH-ID");
00959                         return WLAN_STATUS_INVALID_PMKID;
00960                 }
00961 
00962                 /*
00963                  * TODO: Should return "status pending" (and the caller should
00964                  * not send out response now). The real response will be sent
00965                  * once the response from R0KH is received.
00966                  */
00967                 return WLAN_STATUS_INVALID_PMKID;
00968         }
00969 
00970         wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN);
00971         sm->pmk_r1_name_valid = 1;
00972         os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
00973 
00974         if (os_get_random(sm->ANonce, WPA_NONCE_LEN)) {
00975                 wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
00976                            "ANonce");
00977                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
00978         }
00979 
00980         wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
00981                     sm->SNonce, WPA_NONCE_LEN);
00982         wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
00983                     sm->ANonce, WPA_NONCE_LEN);
00984 
00985         ptk_len = sm->pairwise == WPA_CIPHER_CCMP ? 48 : 64;
00986         wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
00987                           sm->wpa_auth->addr, pmk_r1_name,
00988                           (u8 *) &sm->PTK, ptk_len, ptk_name);
00989         wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
00990                         (u8 *) &sm->PTK, ptk_len);
00991         wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
00992 
00993         wpa_ft_install_ptk(sm);
00994 
00995         buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
00996                 2 + FT_R1KH_ID_LEN + 200;
00997         *resp_ies = os_zalloc(buflen);
00998         if (*resp_ies == NULL) {
00999                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
01000         }
01001 
01002         pos = *resp_ies;
01003         end = *resp_ies + buflen;
01004 
01005         ret = wpa_write_rsn_ie(conf, pos, end - pos, parse.rsn_pmkid);
01006         if (ret < 0) {
01007                 os_free(*resp_ies);
01008                 *resp_ies = NULL;
01009                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
01010         }
01011         pos += ret;
01012 
01013         ret = wpa_write_mdie(conf, pos, end - pos);
01014         if (ret < 0) {
01015                 os_free(*resp_ies);
01016                 *resp_ies = NULL;
01017                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
01018         }
01019         pos += ret;
01020 
01021         ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len,
01022                              sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
01023         if (ret < 0) {
01024                 os_free(*resp_ies);
01025                 *resp_ies = NULL;
01026                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
01027         }
01028         pos += ret;
01029 
01030         *resp_ies_len = pos - *resp_ies;
01031 
01032         return WLAN_STATUS_SUCCESS;
01033 }
01034 
01035 
01036 void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
01037                          u16 auth_transaction, const u8 *ies, size_t ies_len,
01038                          void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
01039                                     u16 auth_transaction, u16 status,
01040                                     const u8 *ies, size_t ies_len),
01041                          void *ctx)
01042 {
01043         u16 status;
01044         u8 *resp_ies;
01045         size_t resp_ies_len;
01046 
01047         if (sm == NULL) {
01048                 wpa_printf(MSG_DEBUG, "FT: Received authentication frame, but "
01049                            "WPA SM not available");
01050                 return;
01051         }
01052 
01053         wpa_printf(MSG_DEBUG, "FT: Received authentication frame: STA=" MACSTR
01054                    " BSSID=" MACSTR " transaction=%d",
01055                    MAC2STR(sm->addr), MAC2STR(bssid), auth_transaction);
01056         status = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies,
01057                                          &resp_ies_len);
01058 
01059         wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
01060                    " auth_transaction=%d status=%d",
01061                    MAC2STR(sm->addr), auth_transaction + 1, status);
01062         wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
01063         cb(ctx, sm->addr, bssid, auth_transaction + 1, status,
01064            resp_ies, resp_ies_len);
01065         os_free(resp_ies);
01066 }
01067 
01068 
01069 u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
01070                             size_t ies_len)
01071 {
01072         struct wpa_ft_ies parse;
01073         struct rsn_mdie *mdie;
01074         struct rsn_ftie *ftie;
01075         u8 mic[16];
01076 
01077         if (sm == NULL)
01078                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
01079 
01080         wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
01081 
01082         if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
01083                 wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
01084                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
01085         }
01086 
01087         if (parse.rsn == NULL) {
01088                 wpa_printf(MSG_DEBUG, "FT: No RSNIE in Reassoc Req");
01089                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
01090         }
01091 
01092         if (parse.rsn_pmkid == NULL) {
01093                 wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE");
01094                 return WLAN_STATUS_INVALID_PMKID;
01095         }
01096 
01097         if (os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0)
01098         {
01099                 wpa_printf(MSG_DEBUG, "FT: PMKID in Reassoc Req did not match "
01100                            "with the PMKR1Name derived from auth request");
01101                 return WLAN_STATUS_INVALID_PMKID;
01102         }
01103 
01104         mdie = (struct rsn_mdie *) parse.mdie;
01105         if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
01106             os_memcmp(mdie->mobility_domain,
01107                       sm->wpa_auth->conf.mobility_domain,
01108                       MOBILITY_DOMAIN_ID_LEN) != 0) {
01109                 wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
01110                 return WLAN_STATUS_INVALID_MDIE;
01111         }
01112 
01113         ftie = (struct rsn_ftie *) parse.ftie;
01114         if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
01115                 wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
01116                 return WLAN_STATUS_INVALID_FTIE;
01117         }
01118 
01119         if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5,
01120                        parse.mdie - 2, parse.mdie_len + 2,
01121                        parse.ftie - 2, parse.ftie_len + 2,
01122                        parse.rsn - 2, parse.rsn_len + 2,
01123                        parse.ric, parse.ric_len,
01124                        mic) < 0) {
01125                 wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
01126                 return WLAN_STATUS_UNSPECIFIED_FAILURE;
01127         }
01128 
01129         if (os_memcmp(mic, ftie->mic, 16) != 0) {
01130                 wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
01131                 wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
01132                 wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
01133                 return WLAN_STATUS_INVALID_FTIE;
01134         }
01135 
01136         return WLAN_STATUS_SUCCESS;
01137 }
01138 
01139 
01140 int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len)
01141 {
01142         const u8 *sta_addr, *target_ap;
01143         const u8 *ies;
01144         size_t ies_len;
01145         u8 action;
01146         struct ft_rrb_frame *frame;
01147 
01148         if (sm == NULL)
01149                 return -1;
01150 
01151         /*
01152          * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
01153          * FT Request action frame body[variable]
01154          */
01155 
01156         if (len < 14) {
01157                 wpa_printf(MSG_DEBUG, "FT: Too short FT Action frame "
01158                            "(len=%lu)", (unsigned long) len);
01159                 return -1;
01160         }
01161 
01162         action = data[1];
01163         sta_addr = data + 2;
01164         target_ap = data + 8;
01165         ies = data + 14;
01166         ies_len = len - 14;
01167 
01168         wpa_printf(MSG_DEBUG, "FT: Received FT Action frame (STA=" MACSTR
01169                    " Target AP=" MACSTR " Action=%d)",
01170                    MAC2STR(sta_addr), MAC2STR(target_ap), action);
01171 
01172         if (os_memcmp(sta_addr, sm->addr, ETH_ALEN) != 0) {
01173                 wpa_printf(MSG_DEBUG, "FT: Mismatch in FT Action STA address: "
01174                            "STA=" MACSTR " STA-Address=" MACSTR,
01175                            MAC2STR(sm->addr), MAC2STR(sta_addr));
01176                 return -1;
01177         }
01178 
01179         /*
01180          * Do some sanity checking on the target AP address (not own and not
01181          * broadcast. This could be extended to filter based on a list of known
01182          * APs in the MD (if such a list were configured).
01183          */
01184         if ((target_ap[0] & 0x01) ||
01185             os_memcmp(target_ap, sm->wpa_auth->addr, ETH_ALEN) == 0) {
01186                 wpa_printf(MSG_DEBUG, "FT: Invalid Target AP in FT Action "
01187                            "frame");
01188                 return -1;
01189         }
01190 
01191         wpa_hexdump(MSG_MSGDUMP, "FT: Action frame body", ies, ies_len);
01192 
01193         /* RRB - Forward action frame to the target AP */
01194         frame = os_malloc(sizeof(*frame) + len);
01195         frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
01196         frame->packet_type = FT_PACKET_REQUEST;
01197         frame->action_length = host_to_le16(len);
01198         os_memcpy(frame->ap_address, sm->wpa_auth->addr, ETH_ALEN);
01199         os_memcpy(frame + 1, data, len);
01200 
01201         wpa_ft_rrb_send(sm->wpa_auth, target_ap, (u8 *) frame,
01202                         sizeof(*frame) + len);
01203         os_free(frame);
01204 
01205         return 0;
01206 }
01207 
01208 
01209 static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
01210                                  const u8 *current_ap, const u8 *sta_addr,
01211                                  const u8 *body, size_t len)
01212 {
01213         struct wpa_state_machine *sm;
01214         u16 status;
01215         u8 *resp_ies, *pos;
01216         size_t resp_ies_len, rlen;
01217         struct ft_rrb_frame *frame;
01218 
01219         sm = wpa_ft_add_sta(wpa_auth, sta_addr);
01220         if (sm == NULL) {
01221                 wpa_printf(MSG_DEBUG, "FT: Failed to add new STA based on "
01222                            "RRB Request");
01223                 return -1;
01224         }
01225 
01226         wpa_hexdump(MSG_MSGDUMP, "FT: RRB Request Frame body", body, len);
01227 
01228         status = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
01229                                          &resp_ies_len);
01230 
01231         wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
01232                    " CurrentAP=" MACSTR " status=%d",
01233                    MAC2STR(sm->addr), MAC2STR(current_ap), status);
01234         wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
01235 
01236         /* RRB - Forward action frame response to the Current AP */
01237 
01238         /*
01239          * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
01240          * Status_Code[2] FT Request action frame body[variable]
01241          */
01242         rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len;
01243 
01244         frame = os_malloc(sizeof(*frame) + rlen);
01245         frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
01246         frame->packet_type = FT_PACKET_RESPONSE;
01247         frame->action_length = host_to_le16(rlen);
01248         os_memcpy(frame->ap_address, wpa_auth->addr, ETH_ALEN);
01249         pos = (u8 *) (frame + 1);
01250         *pos++ = WLAN_ACTION_FT;
01251         *pos++ = 2; /* Action: Response */
01252         os_memcpy(pos, sta_addr, ETH_ALEN);
01253         pos += ETH_ALEN;
01254         os_memcpy(pos, wpa_auth->addr, ETH_ALEN);
01255         pos += ETH_ALEN;
01256         WPA_PUT_LE16(pos, status);
01257         pos += 2;
01258         if (resp_ies) {
01259                 os_memcpy(pos, resp_ies, resp_ies_len);
01260                 os_free(resp_ies);
01261         }
01262 
01263         wpa_ft_rrb_send(wpa_auth, current_ap, (u8 *) frame,
01264                         sizeof(*frame) + rlen);
01265         os_free(frame);
01266 
01267         return 0;
01268 }
01269 
01270 
01271 static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
01272                               const u8 *src_addr,
01273                               const u8 *data, size_t data_len)
01274 {
01275         struct ft_r0kh_r1kh_pull_frame *frame, f;
01276         struct ft_remote_r1kh *r1kh;
01277         struct ft_r0kh_r1kh_resp_frame resp, r;
01278         u8 pmk_r0[PMK_LEN];
01279 
01280         wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
01281 
01282         if (data_len < sizeof(*frame))
01283                 return -1;
01284 
01285         r1kh = wpa_auth->conf.r1kh_list;
01286         while (r1kh) {
01287                 if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) == 0)
01288                         break;
01289                 r1kh = r1kh->next;
01290         }
01291         if (r1kh == NULL) {
01292                 wpa_printf(MSG_DEBUG, "FT: No matching R1KH address found for "
01293                            "PMK-R1 pull source address " MACSTR,
01294                            MAC2STR(src_addr));
01295                 return -1;
01296         }
01297 
01298         frame = (struct ft_r0kh_r1kh_pull_frame *) data;
01299         /* aes_unwrap() does not support inplace decryption, so use a temporary
01300          * buffer for the data. */
01301         if (aes_unwrap(r1kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
01302                        frame->nonce, f.nonce) < 0) {
01303                 wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
01304                            "request from " MACSTR, MAC2STR(src_addr));
01305                 return -1;
01306         }
01307 
01308         wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
01309                     f.nonce, sizeof(f.nonce));
01310         wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR0Name",
01311                     f.pmk_r0_name, WPA_PMK_NAME_LEN);
01312         wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID="
01313                    MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
01314 
01315         os_memset(&resp, 0, sizeof(resp));
01316         resp.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
01317         resp.packet_type = FT_PACKET_R0KH_R1KH_RESP;
01318         resp.data_length = host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN);
01319         os_memcpy(resp.ap_address, wpa_auth->addr, ETH_ALEN);
01320 
01321         /* aes_wrap() does not support inplace encryption, so use a temporary
01322          * buffer for the data. */
01323         os_memcpy(r.nonce, f.nonce, sizeof(f.nonce));
01324         os_memcpy(r.r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN);
01325         os_memcpy(r.s1kh_id, f.s1kh_id, ETH_ALEN);
01326         if (wpa_ft_fetch_pmk_r0(wpa_auth, f.s1kh_id, f.pmk_r0_name, pmk_r0) <
01327             0) {
01328                 wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for "
01329                            "PMK-R1 pull");
01330                 return -1;
01331         }
01332 
01333         wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
01334                           r.pmk_r1, r.pmk_r1_name);
01335         wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
01336         wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
01337                     WPA_PMK_NAME_LEN);
01338 
01339         if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
01340                      r.nonce, resp.nonce) < 0) {
01341                 os_memset(pmk_r0, 0, PMK_LEN);
01342                 return -1;
01343         }
01344 
01345         os_memset(pmk_r0, 0, PMK_LEN);
01346 
01347         wpa_ft_rrb_send(wpa_auth, src_addr, (u8 *) &resp, sizeof(resp));
01348 
01349         return 0;
01350 }
01351 
01352 
01353 static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
01354                               const u8 *src_addr,
01355                               const u8 *data, size_t data_len)
01356 {
01357         struct ft_r0kh_r1kh_resp_frame *frame, f;
01358         struct ft_remote_r0kh *r0kh;
01359 
01360         wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
01361 
01362         if (data_len < sizeof(*frame))
01363                 return -1;
01364 
01365         r0kh = wpa_auth->conf.r0kh_list;
01366         while (r0kh) {
01367                 if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
01368                         break;
01369                 r0kh = r0kh->next;
01370         }
01371         if (r0kh == NULL) {
01372                 wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
01373                            "PMK-R0 pull response source address " MACSTR,
01374                            MAC2STR(src_addr));
01375                 return -1;
01376         }
01377 
01378         frame = (struct ft_r0kh_r1kh_resp_frame *) data;
01379         /* aes_unwrap() does not support inplace decryption, so use a temporary
01380          * buffer for the data. */
01381         if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
01382                        frame->nonce, f.nonce) < 0) {
01383                 wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
01384                            "response from " MACSTR, MAC2STR(src_addr));
01385                 return -1;
01386         }
01387 
01388         if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
01389             != 0) {
01390                 wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull response did not use a "
01391                            "matching R1KH-ID");
01392                 return -1;
01393         }
01394 
01395         /* TODO: verify that <nonce,s1kh_id> matches with a pending request
01396          * and call this requests callback function to finish request
01397          * processing */
01398 
01399         wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
01400                     f.nonce, sizeof(f.nonce));
01401         wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID="
01402                    MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
01403         wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1",
01404                         f.pmk_r1, PMK_LEN);
01405         wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name",
01406                         f.pmk_r1_name, WPA_PMK_NAME_LEN);
01407 
01408         wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name);
01409         os_memset(f.pmk_r1, 0, PMK_LEN);
01410 
01411         return 0;
01412 }
01413 
01414 
01415 static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
01416                               const u8 *src_addr,
01417                               const u8 *data, size_t data_len)
01418 {
01419         struct ft_r0kh_r1kh_push_frame *frame, f;
01420         struct ft_remote_r0kh *r0kh;
01421         struct os_time now;
01422         os_time_t tsend;
01423 
01424         wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
01425 
01426         if (data_len < sizeof(*frame))
01427                 return -1;
01428 
01429         r0kh = wpa_auth->conf.r0kh_list;
01430         while (r0kh) {
01431                 if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
01432                         break;
01433                 r0kh = r0kh->next;
01434         }
01435         if (r0kh == NULL) {
01436                 wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
01437                            "PMK-R0 push source address " MACSTR,
01438                            MAC2STR(src_addr));
01439                 return -1;
01440         }
01441 
01442         frame = (struct ft_r0kh_r1kh_push_frame *) data;
01443         /* aes_unwrap() does not support inplace decryption, so use a temporary
01444          * buffer for the data. */
01445         if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
01446                        frame->timestamp, f.timestamp) < 0) {
01447                 wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from "
01448                            MACSTR, MAC2STR(src_addr));
01449                 return -1;
01450         }
01451 
01452         os_get_time(&now);
01453         tsend = WPA_GET_LE32(f.timestamp);
01454         if ((now.sec > tsend && now.sec - tsend > 60) ||
01455             (now.sec < tsend && tsend - now.sec > 60)) {
01456                 wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not have a valid "
01457                            "timestamp: sender time %d own time %d\n",
01458                            (int) tsend, (int) now.sec);
01459                 return -1;
01460         }
01461 
01462         if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
01463             != 0) {
01464                 wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not use a matching "
01465                            "R1KH-ID (received " MACSTR " own " MACSTR ")",
01466                            MAC2STR(f.r1kh_id),
01467                            MAC2STR(wpa_auth->conf.r1_key_holder));
01468                 return -1;
01469         }
01470 
01471         wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - R1KH-ID=" MACSTR " S1KH-ID="
01472                    MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
01473         wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 push - PMK-R1",
01474                         f.pmk_r1, PMK_LEN);
01475         wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 push - PMKR1Name",
01476                         f.pmk_r1_name, WPA_PMK_NAME_LEN);
01477 
01478         wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name);
01479         os_memset(f.pmk_r1, 0, PMK_LEN);
01480 
01481         return 0;
01482 }
01483 
01484 
01485 int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
01486                   const u8 *data, size_t data_len)
01487 {
01488         struct ft_rrb_frame *frame;
01489         u16 alen;
01490         const u8 *pos, *end, *start;
01491         u8 action;
01492         const u8 *sta_addr, *target_ap_addr;
01493 
01494         wpa_printf(MSG_DEBUG, "FT: RRB received frame from remote AP " MACSTR,
01495                    MAC2STR(src_addr));
01496 
01497         if (data_len < sizeof(*frame)) {
01498                 wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (data_len=%lu)",
01499                            (unsigned long) data_len);
01500                 return -1;
01501         }
01502 
01503         pos = data;
01504         frame = (struct ft_rrb_frame *) pos;
01505         pos += sizeof(*frame);
01506 
01507         alen = le_to_host16(frame->action_length);
01508         wpa_printf(MSG_DEBUG, "FT: RRB frame - frame_type=%d packet_type=%d "
01509                    "action_length=%d ap_address=" MACSTR,
01510                    frame->frame_type, frame->packet_type, alen,
01511                    MAC2STR(frame->ap_address));
01512 
01513         if (frame->frame_type != RSN_REMOTE_FRAME_TYPE_FT_RRB) {
01514                 /* Discard frame per IEEE Std 802.11r-2008, 11A.10.3 */
01515                 wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with "
01516                            "unrecognized type %d", frame->frame_type);
01517                 return -1;
01518         }
01519 
01520         if (alen > data_len - sizeof(*frame)) {
01521                 wpa_printf(MSG_DEBUG, "FT: RRB frame too short for action "
01522                            "frame");
01523                 return -1;
01524         }
01525 
01526         if (frame->packet_type == FT_PACKET_R0KH_R1KH_PULL)
01527                 return wpa_ft_rrb_rx_pull(wpa_auth, src_addr, data, data_len);
01528         if (frame->packet_type == FT_PACKET_R0KH_R1KH_RESP)
01529                 return wpa_ft_rrb_rx_resp(wpa_auth, src_addr, data, data_len);
01530         if (frame->packet_type == FT_PACKET_R0KH_R1KH_PUSH)
01531                 return wpa_ft_rrb_rx_push(wpa_auth, src_addr, data, data_len);
01532 
01533         wpa_hexdump(MSG_MSGDUMP, "FT: RRB - FT Action frame", pos, alen);
01534 
01535         if (alen < 1 + 1 + 2 * ETH_ALEN) {
01536                 wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (not enough "
01537                            "room for Action Frame body); alen=%lu",
01538                            (unsigned long) alen);
01539                 return -1;
01540         }
01541         start = pos;
01542         end = pos + alen;
01543 
01544         if (*pos != WLAN_ACTION_FT) {
01545                 wpa_printf(MSG_DEBUG, "FT: Unexpected Action frame category "
01546                            "%d", *pos);
01547                 return -1;
01548         }
01549 
01550         pos++;
01551         action = *pos++;
01552         sta_addr = pos;
01553         pos += ETH_ALEN;
01554         target_ap_addr = pos;
01555         pos += ETH_ALEN;
01556         wpa_printf(MSG_DEBUG, "FT: RRB Action Frame: action=%d sta_addr="
01557                    MACSTR " target_ap_addr=" MACSTR,
01558                    action, MAC2STR(sta_addr), MAC2STR(target_ap_addr));
01559 
01560         if (frame->packet_type == FT_PACKET_REQUEST) {
01561                 wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Request");
01562 
01563                 if (action != 1) {
01564                         wpa_printf(MSG_DEBUG, "FT: Unexpected Action %d in "
01565                                    "RRB Request", action);
01566                         return -1;
01567                 }
01568 
01569                 if (os_memcmp(target_ap_addr, wpa_auth->addr, ETH_ALEN) != 0) {
01570                         wpa_printf(MSG_DEBUG, "FT: Target AP address in the "
01571                                    "RRB Request does not match with own "
01572                                    "address");
01573                         return -1;
01574                 }
01575 
01576                 if (wpa_ft_rrb_rx_request(wpa_auth, frame->ap_address,
01577                                           sta_addr, pos, end - pos) < 0)
01578                         return -1;
01579         } else if (frame->packet_type == FT_PACKET_RESPONSE) {
01580                 u16 status_code;
01581 
01582                 if (end - pos < 2) {
01583                         wpa_printf(MSG_DEBUG, "FT: Not enough room for status "
01584                                    "code in RRB Response");
01585                         return -1;
01586                 }
01587                 status_code = WPA_GET_LE16(pos);
01588                 pos += 2;
01589 
01590                 wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response "
01591                            "(status_code=%d)", status_code);
01592 
01593                 if (wpa_ft_action_send(wpa_auth, sta_addr, start, alen) < 0)
01594                         return -1;
01595         } else {
01596                 wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with unknown "
01597                            "packet_type %d", frame->packet_type);
01598                 return -1;
01599         }
01600 
01601         return 0;
01602 }
01603 
01604 
01605 static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
01606                                    struct wpa_ft_pmk_r0_sa *pmk_r0,
01607                                    struct ft_remote_r1kh *r1kh,
01608                                    const u8 *s1kh_id)
01609 {
01610         struct ft_r0kh_r1kh_push_frame frame, f;
01611         struct os_time now;
01612 
01613         os_memset(&frame, 0, sizeof(frame));
01614         frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
01615         frame.packet_type = FT_PACKET_R0KH_R1KH_PUSH;
01616         frame.data_length = host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN);
01617         os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
01618 
01619         /* aes_wrap() does not support inplace encryption, so use a temporary
01620          * buffer for the data. */
01621         os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
01622         os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
01623         os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN);
01624         wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id,
01625                           s1kh_id, f.pmk_r1, f.pmk_r1_name);
01626         wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id));
01627         wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN);
01628         wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name,
01629                     WPA_PMK_NAME_LEN);
01630         os_get_time(&now);
01631         WPA_PUT_LE32(f.timestamp, now.sec);
01632         if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
01633                      f.timestamp, frame.timestamp) < 0)
01634                 return;
01635 
01636         wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
01637 }
01638 
01639 
01640 void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
01641 {
01642         struct wpa_ft_pmk_r0_sa *r0;
01643         struct ft_remote_r1kh *r1kh;
01644 
01645         if (!wpa_auth->conf.pmk_r1_push)
01646                 return;
01647 
01648         r0 = wpa_auth->ft_pmk_cache->pmk_r0;
01649         while (r0) {
01650                 if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0)
01651                         break;
01652                 r0 = r0->next;
01653         }
01654 
01655         if (r0 == NULL || r0->pmk_r1_pushed)
01656                 return;
01657         r0->pmk_r1_pushed = 1;
01658 
01659         wpa_printf(MSG_DEBUG, "FT: Deriving and pushing PMK-R1 keys to R1KHs "
01660                    "for STA " MACSTR, MAC2STR(addr));
01661 
01662         r1kh = wpa_auth->conf.r1kh_list;
01663         while (r1kh) {
01664                 wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr);
01665                 r1kh = r1kh->next;
01666         }
01667 }
01668 
01669 #endif /* CONFIG_IEEE80211R */
01670 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:49 2009 for hostapd by  doxygen 1.6.1