📄 at76c503.c
字号:
assert(ptr != NULL); memset(&join, 0, sizeof(struct at76c503_join)); memcpy(join.bssid, ptr->bssid, ETH_ALEN); memcpy(join.essid, ptr->ssid, ptr->ssid_len); join.essid_size = ptr->ssid_len; join.bss_type = (dev->iw_mode == IW_MODE_ADHOC ? 1 : 2); join.channel = ptr->channel; join.timeout = cpu_to_le16(2000); dbg(DBG_PROGRESS, "%s join addr %s ssid %s type %d ch %d timeout %d", dev->netdev->name, mac2str(join.bssid), join.essid, join.bss_type, join.channel, le16_to_cpu(join.timeout)); return set_card_command(dev->udev, CMD_JOIN, (unsigned char*)&join, sizeof(struct at76c503_join));} /* join_bss *//* the firmware download timeout (after remap) */void fw_dl_timeout(unsigned long par){ struct at76c503 *dev = (struct at76c503 *)par; defer_kevent(dev, KEVENT_RESET_DEVICE);}/* the restart timer timed out */void restart_timeout(unsigned long par){ struct at76c503 *dev = (struct at76c503 *)par; defer_kevent(dev, KEVENT_RESTART);}/* we got to check the bss_list for old entries */void bss_list_timeout(unsigned long par){ struct at76c503 *dev = (struct at76c503 *)par; unsigned long flags; struct list_head *lptr, *nptr; struct bss_info *ptr; spin_lock_irqsave(&dev->bss_list_spinlock, flags); list_for_each_safe(lptr, nptr, &dev->bss_list) { ptr = list_entry(lptr, struct bss_info, list); if (ptr != dev->curr_bss && ptr != dev->new_bss && time_after(jiffies, ptr->last_rx+BSS_LIST_TIMEOUT)) { dbg(DBG_BSS_TABLE_RM, "%s: bss_list: removing old BSS %s ch %d", dev->netdev->name, mac2str(ptr->bssid), ptr->channel); list_del(&ptr->list); kfree(ptr); } } spin_unlock_irqrestore(&dev->bss_list_spinlock, flags); /* restart the timer */ mod_timer(&dev->bss_list_timer, jiffies+BSS_LIST_TIMEOUT); }/* we got a timeout for a infrastructure mgmt packet */void mgmt_timeout(unsigned long par){ struct at76c503 *dev = (struct at76c503 *)par; defer_kevent(dev, KEVENT_MGMT_TIMEOUT);}/* == PROC handle_mgmt_timeout_scan == *//* called in istate SCANNING on expiry of the mgmt_timer, when a scan was run before (dev->scan_runs > 0) */void handle_mgmt_timeout_scan(struct at76c503 *dev){ u8 *cmd_status; int ret; struct mib_mdomain mdomain; cmd_status = kmalloc(40, GFP_KERNEL); if (cmd_status == NULL) { err("%s: %s: cmd_status kmalloc returned NULL", dev->netdev->name, __FUNCTION__); return; } if ((ret=get_cmd_status(dev->udev, CMD_SCAN, cmd_status)) < 0) { err("%s: %s: get_cmd_status failed with %d", dev->netdev->name, __FUNCTION__, ret); cmd_status[5] = CMD_STATUS_IN_PROGRESS; /* INFO: Hope it was a one off error - if not, scanning further down the line and stop this cycle */ } dbg(DBG_PROGRESS, "%s %s:%d got cmd_status %d (istate %d, " "scan_runs %d)", dev->netdev->name, __FUNCTION__, __LINE__, cmd_status[5], dev->istate, dev->scan_runs); if (cmd_status[5] == CMD_STATUS_COMPLETE) { if (dev->istate == SCANNING) { dump_bss_table(dev,0); switch (dev->scan_runs) { case 1: assert(dev->international_roaming); if ((ret=get_mib_mdomain(dev, &mdomain)) < 0) { err("get_mib_mdomain returned %d", ret); } else { char obuf1[2*14+1], obuf2[2*14+1]; dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %s " "tx_powerlevel %s", dev->netdev->name, hex2str(obuf1, mdomain.channel_list, (sizeof(obuf1)-1)/2,'\0'), hex2str(obuf2, mdomain.tx_powerlevel, (sizeof(obuf2)-1)/2,'\0')); } if ((ret = start_scan(dev, 0, 1)) < 0) { err("%s: %s: start_scan (ANY) failed with %d", dev->netdev->name, __FUNCTION__, ret); } dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer for %d ticks", __FUNCTION__, __LINE__, SCAN_POLL_INTERVAL); mod_timer(&dev->mgmt_timer, jiffies + SCAN_POLL_INTERVAL); break; case 2: if ((ret = start_scan(dev, 1, 1)) < 0) { err("%s: %s: start_scan (SSID) failed with %d", dev->netdev->name, __FUNCTION__, ret); } dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer for %d ticks", __FUNCTION__, __LINE__, SCAN_POLL_INTERVAL); mod_timer(&dev->mgmt_timer, jiffies + SCAN_POLL_INTERVAL); break; case 3: /* report the end of scan to user space */ iwevent_scan_complete(dev->netdev); 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); break; default: err("unexpected dev->scan_runs %d", dev->scan_runs); } /* switch (dev->scan_runs)*/ dev->scan_runs++; } else { assert(dev->istate == MONITORING); dbg(DBG_MONITOR_MODE, "%s: MONITOR MODE: restart scan", dev->netdev->name); start_scan(dev, 0, 0); dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer for %d ticks", __FUNCTION__, __LINE__, SCAN_POLL_INTERVAL); mod_timer(&dev->mgmt_timer, jiffies + SCAN_POLL_INTERVAL); } } else { if ((cmd_status[5] != CMD_STATUS_IN_PROGRESS) && (cmd_status[5] != CMD_STATUS_IDLE)) err("%s: %s: Bad scan status: %s", dev->netdev->name, __FUNCTION__, get_cmd_status_string(cmd_status[5])); /* the first cmd status after scan start is always a IDLE -> start the timer to poll again until COMPLETED */ dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer for %d ticks", __FUNCTION__, __LINE__, SCAN_POLL_INTERVAL); mod_timer(&dev->mgmt_timer, jiffies + SCAN_POLL_INTERVAL); } kfree(cmd_status);}/* the deferred procedure called from kevent() */void handle_mgmt_timeout(struct at76c503 *dev){ if ((dev->istate != SCANNING && dev->istate != MONITORING) || (debug & DBG_MGMT_TIMER)) /* this is normal behaviour in states MONITORING, SCANNING ... */ dbg(DBG_PROGRESS, "%s: timeout, state %d", dev->netdev->name, dev->istate); switch(dev->istate) { case MONITORING: case SCANNING: handle_mgmt_timeout_scan(dev); break; case JOINING: assert(0); break; case CONNECTED: /* we haven't received the beacon of this BSS for BEACON_TIMEOUT seconds */ info("%s: lost beacon bssid %s", dev->netdev->name, mac2str(dev->curr_bss->bssid)); /* jal: starting mgmt_timer in adhoc mode is questionable, but I'll leave it here to track down another lockup problem */ if (dev->iw_mode != IW_MODE_ADHOC) { netif_carrier_off(dev->netdev); netif_stop_queue(dev->netdev); iwevent_bss_disconnect(dev->netdev); NEW_STATE(dev,SCANNING); defer_kevent(dev,KEVENT_SCAN); } break; case AUTHENTICATING: if (dev->retries-- >= 0) { auth_req(dev, dev->curr_bss, 1, NULL); dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ", __FUNCTION__, __LINE__); mod_timer(&dev->mgmt_timer, jiffies+HZ); } else { /* try to get next matching BSS */ NEW_STATE(dev,JOINING); defer_kevent(dev,KEVENT_JOIN); } break; case ASSOCIATING: if (dev->retries-- >= 0) { assoc_req(dev,dev->curr_bss); dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ", __FUNCTION__, __LINE__); mod_timer(&dev->mgmt_timer, jiffies+HZ); } else { /* jal: TODO: we may be authenticated to several BSS and may try to associate to the next of them here in the future ... */ /* try to get next matching BSS */ NEW_STATE(dev,JOINING); defer_kevent(dev,KEVENT_JOIN); } break; case REASSOCIATING: if (dev->retries-- >= 0) reassoc_req(dev, dev->curr_bss, dev->new_bss); else { /* we disassociate from the curr_bss and scan again ... */ NEW_STATE(dev,DISASSOCIATING); dev->retries = DISASSOC_RETRIES; disassoc_req(dev, dev->curr_bss); } dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ", __FUNCTION__, __LINE__); mod_timer(&dev->mgmt_timer, jiffies+HZ); break; case DISASSOCIATING: if (dev->retries-- >= 0) { disassoc_req(dev, dev->curr_bss); dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ", __FUNCTION__, __LINE__); mod_timer(&dev->mgmt_timer,jiffies+HZ); } else { /* we scan again ... */ NEW_STATE(dev,SCANNING); defer_kevent(dev,KEVENT_SCAN); } break; case INIT: break; default: assert(0); } /* switch (dev->istate) */}/* handle_mgmt_timeout *//* calc. the padding from txbuf->wlength (which excludes the USB TX header) guess this is needed to compensate a flaw in the AT76C503A USB part ... */static inlineint calc_padding(int wlen){ /* add the USB TX header */ wlen += AT76C503_TX_HDRLEN; wlen = wlen % 64; if (wlen < 50) return 50 - wlen; if (wlen >=61) return 64 + 50 - wlen; return 0;}/* send a management frame on bulk-out. txbuf->wlength must be set (in LE format !) */staticint send_mgmt_bulk(struct at76c503 *dev, struct at76c503_tx_buffer *txbuf){ unsigned long flags; int ret = 0; int urb_status; void *oldbuf = NULL; netif_carrier_off(dev->netdev); /* disable running netdev watchdog */ netif_stop_queue(dev->netdev); /* stop tx data packets */ spin_lock_irqsave(&dev->mgmt_spinlock, flags); if ((urb_status=dev->write_urb->status) == USB_ST_URB_PENDING) { oldbuf=dev->next_mgmt_bulk; /* to kfree below */ dev->next_mgmt_bulk = txbuf; txbuf = NULL; } spin_unlock_irqrestore(&dev->mgmt_spinlock, flags); if (oldbuf) { /* a data/mgmt tx is already pending in the URB - if this is no error in some situations we must implement a queue or silently modify the old msg */ err("%s: %s removed pending mgmt buffer %s", dev->netdev->name, __FUNCTION__, hex2str(dev->obuf, (u8 *)dev->next_mgmt_bulk, min((int)(sizeof(dev->obuf))/3, 64),' ')); kfree(dev->next_mgmt_bulk); } if (txbuf) { txbuf->tx_rate = 0;// txbuf->padding = 0; txbuf->padding = cpu_to_le16(calc_padding(le16_to_cpu(txbuf->wlength))); if (dev->next_mgmt_bulk) { err("%s: %s URB status %d, but mgmt is pending", dev->netdev->name, __FUNCTION__, urb_status); } dbg(DBG_TX_MGMT, "%s: tx mgmt: wlen %d tx_rate %d pad %d %s", dev->netdev->name, le16_to_cpu(txbuf->wlength), txbuf->tx_rate, le16_to_cpu(txbuf->padding), hex2str(dev->obuf, txbuf->packet, min((sizeof(dev->obuf)-1)/2, (size_t)le16_to_cpu(txbuf->wlength)),'\0')); /* txbuf was not consumed above -> send mgmt msg immediately */ memcpy(dev->bulk_out_buffer, txbuf, le16_to_cpu(txbuf->wlength) + AT76C503_TX_HDRLEN); FILL_BULK_URB(dev->write_urb, dev->udev, usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), dev->bulk_out_buffer, le16_to_cpu(txbuf->wlength) + le16_to_cpu(txbuf->padding) + AT76C503_TX_HDRLEN, (usb_complete_t)at76c503_write_bulk_callback, dev); ret = submit_urb(dev->write_urb, GFP_ATOMIC); if (ret) { err("%s: %s error in tx submit urb: %d", dev->netdev->name, __FUNCTION__, ret); } kfree(txbuf); } /* if (txbuf) */ return ret;} /* send_mgmt_bulk */staticint disassoc_req(struct at76c503 *dev, struct bss_info *bss){ struct at76c503_tx_buffer *tx_buffer; struct ieee802_11_mgmt *mgmt; struct ieee802_11_disassoc_frame *req; assert(bss != NULL); if (bss == NULL) return -EFAULT; tx_buffer = kmalloc(DISASSOC_FRAME_SIZE + MAX_PADDING_SIZE, GFP_ATOMIC); if (!tx_buffer) return -ENOMEM; mgmt = (struct ieee802_11_mgmt *)&(tx_buffer->packet); req = (struct ieee802_11_disassoc_frame *)&(mgmt->data); /* make wireless header */ mgmt->frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT|IEEE802_11_STYPE_AUTH); mgmt->duration_id = cpu_to_le16(0x8000); memcpy(mgmt->addr1, bss->bssid, ETH_ALEN); memcpy(mgmt->addr2, dev->netdev->dev_addr, ETH_ALEN); memcpy(mgmt->addr3, bss->bssid, ETH_ALEN); mgmt->seq_ctl = cpu_to_le16(0); req->reason = 0; /* init. at76c503 tx header */ tx_buffer->wlength = cpu_to_le16(DISASSOC_FRAME_SIZE - AT76C503_TX_HDRLEN); dbg(DBG_TX_MGMT, "%s: DisAssocReq bssid %s", dev->netdev->name, mac2str(mgmt->addr3)); /* either send immediately (if no data tx is pending or put it in pending list */ return send_mgmt_bulk(dev, tx_buffer); } /* disassoc_req *//* challenge is the challenge string (in TLV format) we got with seq_nr 2 for shared secret authentication only and send in seq_nr 3 WEP encrypted to prove we have the correct WEP key; otherwise it is NULL */staticint auth_req(struct at76c503 *dev, struct bss_info *bss, int seq_nr, u8 *challenge){ struct at76c503_tx_buffer *tx_buffer; struct ieee802_11_mgmt *mgmt; struct ieee802_11_auth_frame *req; int buf_len = (seq_nr != 3 ? AUTH_FRAME_SIZE : AUTH_FRAME_SIZE + 1 + 1 + challenge[1]); assert(bss != NULL); assert(seq_nr != 3 || challenge != NULL); tx_buffer = kmalloc(buf_len + MAX_PADDING_SIZE, GFP_ATOMIC); if (!tx_buffer) return -ENOMEM; mgmt = (struct ieee802_11_mgmt *)&(tx_buffer->packet); req = (struct ieee802_11_auth_fr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -