📄 at76c503.c
字号:
memcpy(dev->bssid, mac_mgmt->current_bssid, ETH_ALEN); dbg(DBG_PROGRESS, "using BSSID %s", mac2str(dev->bssid)); memset(&mib_buf, 0, sizeof(struct set_mib_buffer)); mib_buf.type = MIB_MAC_MGMT; mib_buf.size = 1; mib_buf.index = IBSS_CHANGE_OK_OFFSET; ret = set_mib(dev, &mib_buf); if(ret < 0){ err("%s: set_mib (ibss change ok) failed: %d", netdev->name, ret); goto new_bss_clean; } clear_bit(KEVENT_NEW_BSS, &dev->kevent_flags); new_bss_clean: kfree(mac_mgmt); } if(test_bit(KEVENT_SET_PROMISC, &dev->kevent_flags)){ info("%s: KEVENT_SET_PROMISC", dev->netdev->name); set_promisc(dev, dev->promisc); clear_bit(KEVENT_SET_PROMISC, &dev->kevent_flags); } if(test_bit(KEVENT_MGMT_TIMEOUT, &dev->kevent_flags)){ clear_bit(KEVENT_MGMT_TIMEOUT, &dev->kevent_flags); handle_mgmt_timeout(dev); } /* check this _before_ KEVENT_JOIN, 'cause _JOIN sets _STARTIBSS bit */ if (test_bit(KEVENT_STARTIBSS, &dev->kevent_flags)) { struct set_mib_buffer mib_buf; clear_bit(KEVENT_STARTIBSS, &dev->kevent_flags); assert(dev->istate == STARTIBSS); ret = start_ibss(dev); if(ret < 0){ err("%s: start_ibss failed: %d", dev->netdev->name, ret); goto end_startibss; } ret = wait_completion(dev, CMD_START_IBSS); if (ret != CMD_STATUS_COMPLETE) { err("%s start_ibss failed to complete,%d", dev->netdev->name, ret); goto end_startibss; } ret = get_current_bssid(dev); if(ret < 0) goto end_startibss; ret = get_current_channel(dev); if(ret < 0) goto end_startibss; /* not sure what this is good for ??? */ memset(&mib_buf, 0, sizeof(struct set_mib_buffer)); mib_buf.type = MIB_MAC_MGMT; mib_buf.size = 1; mib_buf.index = IBSS_CHANGE_OK_OFFSET; ret = set_mib(dev, &mib_buf); if(ret < 0){ err("%s: set_mib (ibss change ok) failed: %d", dev->netdev->name, ret); goto end_startibss; } netif_start_queue(dev->netdev); }end_startibss: /* check this _before_ KEVENT_SCAN, 'cause _SCAN sets _JOIN bit */ if (test_bit(KEVENT_JOIN, &dev->kevent_flags)) { clear_bit(KEVENT_JOIN, &dev->kevent_flags); if (dev->istate == INIT) goto end_join; assert(dev->istate == JOINING); /* dev->curr_bss == NULL signals a new round, starting with list_entry(dev->bss_list.next, ...) */ /* secure the access to dev->curr_bss ! */ spin_lock_irqsave(&dev->bss_list_spinlock, flags); dev->curr_bss=find_matching_bss(dev, dev->curr_bss); spin_unlock_irqrestore(&dev->bss_list_spinlock, flags); if (dev->curr_bss != NULL) { if ((ret=join_bss(dev,dev->curr_bss)) < 0) { err("%s: join_bss failed with %d", dev->netdev->name, ret); goto end_join; } ret=wait_completion(dev,CMD_JOIN); if (ret != CMD_STATUS_COMPLETE) { if (ret != CMD_STATUS_TIME_OUT) err("%s join_bss completed with %d", dev->netdev->name, ret); else info("%s join_bss ssid %s timed out", dev->netdev->name, mac2str(dev->curr_bss->bssid)); /* retry next BSS immediately */ defer_kevent(dev,KEVENT_JOIN); goto end_join; } /* here we have joined the (I)BSS */ if (dev->iw_mode == IW_MODE_ADHOC) { struct bss_info *bptr = dev->curr_bss; NEW_STATE(dev,CONNECTED); /* get ESSID, BSSID and channel for dev->curr_bss */ dev->essid_size = bptr->ssid_len; memcpy(dev->essid, bptr->ssid, bptr->ssid_len); memcpy(dev->bssid, bptr->bssid, ETH_ALEN); dev->channel = bptr->channel; netif_start_queue(dev->netdev); /* just to be sure */ del_timer_sync(&dev->mgmt_timer); } else { /* send auth req */ NEW_STATE(dev,AUTHENTICATING); auth_req(dev, dev->curr_bss, 1, NULL); mod_timer(&dev->mgmt_timer, jiffies+HZ); } goto end_join; } /* if (dev->curr_bss != NULL) */ /* here we haven't found a matching (i)bss ... */ if (dev->iw_mode == IW_MODE_ADHOC) { NEW_STATE(dev,STARTIBSS); defer_kevent(dev,KEVENT_STARTIBSS); goto end_join; } /* haven't found a matching BSS in infra mode - use timer to try again in 10 seconds */ NEW_STATE(dev,SCANNING); mod_timer(&dev->mgmt_timer, jiffies+RESCAN_TIME*HZ); } /* if (test_bit(KEVENT_JOIN, &dev->kevent_flags)) */end_join: if (test_bit(KEVENT_SCAN, &dev->kevent_flags)) { clear_bit(KEVENT_SCAN, &dev->kevent_flags); if (dev->istate == INIT) goto end_scan; assert(dev->istate == SCANNING); /* empty the driver's bss list */ free_bss_list(dev); /* scan twice: first run with ProbeReq containing the empty SSID, the second run with the real SSID. APs in cloaked mode (e.g. Agere) will answer in the second run with their real SSID. */ if ((ret=start_scan(dev, 0)) < 0) { err("%s: start_scan failed with %d", dev->netdev->name, ret); goto end_scan; } if ((ret=wait_completion(dev,CMD_SCAN)) != CMD_STATUS_COMPLETE) { err("%s start_scan completed with %d", dev->netdev->name, ret); goto end_scan; } /* dump the results of the scan with ANY ssid */ dump_bss_table(dev, 0); if ((ret=start_scan(dev, 1)) < 0) { err("%s: 2.start_scan failed with %d", dev->netdev->name, ret); goto end_scan; } if ((ret=wait_completion(dev,CMD_SCAN)) != CMD_STATUS_COMPLETE) { err("%s 2.start_scan completed with %d", dev->netdev->name, ret); goto end_scan; } /* dump the results of the scan with real ssid */ dump_bss_table(dev, 0); NEW_STATE(dev,JOINING); assert(dev->curr_bss == NULL); /* done in free_bss_list, find_bss will start with first bss */ /* call join_bss immediately after re-run of all other threads in kevent */ defer_kevent(dev,KEVENT_JOIN); } /* if (test_bit(KEVENT_SCAN, &dev->kevent_flags)) */end_scan: if (test_bit(KEVENT_SUBMIT_RX, &dev->kevent_flags)) { clear_bit(KEVENT_SUBMIT_RX, &dev->kevent_flags); submit_rx_urb(dev); } if (test_bit(KEVENT_RESTART, &dev->kevent_flags)) { clear_bit(KEVENT_RESTART, &dev->kevent_flags); assert(dev->istate == INIT); startup_device(dev); /* scan again in a second */ NEW_STATE(dev,SCANNING); mod_timer(&dev->mgmt_timer, jiffies+HZ); } if (test_bit(KEVENT_ASSOC_DONE, &dev->kevent_flags)) { clear_bit(KEVENT_ASSOC_DONE, &dev->kevent_flags); assert(dev->istate == ASSOCIATING || dev->istate == REASSOCIATING); if (dev->iw_mode == IW_MODE_INFRA) { assert(dev->curr_bss != NULL); if (dev->curr_bss != NULL && dev->pm_mode != PM_ACTIVE) { /* calc the listen interval in units of beacon intervals of the curr_bss */ dev->pm_period_beacon = (dev->pm_period_us >> 10) / dev->curr_bss->beacon_interval;#if 0 /* only to check if we need to set the listen interval here or could do it in the (re)assoc_req parameter */ dump_mib_mac(dev);#endif if (dev->pm_period_beacon < 2) dev->pm_period_beacon = 2; else if ( dev->pm_period_beacon > 0xffff) dev->pm_period_beacon = 0xffff; dbg(DBG_PM, "%s: pm_mode %d assoc id x%x listen int %d", dev->netdev->name, dev->pm_mode, dev->curr_bss->assoc_id, dev->pm_period_beacon); set_associd(dev, dev->curr_bss->assoc_id); set_listen_interval(dev, (u16)dev->pm_period_beacon); set_pm_mode(dev, dev->pm_mode);#if 0 dump_mib_mac(dev); dump_mib_mac_mgmt(dev);#endif } } netif_carrier_on(dev->netdev); netif_wake_queue(dev->netdev); /* _start_queue ??? */ NEW_STATE(dev,CONNECTED); dbg(DBG_PROGRESS, "%s: connected to BSSID %s", dev->netdev->name, mac2str(dev->curr_bss->bssid)); } up(&dev->sem); dbg(DBG_KEVENT, "%s: kevent exit flags=x%x", dev->netdev->name, dev->kevent_flags); return;}staticint essid_matched(struct at76c503 *dev, struct bss_info *ptr){ /* common criteria for both modi */ int retval = (dev->essid_size == 0 /* ANY ssid */ || (dev->essid_size == ptr->ssid_len && !memcmp(dev->essid, ptr->ssid, ptr->ssid_len))); if (!retval) dbg(DBG_BSS_MATCH, "%s bss table entry %p: essid didn't match", dev->netdev->name, ptr); return retval;}static inlineint mode_matched(struct at76c503 *dev, struct bss_info *ptr){ int retval; if (dev->iw_mode == IW_MODE_ADHOC) retval = ptr->capa & IEEE802_11_CAPA_IBSS; else retval = ptr->capa & IEEE802_11_CAPA_ESS; if (!retval) dbg(DBG_BSS_MATCH, "%s bss table entry %p: mode didn't match", dev->netdev->name, ptr); return retval;}staticint rates_matched(struct at76c503 *dev, struct bss_info *ptr){ int i; u8 *rate; for(i=0,rate=ptr->rates; i < ptr->rates_len; i++,rate++) if (*rate & 0x80) { /* this is a basic rate we have to support (see IEEE802.11, ch. 7.3.2.2) */ if (*rate != (0x80|hw_rates[0]) && *rate != (0x80|hw_rates[1]) && *rate != (0x80|hw_rates[2]) && *rate != (0x80|hw_rates[3])) { dbg(DBG_BSS_MATCH, "%s: bss table entry %p: basic rate %02x not supported", dev->netdev->name, ptr, *rate); return 0; } } /* if we use short preamble, the bss must support it */ if (dev->preamble_type == PREAMBLE_TYPE_SHORT && !(ptr->capa & IEEE802_11_CAPA_SHORT_PREAMBLE)) { dbg(DBG_BSS_MATCH, "%s: %p does not support short preamble", dev->netdev->name, ptr); return 0; } else return 1;}static inlineint wep_matched(struct at76c503 *dev, struct bss_info *ptr){ if (!dev->wep_enabled && ptr->capa & IEEE802_11_CAPA_PRIVACY) { /* we have disabled WEP, but the BSS signals privacy */ dbg(DBG_BSS_MATCH, "%s: bss table entry %p: requires encryption", dev->netdev->name, ptr); return 0; } /* otherwise if the BSS does not signal privacy it may well accept encrypted packets from us ... */ return 1;}static void dump_bss_table(struct at76c503 *dev, int force_output){ struct bss_info *ptr; /* hex dump output buffer for debug */ char hexssid[IW_ESSID_MAX_SIZE*2+1] __attribute__ ((unused)); char hexrates[BSS_LIST_MAX_RATE_LEN*3+1] __attribute__ ((unused)); unsigned long flags; struct list_head *lptr; if ((debug & DBG_BSS_TABLE) || (force_output)) { spin_lock_irqsave(&dev->bss_list_spinlock, flags); dbg_uc("%s BSS table (curr=%p, new=%p):", dev->netdev->name, dev->curr_bss, dev->new_bss); list_for_each(lptr, &dev->bss_list) { ptr = list_entry(lptr, struct bss_info, list); dbg_uc("0x%p: bssid %s channel %d ssid %s (%s)" " capa x%04x rates %s rssi %d link %d noise %d", ptr, mac2str(ptr->bssid), ptr->channel, ptr->ssid, hex2str(hexssid,ptr->ssid,ptr->ssid_len,'\0'), le16_to_cpu(ptr->capa), hex2str(hexrates, ptr->rates, ptr->rates_len, ' '), ptr->rssi, ptr->link_qual, ptr->noise_level); } spin_unlock_irqrestore(&dev->bss_list_spinlock, flags); }}/* try to find a matching bss in dev->bss, starting at position start. returns the ptr to a matching bss in the list or NULL if none found *//* last is the last bss tried, last == NULL signals a new round, starting with list_entry(dev->bss_list.next, ...) *//* this proc must be called inside an aquired dev->bss_list_spinlock otherwise the timeout on bss may remove the newly chosen entry ! */static struct bss_info *find_matching_bss(struct at76c503 *dev, struct bss_info *last){ struct bss_info *ptr = NULL; struct list_head *curr; curr = last != NULL ? last->list.next : dev->bss_list.next; while (curr != &dev->bss_list) { ptr = list_entry(curr, struct bss_info, list); if (essid_matched(dev,ptr) && mode_matched(dev,ptr) && wep_matched(dev,ptr) && rates_matched(dev,ptr)) break; curr = curr->next; } if (curr == &dev->bss_list) ptr = NULL; /* otherwise ptr points to the struct bss_info we have chosen */ dbg(DBG_BSS_TABLE, "%s %s: returned %p", dev->netdev->name, __FUNCTION__, ptr); return ptr;} /* find_matching_bss *//* we got an association response */static void rx_mgmt_assoc(struct at76c503 *dev, struct at76c503_rx_buffer *buf){ struct ieee802_11_mgmt *mgmt = (struct ieee802_11_mgmt *)buf->packet; struct ieee802_11_assoc_resp *resp = (struct ieee802_11_assoc_resp *)mgmt->data; char orates[2*8+1] __attribute__((unused)); u16 assoc_id = le16_to_cpu(resp->assoc_id); u16 status = le16_to_cpu(resp->status); u16 capa = le16_to_cpu(resp->capability); dbg(DBG_RX_MGMT, "%s: rx AssocResp bssid %s capa x%04x status x%04x " "assoc_id x%04x rates %s", dev->netdev->name, mac2str(mgmt->addr3), capa, status, assoc_id, hex2str(orates, resp->data+2, min((size_t)*(resp->data+1),(sizeof(orates)-1)/2), '\0')); if (dev->istate == ASSOCIATING) { assert(dev->curr_bss != NULL); if (dev->curr_bss == NULL) return; if (status == IEEE802_11_STATUS_SUCCESS) { struct bss_info *ptr = dev->curr_bss; ptr->assoc_id = assoc_id & 0x3fff; /* update iwconfig params */ memcpy(dev->bssid, ptr->bssid, ETH_ALEN); memcpy(dev->essid, ptr->ssid, ptr->ssid_len); dev->essid_size = ptr->ssid_len; dev->channel = ptr->channel; defer_kevent(dev,KEVENT_ASSOC_DONE); } else { NEW_STATE(dev,JOINING); defer_kevent(dev,KEVENT_JOIN); } del_timer_sync(&dev->mgmt_timer); } else info("%s: AssocResp in state %d ignored", dev->netdev->name, dev->istate);} /* rx_mgmt_assoc */static void rx_mgmt_reassoc(struct at76c503 *dev, struct at76c503_rx_buffer *buf){ struct ieee802_11_mgmt *mgmt = (struct ieee802_11_mgmt *)buf->packet; struct ieee802_11_assoc_resp *resp = (struct ieee802_11_assoc_resp *)mgmt->data; char orates[2*8+1] __attribute__((unused)); unsigned long flags; u16 capa = le16_to_cpu(resp->capability); u16 status = le16_to_cpu(resp->status); u16 assoc_id = le16_to_cpu(resp->asso
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -