drv_callbacks.c
Go to the documentation of this file.
00001 /*
00002  * hostapd / Callback functions for driver wrappers
00003  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  *
00009  * Alternatively, this software may be distributed under the terms of BSD
00010  * license.
00011  *
00012  * See README and COPYING for more details.
00013  */
00014 
00015 #include "utils/includes.h"
00016 
00017 #include "utils/common.h"
00018 #include "radius/radius.h"
00019 #include "drivers/driver.h"
00020 #include "common/ieee802_11_defs.h"
00021 #include "common/ieee802_11_common.h"
00022 #include "common/wpa_ctrl.h"
00023 #include "hostapd.h"
00024 #include "ieee802_11.h"
00025 #include "sta_info.h"
00026 #include "accounting.h"
00027 #include "tkip_countermeasures.h"
00028 #include "iapp.h"
00029 #include "ieee802_1x.h"
00030 #include "wpa_auth.h"
00031 #include "wmm.h"
00032 #include "wps_hostapd.h"
00033 #include "ap_config.h"
00034 
00035 
00036 int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
00037                         const u8 *ie, size_t ielen)
00038 {
00039         struct sta_info *sta;
00040         int new_assoc, res;
00041         struct ieee802_11_elems elems;
00042 
00043         if (addr == NULL) {
00044                 /*
00045                  * This could potentially happen with unexpected event from the
00046                  * driver wrapper. This was seen at least in one case where the
00047                  * driver ended up being set to station mode while hostapd was
00048                  * running, so better make sure we stop processing such an
00049                  * event here.
00050                  */
00051                 wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with "
00052                            "no address");
00053                 return -1;
00054         }
00055 
00056         hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
00057                        HOSTAPD_LEVEL_INFO, "associated");
00058 
00059         ieee802_11_parse_elems(ie, ielen, &elems, 0);
00060         if (elems.wps_ie) {
00061                 ie = elems.wps_ie - 2;
00062                 ielen = elems.wps_ie_len + 2;
00063                 wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq");
00064         } else if (elems.rsn_ie) {
00065                 ie = elems.rsn_ie - 2;
00066                 ielen = elems.rsn_ie_len + 2;
00067                 wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq");
00068         } else if (elems.wpa_ie) {
00069                 ie = elems.wpa_ie - 2;
00070                 ielen = elems.wpa_ie_len + 2;
00071                 wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
00072         } else {
00073                 ie = NULL;
00074                 ielen = 0;
00075                 wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in "
00076                            "(Re)AssocReq");
00077         }
00078 
00079         sta = ap_get_sta(hapd, addr);
00080         if (sta) {
00081                 accounting_sta_stop(hapd, sta);
00082         } else {
00083                 sta = ap_sta_add(hapd, addr);
00084                 if (sta == NULL)
00085                         return -1;
00086         }
00087         sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
00088 
00089         if (hapd->conf->wpa) {
00090                 if (ie == NULL || ielen == 0) {
00091                         if (hapd->conf->wps_state) {
00092                                 wpa_printf(MSG_DEBUG, "STA did not include "
00093                                            "WPA/RSN IE in (Re)Association "
00094                                            "Request - possible WPS use");
00095                                 sta->flags |= WLAN_STA_MAYBE_WPS;
00096                                 goto skip_wpa_check;
00097                         }
00098 
00099                         wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
00100                         return -1;
00101                 }
00102                 if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
00103                     os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
00104                         sta->flags |= WLAN_STA_WPS;
00105                         goto skip_wpa_check;
00106                 }
00107 
00108                 if (sta->wpa_sm == NULL)
00109                         sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
00110                                                         sta->addr);
00111                 if (sta->wpa_sm == NULL) {
00112                         wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
00113                                    "machine");
00114                         return -1;
00115                 }
00116                 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
00117                                           ie, ielen, NULL, 0);
00118                 if (res != WPA_IE_OK) {
00119                         int resp;
00120                         wpa_printf(MSG_DEBUG, "WPA/RSN information element "
00121                                    "rejected? (res %u)", res);
00122                         wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
00123                         if (res == WPA_INVALID_GROUP)
00124                                 resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
00125                         else if (res == WPA_INVALID_PAIRWISE)
00126                                 resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
00127                         else if (res == WPA_INVALID_AKMP)
00128                                 resp = WLAN_REASON_AKMP_NOT_VALID;
00129 #ifdef CONFIG_IEEE80211W
00130                         else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
00131                                 resp = WLAN_REASON_INVALID_IE;
00132                         else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
00133                                 resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
00134 #endif /* CONFIG_IEEE80211W */
00135                         else
00136                                 resp = WLAN_REASON_INVALID_IE;
00137                         hapd->drv.sta_disassoc(hapd, sta->addr, resp);
00138                         ap_free_sta(hapd, sta);
00139                         return -1;
00140                 }
00141         } else if (hapd->conf->wps_state) {
00142                 if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 &&
00143                     os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
00144                         sta->flags |= WLAN_STA_WPS;
00145                 } else
00146                         sta->flags |= WLAN_STA_MAYBE_WPS;
00147         }
00148 skip_wpa_check:
00149 
00150         new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
00151         sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
00152         wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
00153 
00154         hostapd_new_assoc_sta(hapd, sta, !new_assoc);
00155 
00156         ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
00157 
00158         return 0;
00159 }
00160 
00161 
00162 void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
00163 {
00164         struct sta_info *sta;
00165 
00166         hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
00167                        HOSTAPD_LEVEL_INFO, "disassociated");
00168 
00169         sta = ap_get_sta(hapd, addr);
00170         if (sta == NULL) {
00171                 wpa_printf(MSG_DEBUG, "Disassociation notification for "
00172                            "unknown STA " MACSTR, MAC2STR(addr));
00173                 return;
00174         }
00175 
00176         sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
00177         wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
00178                 MAC2STR(sta->addr));
00179         wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
00180         sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
00181         ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
00182         ap_free_sta(hapd, sta);
00183 }
00184 
00185 
00186 #ifdef HOSTAPD
00187 
00188 #ifdef NEED_AP_MLME
00189 
00190 static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
00191 {
00192         u16 fc, type, stype;
00193 
00194         /*
00195          * PS-Poll frames are 16 bytes. All other frames are
00196          * 24 bytes or longer.
00197          */
00198         if (len < 16)
00199                 return NULL;
00200 
00201         fc = le_to_host16(hdr->frame_control);
00202         type = WLAN_FC_GET_TYPE(fc);
00203         stype = WLAN_FC_GET_STYPE(fc);
00204 
00205         switch (type) {
00206         case WLAN_FC_TYPE_DATA:
00207                 if (len < 24)
00208                         return NULL;
00209                 switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
00210                 case WLAN_FC_FROMDS | WLAN_FC_TODS:
00211                 case WLAN_FC_TODS:
00212                         return hdr->addr1;
00213                 case WLAN_FC_FROMDS:
00214                         return hdr->addr2;
00215                 default:
00216                         return NULL;
00217                 }
00218         case WLAN_FC_TYPE_CTRL:
00219                 if (stype != WLAN_FC_STYPE_PSPOLL)
00220                         return NULL;
00221                 return hdr->addr1;
00222         case WLAN_FC_TYPE_MGMT:
00223                 return hdr->addr3;
00224         default:
00225                 return NULL;
00226         }
00227 }
00228 
00229 
00230 #define HAPD_BROADCAST ((struct hostapd_data *) -1)
00231 
00232 static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
00233                                             const u8 *bssid)
00234 {
00235         size_t i;
00236 
00237         if (bssid == NULL)
00238                 return NULL;
00239         if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
00240             bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
00241                 return HAPD_BROADCAST;
00242 
00243         for (i = 0; i < iface->num_bss; i++) {
00244                 if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0)
00245                         return iface->bss[i];
00246         }
00247 
00248         return NULL;
00249 }
00250 
00251 
00252 static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
00253                                         const u8 *frame, size_t len)
00254 {
00255         const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame;
00256         u16 fc = le_to_host16(hdr->frame_control);
00257         hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
00258         if (hapd == NULL || hapd == HAPD_BROADCAST)
00259                 return;
00260 
00261         ieee802_11_rx_from_unknown(hapd, hdr->addr2,
00262                                    (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
00263                                    (WLAN_FC_TODS | WLAN_FC_FROMDS));
00264 }
00265 
00266 
00267 static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
00268 {
00269         struct hostapd_iface *iface = hapd->iface;
00270         const struct ieee80211_hdr *hdr;
00271         const u8 *bssid;
00272         struct hostapd_frame_info fi;
00273 
00274         hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
00275         bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
00276         if (bssid == NULL)
00277                 return;
00278 
00279         hapd = get_hapd_bssid(iface, bssid);
00280         if (hapd == NULL) {
00281                 u16 fc;
00282                 fc = le_to_host16(hdr->frame_control);
00283 
00284                 /*
00285                  * Drop frames to unknown BSSIDs except for Beacon frames which
00286                  * could be used to update neighbor information.
00287                  */
00288                 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
00289                     WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
00290                         hapd = iface->bss[0];
00291                 else
00292                         return;
00293         }
00294 
00295         os_memset(&fi, 0, sizeof(fi));
00296         fi.datarate = rx_mgmt->datarate;
00297         fi.ssi_signal = rx_mgmt->ssi_signal;
00298 
00299         if (hapd == HAPD_BROADCAST) {
00300                 size_t i;
00301                 for (i = 0; i < iface->num_bss; i++)
00302                         ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
00303                                         rx_mgmt->frame_len, &fi);
00304         } else
00305                 ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi);
00306 }
00307 
00308 
00309 static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
00310                                size_t len, u16 stype, int ok)
00311 {
00312         struct ieee80211_hdr *hdr;
00313         hdr = (struct ieee80211_hdr *) buf;
00314         hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
00315         if (hapd == NULL || hapd == HAPD_BROADCAST)
00316                 return;
00317         ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
00318 }
00319 
00320 #endif /* NEED_AP_MLME */
00321 
00322 
00323 static int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
00324                                 const u8 *ie, size_t ie_len)
00325 {
00326         size_t i;
00327         int ret = 0;
00328 
00329         for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
00330                 if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
00331                                             sa, ie, ie_len) > 0) {
00332                         ret = 1;
00333                         break;
00334                 }
00335         }
00336         return ret;
00337 }
00338 
00339 
00340 static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
00341 {
00342         struct sta_info *sta = ap_get_sta(hapd, addr);
00343         if (sta)
00344                 return 0;
00345 
00346         wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR
00347                    " - adding a new STA", MAC2STR(addr));
00348         sta = ap_sta_add(hapd, addr);
00349         if (sta) {
00350                 hostapd_new_assoc_sta(hapd, sta, 0);
00351         } else {
00352                 wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR,
00353                            MAC2STR(addr));
00354                 return -1;
00355         }
00356 
00357         return 0;
00358 }
00359 
00360 
00361 static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
00362                                    const u8 *data, size_t data_len)
00363 {
00364         struct hostapd_iface *iface = hapd->iface;
00365         size_t j;
00366 
00367         for (j = 0; j < iface->num_bss; j++) {
00368                 if (ap_get_sta(iface->bss[j], src)) {
00369                         hapd = iface->bss[j];
00370                         break;
00371                 }
00372         }
00373 
00374         ieee802_1x_receive(hapd, src, data, data_len);
00375 }
00376 
00377 
00378 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
00379                           union wpa_event_data *data)
00380 {
00381         struct hostapd_data *hapd = ctx;
00382 
00383         switch (event) {
00384         case EVENT_MICHAEL_MIC_FAILURE:
00385                 michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
00386                 break;
00387         case EVENT_SCAN_RESULTS:
00388                 if (hapd->iface->scan_cb)
00389                         hapd->iface->scan_cb(hapd->iface);
00390                 break;
00391 #ifdef CONFIG_IEEE80211R
00392         case EVENT_FT_RRB_RX:
00393                 wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src,
00394                               data->ft_rrb_rx.data, data->ft_rrb_rx.data_len);
00395                 break;
00396 #endif /* CONFIG_IEEE80211R */
00397         case EVENT_WPS_BUTTON_PUSHED:
00398                 hostapd_wps_button_pushed(hapd);
00399                 break;
00400 #ifdef NEED_AP_MLME
00401         case EVENT_TX_STATUS:
00402                 switch (data->tx_status.type) {
00403                 case WLAN_FC_TYPE_MGMT:
00404                         hostapd_mgmt_tx_cb(hapd, data->tx_status.data,
00405                                            data->tx_status.data_len,
00406                                            data->tx_status.stype,
00407                                            data->tx_status.ack);
00408                         break;
00409                 case WLAN_FC_TYPE_DATA:
00410                         hostapd_tx_status(hapd, data->tx_status.dst,
00411                                           data->tx_status.data,
00412                                           data->tx_status.data_len,
00413                                           data->tx_status.ack);
00414                         break;
00415                 }
00416                 break;
00417         case EVENT_RX_FROM_UNKNOWN:
00418                 hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.frame,
00419                                             data->rx_from_unknown.len);
00420                 break;
00421         case EVENT_RX_MGMT:
00422                 hostapd_mgmt_rx(hapd, &data->rx_mgmt);
00423                 break;
00424 #endif /* NEED_AP_MLME */
00425         case EVENT_RX_PROBE_REQ:
00426                 hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
00427                                      data->rx_probe_req.ie,
00428                                      data->rx_probe_req.ie_len);
00429                 break;
00430         case EVENT_NEW_STA:
00431                 hostapd_event_new_sta(hapd, data->new_sta.addr);
00432                 break;
00433         case EVENT_EAPOL_RX:
00434                 hostapd_event_eapol_rx(hapd, data->eapol_rx.src,
00435                                        data->eapol_rx.data,
00436                                        data->eapol_rx.data_len);
00437                 break;
00438         case EVENT_ASSOC:
00439                 hostapd_notif_assoc(hapd, data->assoc_info.addr,
00440                                     data->assoc_info.req_ies,
00441                                     data->assoc_info.req_ies_len);
00442                 break;
00443         case EVENT_DISASSOC:
00444                 if (data)
00445                         hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
00446                 break;
00447         case EVENT_DEAUTH:
00448                 if (data)
00449                         hostapd_notif_disassoc(hapd, data->deauth_info.addr);
00450                 break;
00451         default:
00452                 wpa_printf(MSG_DEBUG, "Unknown event %d", event);
00453                 break;
00454         }
00455 }
00456 
00457 #endif /* HOSTAPD */


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:34