void ieee802_11_mgmt_cb(struct hostapd_data *hapd, u8 *buf, size_t len, u16 stype, int ok) { struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) buf; switch (stype) { case WLAN_FC_STYPE_AUTH: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "mgmt::auth cb\n"); handle_auth_cb(hapd, mgmt, len, ok); break; case WLAN_FC_STYPE_ASSOC_RESP: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "mgmt::assoc_resp cb\n"); handle_assoc_cb(hapd, mgmt, len, 0, ok); break; case WLAN_FC_STYPE_REASSOC_RESP: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "mgmt::reassoc_resp cb\n"); handle_assoc_cb(hapd, mgmt, len, 1, ok); break; default: printf("unknown mgmt cb frame subtype %d\n", stype); break; } }
static void handle_tx_callback(hostapd *hapd, char *buf, size_t len, int ok) { struct ieee80211_hdr *hdr; u16 fc, type, stype; hdr = (struct ieee80211_hdr *) buf; fc = le_to_host16(hdr->frame_control); type = WLAN_FC_GET_TYPE(fc); stype = WLAN_FC_GET_STYPE(fc); switch (type) { case WLAN_FC_TYPE_MGMT: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "MGMT (TX callback) %s\n", ok ? "ACK" : "fail"); ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); break; case WLAN_FC_TYPE_CTRL: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "CTRL (TX callback) %s\n", ok ? "ACK" : "fail"); break; case WLAN_FC_TYPE_DATA: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "DATA (TX callback) %s\n", ok ? "ACK" : "fail"); /* TODO: could replace TXExc counter hack with kernel driver * in data polling for inactivity check with the new TX * callback.. */ /* handle_data_cb(hapd, buf, len, stype, ok); */ break; default: printf("unknown TX callback frame type %d\n", type); break; } }
static void rsn_preauth_receive(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { struct rsn_preauth_interface *piface = ctx; struct hostapd_data *hapd = piface->hapd; struct ieee802_1x_hdr *hdr; struct sta_info *sta; struct l2_ethhdr *ethhdr; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: receive pre-auth packet " "from interface '%s'\n", piface->ifname); if (len < sizeof(*ethhdr) + sizeof(*hdr)) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: too short pre-auth " "packet (len=%lu)\n", (unsigned long) len); return; } ethhdr = (struct l2_ethhdr *) buf; hdr = (struct ieee802_1x_hdr *) (ethhdr + 1); if (memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: pre-auth for " "foreign address " MACSTR "\n", MAC2STR(ethhdr->h_dest)); return; } sta = ap_get_sta(hapd, ethhdr->h_source); if (sta && (sta->flags & WLAN_STA_ASSOC)) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: pre-auth for " "already association STA " MACSTR "\n", MAC2STR(sta->addr)); return; } if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) { sta = ap_sta_add(hapd, ethhdr->h_source); if (sta == NULL) return; sta->flags = WLAN_STA_PREAUTH; ieee802_1x_new_station(hapd, sta); if (sta->eapol_sm == NULL) { ap_free_sta(hapd, sta); sta = NULL; } else { sta->eapol_sm->radius_identifier = -1; sta->eapol_sm->portValid = TRUE; sta->eapol_sm->flags |= EAPOL_SM_PREAUTH; } } if (sta == NULL) return; sta->preauth_iface = piface; ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1), len - sizeof(*ethhdr)); }
/* This function will be called whenever a station associates with the AP */ void hostapd_new_assoc_sta(hostapd *hapd, struct sta_info *sta) { if (hapd->tkip_countermeasures) { hostapd_sta_deauth(hapd, sta->addr, WLAN_REASON_MICHAEL_MIC_FAILURE); return; } /* IEEE 802.11F (IAPP) */ if (hapd->conf->ieee802_11f) iapp_new_station(hapd->iapp, sta); /* Start accounting here, if IEEE 802.1X is not used. IEEE 802.1X code * will start accounting after the station has been authorized. */ if (!hapd->conf->ieee802_1x) accounting_sta_start(hapd, sta); #ifdef JUMPSTART if (hapd->conf->js_p1) { /* Only one STA at a time to attempt Jumpstart */ if (!hapd->jsw_profile->p1_in_progress) { hapd->jsw_profile->p1_in_progress = 1; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "JUMPSTART: " MACSTR " %s: starting P1\n", MAC2STR(sta->addr), __func__); js_p1_new_station(hapd, sta); /* Start the JS state machine */ smSendEvent(sta->js_session, JSW_EVENT_ASSOC); } else { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "JUMPSTART: " MACSTR "%s: P1 running with another STA." " Disassoc\n", MAC2STR(sta->addr), __func__); hostapd_sta_disassoc(hapd, sta->addr, WLAN_REASON_UNSPECIFIED); } return; } #endif /* JUMPSTART */ /* Start IEEE 802.1x authentication process for new stations */ ieee802_1x_new_station(hapd, sta); wpa_new_station(hapd, sta); }
u8 radius_client_get_id(struct radius_client_data *radius) { struct hostapd_data *hapd = radius->hapd; struct radius_msg_list *entry, *prev, *remove; u8 id = radius->next_radius_identifier++; /* remove entries with matching id from retransmit list to avoid * using new reply from the RADIUS server with an old request */ entry = radius->msgs; prev = NULL; while (entry) { if (entry->msg->hdr->identifier == id) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Removing pending RADIUS message, since " "its id (%d) is reused\n", id); if (prev) prev->next = entry->next; else radius->msgs = entry->next; remove = entry; } else remove = NULL; prev = entry; entry = entry->next; if (remove) radius_client_msg_free(remove); } return id; }
static void radius_client_list_del(struct radius_client_data *radius, RadiusType msg_type, u8 *addr) { struct hostapd_data *hapd = radius->hapd; struct radius_msg_list *entry, *prev, *tmp; if (addr == NULL) return; entry = radius->msgs; prev = NULL; while (entry) { if (entry->msg_type == msg_type && memcmp(entry->addr, addr, ETH_ALEN) == 0) { if (prev) prev->next = entry->next; else radius->msgs = entry->next; tmp = entry; entry = entry->next; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Removing matching RADIUS message for " MACSTR "\n", MAC2STR(addr)); radius_client_msg_free(tmp); radius->num_msgs--; continue; } prev = entry; entry = entry->next; } }
static void radius_client_update_timeout(struct radius_client_data *radius) { struct hostapd_data *hapd = radius->hapd; time_t now, first; struct radius_msg_list *entry; eloop_cancel_timeout(radius_client_timer, radius, NULL); if (radius->msgs == NULL) { return; } first = 0; for (entry = radius->msgs; entry; entry = entry->next) { if (first == 0 || entry->next_try < first) first = entry->next_try; } time(&now); if (first < now) first = now; eloop_register_timeout(first - now, 0, radius_client_timer, radius, NULL); HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Next RADIUS client retransmit in" " %ld seconds\n", (long int) (first - now)); }
void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta, u8 *buf, size_t len) { struct rsn_preauth_interface *piface; struct l2_ethhdr *ethhdr; piface = hapd->preauth_iface; while (piface) { if (piface == sta->preauth_iface) break; piface = piface->next; } if (piface == NULL) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: Could not find " "pre-authentication interface for " MACSTR "\n", MAC2STR(sta->addr)); return; } ethhdr = malloc(sizeof(*ethhdr) + len); if (ethhdr == NULL) return; memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN); memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN); ethhdr->h_proto = htons(ETH_P_PREAUTH); memcpy(ethhdr + 1, buf, len); if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr, sizeof(*ethhdr) + len) < 0) { printf("Failed to send preauth packet using l2_packet_send\n"); } free(ethhdr); }
static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname) { struct rsn_preauth_interface *piface; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN pre-auth interface '%s'\n", ifname); piface = wpa_zalloc(sizeof(*piface)); if (piface == NULL) return -1; piface->hapd = hapd; piface->ifname = strdup(ifname); if (piface->ifname == NULL) { goto fail1; } piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH, rsn_preauth_receive, piface, 1); if (piface->l2 == NULL) { printf("Failed to open register layer 2 access to " "ETH_P_PREAUTH\n"); goto fail2; } piface->next = hapd->preauth_iface; hapd->preauth_iface = piface; return 0; fail2: free(piface->ifname); fail1: free(piface); return -1; }
static void hostapd_acl_expire_queries(struct hostapd_data *hapd, time_t now) { struct hostapd_acl_query_data *prev, *entry, *tmp; prev = NULL; entry = hapd->acl_queries; while (entry) { if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "ACL query for " MACSTR " has expired.\n", MAC2STR(entry->addr)); if (prev) prev->next = entry->next; else hapd->acl_queries = entry->next; tmp = entry; entry = entry->next; hostapd_acl_query_free(tmp); continue; } prev = entry; entry = entry->next; } }
static int radius_client_retransmit(hostapd *hapd, struct radius_msg_list *entry, time_t now) { int s; if (entry->msg_type == RADIUS_ACCT) s = hapd->radius->acct_serv_sock; else s = hapd->radius->auth_serv_sock; /* retransmit; remove entry if too many attempts */ entry->attempts++; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Resending RADIUS message (id=%d)" "\n", entry->msg->hdr->identifier); if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0) perror("send[RADIUS]"); entry->next_try = now + entry->next_wait; entry->next_wait *= 2; if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT) entry->next_wait = RADIUS_CLIENT_MAX_WAIT; if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) { printf("Removing un-ACKed RADIUS message due to too many " "failed retransmit attempts\n"); return 1; } return 0; }
static void hostapd_acl_expire_cache(hostapd *hapd, time_t now) { struct hostapd_cached_radius_acl *prev, *entry, *tmp; prev = NULL; entry = hapd->acl_cache; while (entry) { if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Cached ACL entry for " MACSTR " has expired.\n", MAC2STR(entry->addr)); if (prev) prev->next = entry->next; else hapd->acl_cache = entry->next; tmp = entry; entry = entry->next; free(tmp); continue; } prev = entry; entry = entry->next; } }
/** * reload_hw_mode_done - Callback for after the HW mode is setup * @hapd_iface: Pointer to interface data. * @status: Status of the HW mode setup. */ static void reload_hw_mode_done(struct hostapd_iface *hapd_iface, int status) { struct hostapd_data *hapd = hapd_iface->bss[0]; struct hostapd_config_change *change = hapd_iface->change; struct hostapd_config *newconf = change->newconf; hostapd_iface_cb cb; int freq; if (status) { printf("Failed to select hw_mode.\n"); cb = hapd_iface->reload_iface_cb; hapd_iface->reload_iface_cb = NULL; cb(hapd_iface, -1); return; } freq = hostapd_hw_get_freq(hapd, newconf->channel); HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Mode: %s Channel: %d Frequency: %d MHz\n", hostapd_hw_mode_txt(newconf->hw_mode), newconf->channel, freq); if (hostapd_set_freq(hapd, newconf->hw_mode, freq)) { printf("Could not set channel %d (%d MHz) for kernel " "driver\n", newconf->channel, freq); } change->beacon_changed++; reload_iface2(hapd_iface); }
struct sta_info * ap_sta_add(struct hostapd_data *hapd, u8 *addr) { struct sta_info *sta; sta = ap_get_sta(hapd, addr); if (sta) return sta; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " New STA\n"); if (hapd->num_sta >= MAX_STA_COUNT) { /* FIX: might try to remove some old STAs first? */ printf(" no more room for new STAs (%d/%d)\n", hapd->num_sta, MAX_STA_COUNT); return NULL; } sta = (struct sta_info *) malloc(sizeof(struct sta_info)); if (sta == NULL) { printf(" malloc failed\n"); return NULL; } memset(sta, 0, sizeof(struct sta_info)); sta->acct_interim_interval = hapd->conf->radius_acct_interim_interval; /* initialize STA info data */ eloop_register_timeout(AP_MAX_INACTIVITY, 0, ap_handle_timer, hapd, sta); memcpy(sta->addr, addr, ETH_ALEN); sta->next = hapd->sta_list; hapd->sta_list = sta; hapd->num_sta++; ap_sta_hash_add(hapd, sta); return sta; }
static int bsd_set_ieee8021x(void *priv, int enabled) { struct bsd_driver_data *drv = priv; hostapd *hapd = drv->hapd; struct hostapd_config *conf = hapd->conf; HOSTAPD_DEBUG(HOSTAPD_DEBUG_VERBOSE, "%s: enabled=%d\n", __func__, enabled); if (!enabled) { /* XXX restore state */ return set80211param(priv, IEEE80211_IOC_AUTHMODE, IEEE80211_AUTH_AUTO); } if (!conf->wpa && !conf->ieee802_1x) { hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER, HOSTAPD_LEVEL_WARNING, "No 802.1x or WPA enabled!"); return -1; } if (conf->wpa && bsd_configure_wpa(drv) != 0) { hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER, HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!"); return -1; } if (set80211param(priv, IEEE80211_IOC_AUTHMODE, (conf->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER, HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1x!"); return -1; } return bsd_set_iface_flags(priv, 1); }
static int bsd_get_seqnum(void *priv, u8 *addr, int idx, u8 *seq) { struct bsd_driver_data *drv = priv; hostapd *hapd = drv->hapd; struct ieee80211req_key wk; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "%s: addr=%s idx=%d\n", __func__, ether_sprintf(addr), idx); memset(&wk, 0, sizeof(wk)); if (addr == NULL) memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); else memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); wk.ik_keyix = idx; if (get80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) { printf("Failed to get encryption.\n"); return -1; } else { memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); return 0; } }
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) { struct sta_info *sta; sta = ap_get_sta(hapd, addr); if (sta) return sta; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " New STA\n"); if (hapd->num_sta >= hapd->conf->max_num_sta) { /* FIX: might try to remove some old STAs first? */ printf(" no more room for new STAs (%d/%d)\n", hapd->num_sta, hapd->conf->max_num_sta); return NULL; } sta = wpa_zalloc(sizeof(struct sta_info)); if (sta == NULL) { printf(" malloc failed\n"); return NULL; } sta->acct_interim_interval = hapd->conf->radius->acct_interim_interval; /* initialize STA info data */ eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, ap_handle_timer, hapd, sta); memcpy(sta->addr, addr, ETH_ALEN); sta->next = hapd->sta_list; hapd->sta_list = sta; hapd->num_sta++; ap_sta_hash_add(hapd, sta); sta->ssid = &hapd->conf->ssid; return sta; }
void ieee80211_michael_mic_failure(struct hostapd_data *hapd, u8 *addr, int local) { time_t now; if (addr && local) { struct sta_info *sta = ap_get_sta(hapd, addr); if (sta != NULL) { sta->dot11RSNAStatsTKIPLocalMICFailures++; hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "Michael MIC failure detected in " "received frame"); } else { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "MLME-MICHAELMICFAILURE.indication " "for not associated STA (" MACSTR ") ignored\n", MAC2STR(addr)); return; } } time(&now); if (now > hapd->michael_mic_failure + 60) { hapd->michael_mic_failures = 1; } else { hapd->michael_mic_failures++; if (hapd->michael_mic_failures > 1) ieee80211_tkip_countermeasures_start(hapd); } hapd->michael_mic_failure = now; }
void ieee802_11_mgmt(struct hostapd_data *hapd, u8 *buf, size_t len, u16 stype) { struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) buf; if (stype == WLAN_FC_STYPE_BEACON) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_EXCESSIVE, "mgmt::beacon\n"); handle_beacon(hapd, mgmt, len); return; } if (memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0 && (hapd->assoc_ap_state == DO_NOT_ASSOC || memcmp(mgmt->bssid, hapd->conf->assoc_ap_addr, ETH_ALEN) != 0)) { printf("MGMT: BSSID=" MACSTR " not our address\n", MAC2STR(mgmt->bssid)); return; } if (stype == WLAN_FC_STYPE_PROBE_REQ) { printf("mgmt::probe_req\n"); return; } if (memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) { printf("MGMT: DA=" MACSTR " not our address\n", MAC2STR(mgmt->da)); return; } switch (stype) { case WLAN_FC_STYPE_AUTH: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "mgmt::auth\n"); handle_auth(hapd, mgmt, len); break; case WLAN_FC_STYPE_ASSOC_REQ: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "mgmt::assoc_req\n"); handle_assoc(hapd, mgmt, len, 0); break; case WLAN_FC_STYPE_ASSOC_RESP: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "mgmt::assoc_resp\n"); handle_assoc_resp(hapd, mgmt, len); break; case WLAN_FC_STYPE_REASSOC_REQ: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "mgmt::reassoc_req\n"); handle_assoc(hapd, mgmt, len, 1); break; case WLAN_FC_STYPE_DISASSOC: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "mgmt::disassoc\n"); handle_disassoc(hapd, mgmt, len); break; case WLAN_FC_STYPE_DEAUTH: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "mgmt::deauth\n"); handle_deauth(hapd, mgmt, len); break; default: printf("unknown mgmt frame subtype %d\n", stype); break; } }
int hostapd_init_sockets(struct hostap_driver_data *drv) { struct hostapd_data *hapd = drv->hapd; struct ifreq ifr; struct sockaddr_ll addr; drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (drv->sock < 0) { perror("socket[PF_PACKET,SOCK_RAW]"); return -1; } if (eloop_register_read_sock(drv->sock, handle_read, drv->hapd, NULL)) { printf("Could not register read socket\n"); return -1; } memset(&ifr, 0, sizeof(ifr)); snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface); if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) { perror("ioctl(SIOCGIFINDEX)"); return -1; } if (hostapd_set_iface_flags(drv, 1)) { return -1; } memset(&addr, 0, sizeof(addr)); addr.sll_family = AF_PACKET; addr.sll_ifindex = ifr.ifr_ifindex; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Opening raw packet socket for ifindex %d\n", addr.sll_ifindex); if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("bind"); return -1; } memset(&ifr, 0, sizeof(ifr)); snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", drv->iface); if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) { perror("ioctl(SIOCGIFHWADDR)"); return -1; } if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { printf("Invalid HW-addr family 0x%04x\n", ifr.ifr_hwaddr.sa_family); return -1; } memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); return 0; }
static void handle_disassoc(hostapd *hapd, struct ieee80211_mgmt *mgmt, size_t len) { struct sta_info *sta; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) { printf("handle_disassoc - too short payload (len=%lu)\n", (unsigned long) len); return; } HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "disassocation: STA=" MACSTR " reason_code=%d\n", MAC2STR(mgmt->sa), le_to_host16(mgmt->u.disassoc.reason_code)); if (hapd->assoc_ap_state != DO_NOT_ASSOC && memcmp(mgmt->sa, hapd->conf->assoc_ap_addr, ETH_ALEN) == 0) { printf("Assoc AP " MACSTR " sent disassociation " "(reason_code=%d) - try to authenticate\n", MAC2STR(hapd->conf->assoc_ap_addr), le_to_host16(mgmt->u.disassoc.reason_code)); hapd->assoc_ap_state = AUTHENTICATE; ieee802_11_sta_authenticate(hapd, NULL); eloop_register_timeout(0, 500000, ieee802_11_sta_authenticate, hapd, NULL); return; } sta = ap_get_sta(hapd, mgmt->sa); if (sta == NULL) { printf("Station " MACSTR " trying to disassociate, but it " "is not associated.\n", MAC2STR(mgmt->sa)); return; } sta->flags &= ~WLAN_STA_ASSOC; wpa_sm_event(hapd, sta, WPA_DISASSOC); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "disassociated"); sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; ieee802_1x_set_port_enabled(hapd, sta, 0); /* Stop Accounting and IEEE 802.1X sessions, but leave the STA * authenticated. */ accounting_sta_stop(hapd, sta); ieee802_1x_free_station(sta); hostapd_sta_remove(hapd, sta->addr); if (sta->timeout_next == STA_NULLFUNC || sta->timeout_next == STA_DISASSOC) { sta->timeout_next = STA_DEAUTH; eloop_cancel_timeout(ap_handle_timer, hapd, sta); eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, hapd, sta); } }
static void handle_tx_callback(hostapd *hapd, char *buf, size_t len, int ok) { struct ieee80211_hdr *hdr; u16 fc, type, stype; struct sta_info *sta; hdr = (struct ieee80211_hdr *) buf; fc = le_to_host16(hdr->frame_control); type = WLAN_FC_GET_TYPE(fc); stype = WLAN_FC_GET_STYPE(fc); switch (type) { case WLAN_FC_TYPE_MGMT: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "MGMT (TX callback) %s\n", ok ? "ACK" : "fail"); ieee802_11_mgmt_cb(hapd, buf, len, stype, ok); break; case WLAN_FC_TYPE_CTRL: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "CTRL (TX callback) %s\n", ok ? "ACK" : "fail"); break; case WLAN_FC_TYPE_DATA: HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "DATA (TX callback) %s\n", ok ? "ACK" : "fail"); sta = ap_get_sta(hapd, hdr->addr1); if (sta && sta->flags & WLAN_STA_PENDING_POLL) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "STA " MACSTR " %s pending activity poll\n", MAC2STR(sta->addr), ok ? "ACKed" : "did not ACK"); if (ok) sta->flags &= ~WLAN_STA_PENDING_POLL; } if (sta) ieee802_1x_tx_status(hapd, sta, buf, len, ok); break; default: printf("unknown TX callback frame type %d\n", type); break; } }
static int bsd_set_ssid(void *priv, u8 *buf, int len) { struct bsd_driver_data *drv = priv; hostapd *hapd = drv->hapd; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "%s: ssid=\"%.*s\"\n", __func__, len, buf); return set80211var(priv, IEEE80211_IOC_SSID, buf, len); }
static int bsd_set_privacy(void *priv, int enabled) { struct bsd_driver_data *drv = priv; hostapd *hapd = drv->hapd; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "%s: enabled=%d\n", __func__, enabled); return set80211param(priv, IEEE80211_IOC_PRIVACY, enabled); }
static int bsd_set_key(void *priv, const char *alg, unsigned char *addr, int key_idx, u8 *key, size_t key_len) { struct bsd_driver_data *drv = priv; hostapd *hapd = drv->hapd; struct ieee80211req_key wk; u_int8_t cipher; if (strcmp(alg, "none") == 0) return bsd_del_key(priv, addr, key_idx); HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "%s: alg=%s addr=%s key_idx=%d\n", __func__, alg, ether_sprintf(addr), key_idx); if (strcmp(alg, "WEP") == 0) cipher = IEEE80211_CIPHER_WEP; else if (strcmp(alg, "TKIP") == 0) cipher = IEEE80211_CIPHER_TKIP; else if (strcmp(alg, "CCMP") == 0) cipher = IEEE80211_CIPHER_AES_CCM; else { printf("%s: unknown/unsupported algorithm %s\n", __func__, alg); return -1; } if (key_len > sizeof(wk.ik_keydata)) { printf("%s: key length %d too big\n", __func__, key_len); return -3; } memset(&wk, 0, sizeof(wk)); wk.ik_type = cipher; wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT; if (addr == NULL) { memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); wk.ik_keyix = key_idx; wk.ik_flags |= IEEE80211_KEY_DEFAULT; } else { memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); wk.ik_keyix = IEEE80211_KEYIX_NONE; } wk.ik_keylen = key_len; memcpy(wk.ik_keydata, key, key_len); return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)); }
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta) { ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Removing STA " MACSTR " from kernel driver\n", MAC2STR(sta->addr)); if (hostapd_sta_remove(hapd, sta->addr) && sta->flags & WLAN_STA_ASSOC) { printf("Could not remove station " MACSTR " from kernel " "driver.\n", MAC2STR(sta->addr)); return -1; } return 0; }
static int bsd_sta_disassoc(void *priv, u8 *addr, int reason_code) { struct bsd_driver_data *drv = priv; hostapd *hapd = drv->hapd; struct ieee80211req_mlme mlme; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "%s: addr=%s reason_code=%d\n", __func__, ether_sprintf(addr), reason_code); mlme.im_reason = reason_code; memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); return set80211var(priv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); }
static void ap_list_timer(void *eloop_ctx, void *timeout_ctx) { struct hostapd_iface *iface = eloop_ctx; time_t now; struct ap_info *ap; eloop_register_timeout(10, 0, ap_list_timer, iface, NULL); if (!iface->ap_list) return; time(&now); /* FIX: it looks like jkm-Purina ended up in busy loop in this * function. Apparently, something can still cause a loop in the AP * list.. */ while (iface->ap_list) { ap = iface->ap_list->prev; if (ap->last_beacon + iface->conf->ap_table_expiration_time >= now) break; if (iface->conf->passive_scan_interval > 0) ap_list_expired_ap(iface, ap); ap_free_ap(iface, ap); } if (iface->olbc) { int olbc = 0; ap = iface->ap_list; while (ap) { if (ap_list_beacon_olbc(iface, ap)) { olbc = 1; break; } ap = ap->next; } if (!olbc) { struct hostapd_data *hapd = iface->bss[0]; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "OLBC not detected anymore\n"); iface->olbc = 0; ieee802_11_set_beacons(hapd->iface); } } }
static int radius_client_retransmit(struct radius_client_data *radius, struct radius_msg_list *entry, time_t now) { struct hostapd_data *hapd = radius->hapd; int s; if (entry->msg_type == RADIUS_ACCT || entry->msg_type == RADIUS_ACCT_INTERIM) { s = radius->acct_serv_sock; if (entry->attempts == 0) hapd->conf->acct_server->requests++; else { hapd->conf->acct_server->timeouts++; hapd->conf->acct_server->retransmissions++; } } else { s = radius->auth_serv_sock; if (entry->attempts == 0) hapd->conf->auth_server->requests++; else { hapd->conf->auth_server->timeouts++; hapd->conf->auth_server->retransmissions++; } } /* retransmit; remove entry if too many attempts */ entry->attempts++; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Resending RADIUS message (id=%d)" "\n", entry->msg->hdr->identifier); gettimeofday(&entry->last_attempt, NULL); if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0) radius_client_handle_send_error(radius, s, entry->msg_type); entry->next_try = now + entry->next_wait; entry->next_wait *= 2; if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT) entry->next_wait = RADIUS_CLIENT_MAX_WAIT; if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) { printf("Removing un-ACKed RADIUS message due to too many " "failed retransmit attempts\n"); return 1; } return 0; }
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, u16 reason) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "%s: deauthenticate STA " MACSTR "\n", hapd->conf->iface, MAC2STR(sta->addr)); sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC)) ap_sta_remove(hapd, sta); sta->timeout_next = STA_REMOVE; eloop_cancel_timeout(ap_handle_timer, hapd, sta); eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, ap_handle_timer, hapd, sta); accounting_sta_stop(hapd, sta); ieee802_1x_free_station(sta); mlme_deauthenticate_indication(hapd, sta, reason); }