📄 at76c503.c
字号:
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); } mod_timer(&dev->mgmt_timer, jiffies+HZ); break; case DISASSOCIATING: if (dev->retries-- >= 0) { disassoc_req(dev, dev->curr_bss); 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; char obuf[3*64+1] __attribute__ ((unused)); 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(obuf, (u8 *)dev->next_mgmt_bulk, 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(obuf,txbuf->packet, min((sizeof(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, at76c503_write_bulk_callback, dev); ret = usb_submit_urb(dev->write_urb); 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_frame *)&(mgmt->data); /* make wireless header */ /* first auth msg is not encrypted, only the second (seq_nr == 3) */ mgmt->frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT | IEEE802_11_STYPE_AUTH | (seq_nr == 3 ? IEEE802_11_FCTL_WEP : 0)); 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->algorithm = cpu_to_le16(dev->auth_mode); req->seq_nr = cpu_to_le16(seq_nr); req->status = cpu_to_le16(0); if (seq_nr == 3) memcpy(req->challenge, challenge, 1+1+challenge[1]); /* init. at76c503 tx header */ tx_buffer->wlength = cpu_to_le16(buf_len - AT76C503_TX_HDRLEN); dbg(DBG_TX_MGMT, "%s: AuthReq bssid %s alg %d seq_nr %d", dev->netdev->name, mac2str(mgmt->addr3), le16_to_cpu(req->algorithm), le16_to_cpu(req->seq_nr)); if (seq_nr == 3) { char obuf[18*3] __attribute__ ((unused)); dbg(DBG_TX_MGMT, "%s: AuthReq challenge: %s ...", dev->netdev->name, hex2str(obuf, req->challenge, sizeof(obuf)/3,' ')); } /* either send immediately (if no data tx is pending or put it in pending list */ return send_mgmt_bulk(dev, tx_buffer); } /* auth_req */staticint assoc_req(struct at76c503 *dev, struct bss_info *bss){ struct at76c503_tx_buffer *tx_buffer; struct ieee802_11_mgmt *mgmt; struct ieee802_11_assoc_req *req; u8 *tlv; assert(bss != NULL); tx_buffer = kmalloc(ASSOCREQ_MAX_SIZE + MAX_PADDING_SIZE, GFP_ATOMIC); if (!tx_buffer) return -ENOMEM; mgmt = (struct ieee802_11_mgmt *)&(tx_buffer->packet); req = (struct ieee802_11_assoc_req *)&(mgmt->data); tlv = req->data; /* make wireless header */ mgmt->frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT|IEEE802_11_STYPE_ASSOC_REQ); 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); /* we must set the Privacy bit in the capabilites to assure an Agere-based AP with optional WEP transmits encrypted frames to us. AP only set the Privacy bit in their capabilities if WEP is mandatory in the BSS! */ req->capability = cpu_to_le16(bss->capa | (dev->wep_enabled ? IEEE802_11_CAPA_PRIVACY : 0) | (dev->preamble_type == PREAMBLE_TYPE_SHORT ? IEEE802_11_CAPA_SHORT_PREAMBLE : 0)); req->listen_interval = cpu_to_le16(2 * bss->beacon_interval); /* write TLV data elements */ *tlv++ = IE_ID_SSID; *tlv++ = bss->ssid_len; memcpy(tlv, bss->ssid, bss->ssid_len); tlv += bss->ssid_len; *tlv++ = IE_ID_SUPPORTED_RATES; *tlv++ = sizeof(hw_rates); memcpy(tlv, hw_rates, sizeof(hw_rates)); tlv += sizeof(hw_rates); /* tlv points behind the supp_rates field */ /* init. at76c503 tx header */ tx_buffer->wlength = cpu_to_le16(tlv-(u8 *)mgmt); { /* output buffer for ssid and rates */ char ossid[IW_ESSID_MAX_SIZE+1] __attribute__ ((unused)); char orates[4*2+1] __attribute__ ((unused)); int len; tlv = req->data; len = min(sizeof(ossid)-1,(size_t)*(tlv+1)); memcpy(ossid, tlv+2, len); ossid[len] = '\0'; tlv += (1 + 1 + *(tlv+1)); /* points to IE of rates now */ dbg(DBG_TX_MGMT, "%s: AssocReq bssid %s capa x%04x ssid %s rates %s", dev->netdev->name, mac2str(mgmt->addr3), le16_to_cpu(req->capability), ossid, hex2str(orates,tlv+2,min((sizeof(orates)-1)/2,(size_t)*(tlv+1)), '\0')); } /* either send immediately (if no data tx is pending or put it in pending list */ return send_mgmt_bulk(dev, tx_buffer); } /* assoc_req *//* we are currently associated to curr_bss and want to reassoc to new_bss */staticint reassoc_req(struct at76c503 *dev, struct bss_info *curr_bss, struct bss_info *new_bss){ struct at76c503_tx_buffer *tx_buffer; struct ieee802_11_mgmt *mgmt; struct ieee802_11_reassoc_req *req; u8 *tlv; assert(curr_bss != NULL); assert(new_bss != NULL); if (curr_bss == NULL || new_bss == NULL) return -EFAULT; tx_buffer = kmalloc(REASSOCREQ_MAX_SIZE + MAX_PADDING_SIZE, GFP_ATOMIC); if (!tx_buffer) return -ENOMEM; mgmt = (struct ieee802_11_mgmt *)&(tx_buffer->packet); req = (struct ieee802_11_reassoc_req *)&(mgmt->data); tlv = req->data; /* make wireless header */ /* jal: encrypt this packet if wep_enabled is TRUE ??? */ mgmt->frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT|IEEE802_11_STYPE_REASSOC_REQ); mgmt->duration_id = cpu_to_le16(0x8000); memcpy(mgmt->addr1, new_bss->bssid, ETH_ALEN); memcpy(mgmt->addr2, dev->netdev->dev_addr, ETH_ALEN); memcpy(mgmt->addr3, new_bss->bssid, ETH_ALEN); mgmt->seq_ctl = cpu_to_le16(0); /* we must set the Privacy bit in the capabilites to assure an Agere-based AP with optional WEP transmits encrypted frames to us. AP only set the Privacy bit in their capabilities if WEP is mandatory in the BSS! */ req->capability = cpu_to_le16(new_bss->capa | (dev->wep_enabled ? IEEE802_11_CAPA_PRIVACY : 0) | (dev->preamble_type == PREAMBLE_TYPE_SHORT ? IEEE802_11_CAPA_SHORT_PREAMBLE : 0)); req->listen_interval = cpu_to_le16(2 * new_bss->beacon_interval); memcpy(req->curr_ap, curr_bss->bssid, ETH_ALEN); /* write TLV data elements */ *tlv++ = IE_ID_SSID; *tlv++ = new_bss->ssid_len; memcpy(tlv,new_bss->ssid, new_bss->ssid_len); tlv += new_bss->ssid_len; *tlv++ = IE_ID_SUPPORTED_RATES; *tlv++ = sizeof(hw_rates); memcpy(tlv, hw_rates, sizeof(hw_rates)); tlv += sizeof(hw_rates); /* tlv points behind the supp_rates field */ /* init. at76c503 tx header */ tx_buffer->wlength = cpu_to_le16(tlv-(u8 *)mgmt); { /* output buffer for ssid and rates */ char ossid[IW_ESSID_MAX_SIZE+1] __attribute__ ((unused)); char orates[4*2+1] __attribute__ ((unused)); char ocurr[6*3+1] __attribute__ ((unused)); tlv = req->data; memcpy(ossid, tlv+2, min(sizeof(ossid),(size_t)*(tlv+1))); ossid[sizeof(ossid)-1] = '\0'; tlv += (1 + 1 + *(tlv+1)); /* points to IE of rates now */ dbg(DBG_TX_MGMT, "%s: ReAssocReq curr %s new %s capa x%04x ssid %s rates %s", dev->netdev->name, hex2str(ocurr, req->curr_ap, ETH_ALEN, ':'), mac2str(mgmt->addr3), le16_to_cpu(req->capability), ossid, hex2str(orates,tlv+2,min((sizeof(orates)-1)/2,(size_t)*(tlv+1)), '\0')); } /* either send immediately (if no data tx is pending or put it in pending list */ return send_mgmt_bulk(dev, tx_buffer); } /* reassoc_req *//* shamelessly copied from usbnet.c (oku) */static void defer_kevent (struct at76c503 *dev, int flag){ set_bit (flag, &dev->kevent_flags); if (!schedule_task (&dev->kevent)) dbg(DBG_KEVENT, "%s: kevent %d may have been dropped", dev->netdev->name, flag); else dbg(DBG_KEVENT, "%s: kevent %d scheduled", dev->netdev->name, flag);}static voidkevent(void *data){ struct at76c503 *dev = data; int ret; unsigned long flags; /* on errors, bits aren't cleared, but no reschedule is done. So work will be done next time something else has to be done. This is ugly. TODO! (oku) */ dbg(DBG_KEVENT, "%s: kevent entry flags=x%x", dev->netdev->name, dev->kevent_flags); down(&dev->sem); if(test_bit(KEVENT_CTRL_HALT, &dev->kevent_flags)){ /* this never worked... but it seems that it's rarely necessary, if at all (oku) */ ret = usb_clear_halt(dev->udev, usb_sndctrlpipe (dev->udev, 0)); if(ret < 0) err("usb_clear_halt() failed: %d", ret); else{ clear_bit(KEVENT_CTRL_HALT, &dev->kevent_flags); info("usb_clear_halt() succesful"); } } if(test_bit(KEVENT_NEW_BSS, &dev->kevent_flags)){ struct net_device *netdev = dev->netdev; struct mib_mac_mgmt *mac_mgmt = kmalloc(sizeof(struct mib_mac_mgmt), GFP_KERNEL); struct set_mib_buffer mib_buf; ret = get_mib(dev->udev, MIB_MAC_MGMT, (u8*)mac_mgmt, sizeof(struct mib_mac_mgmt)); if(ret < 0){ err("%s: get_mib failed: %d", netdev->name, ret); goto new_bss_clean; } // usb_debug_data(__FUNCTION__, (unsigned char *)mac_mgmt, sizeof(struct mib_mac_mgmt)); dbg(DBG_PROGRESS, "ibss_change = 0x%2x", mac_mgmt->ibss_change);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -