📄 wl_iw.c
字号:
struct net_device *dev, struct iw_request_info *info, struct sockaddr *awrq, char *extra){ int error = -EINVAL; WL_TRACE(("%s: SIOCSIWAP\n", dev->name)); if (awrq->sa_family != ARPHRD_ETHER) { WL_ERROR(("Invalid Header...sa_family\n")); return -EINVAL; } /* Ignore "auto" or "off" */ if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) { scb_val_t scbval; WL_ASSOC(("disassociating \n")); bzero(&scbval, sizeof (scb_val_t)); dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); return 0; } WL_ASSOC(("Assoc to %s\n", bcm_ether_ntoa((struct ether_addr *)&(awrq->sa_data), eabuf))); /* Reassociate to the specified AP */ if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, awrq->sa_data, ETHER_ADDR_LEN))) { WL_ERROR(("Invalid ioctl data.\n")); return error; } return 0;}static intwl_iw_get_wap( struct net_device *dev, struct iw_request_info *info, struct sockaddr *awrq, char *extra){ WL_TRACE(("%s: SIOCGIWAP\n", dev->name)); awrq->sa_family = ARPHRD_ETHER; memset(awrq->sa_data, 0, ETHER_ADDR_LEN); /* Ignore error (may be down or disassociated) */ (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN); return 0;}#if WIRELESS_EXT > 17static intwl_iw_mlme( struct net_device *dev, struct iw_request_info *info, struct sockaddr *awrq, char *extra){ struct iw_mlme *mlme; scb_val_t scbval; int error = -EINVAL; WL_TRACE(("%s: SIOCSIWMLME\n", dev->name)); mlme = (struct iw_mlme *)extra; if (mlme == NULL) { WL_ERROR(("Invalid ioctl data.\n")); return error; } scbval.val = mlme->reason_code; bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN); if (mlme->cmd == IW_MLME_DISASSOC) error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)); else if (mlme->cmd == IW_MLME_DEAUTH) error = dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval, sizeof(scb_val_t)); else { WL_ERROR(("Invalid ioctl data.\n")); return error; } return error;}#endifstatic intwl_iw_get_aplist( struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra){ wl_scan_results_t *list; struct sockaddr *addr = (struct sockaddr *) extra; struct iw_quality qual[IW_MAX_AP]; wl_bss_info_t *bi = NULL; int error, i; WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name)); if (!extra) return -EINVAL; /* Get scan results (too large to put on the stack) */ list = kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); if (!list) return -ENOMEM; memset(list, 0, WLC_IOCTL_MAXLEN); list->buflen = WLC_IOCTL_MAXLEN; if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, WLC_IOCTL_MAXLEN))) { WL_ERROR(("%d: Scan results error %d\n", __LINE__, error)); kfree(list); return error; } ASSERT(list->version == WL_BSS_INFO_VERSION); for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) { bi = bi ? (wl_bss_info_t *)((unsigned) bi + bi->length) : list->bss_info; ASSERT(((unsigned) bi + bi->length) <= ((unsigned) list + WLC_IOCTL_MAXLEN)); /* Infrastructure only */ if (!(bi->capability & DOT11_CAP_ESS)) continue; /* BSSID */ memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN); addr[dwrq->length].sa_family = ARPHRD_ETHER; qual[dwrq->length].qual = rssi_to_qual(bi->RSSI); qual[dwrq->length].level = 0x100 + bi->RSSI; qual[dwrq->length].noise = 0x100 + bi->phy_noise; /* Updated qual, level, and noise */ qual[dwrq->length].updated = 7; dwrq->length++; } kfree(list); if (dwrq->length) { memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length); /* Provided qual */ dwrq->flags = 1; } return 0;}#if WIRELESS_EXT > 13static intwl_iw_set_scan( struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra){ wlc_ssid_t ssid; WL_TRACE(("%s: SIOCSIWSCAN\n", dev->name)); /* Broadcast scan */ ssid.SSID_len = 0; /* Ignore error (most likely scan in progress) */ (void) dev_wlc_ioctl(dev, WLC_SCAN, &ssid, sizeof(ssid)); return 0;}#if WIRELESS_EXT > 17static boolie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len){/* Is this body of this tlvs entry a WPA entry? If *//* not update the tlvs buffer pointer/length */ uint8 *ie = *wpaie; /* If the contents match the WPA_OUI and type=1 */ if ((ie[1] >= 6) && !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) { return TRUE; } /* point to the next ie */ ie += ie[1] + 2; /* calculate the length of the rest of the buffer */ *tlvs_len -= (int)ie - (int)*tlvs; /* update the pointer to the start of the buffer */ *tlvs = ie; return FALSE;}#endifstatic intwl_iw_get_scan( struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra){ wl_scan_results_t *list; struct iw_event iwe; wl_bss_info_t *bi = NULL; int error, i, j; char *event = extra, *end = extra + IW_SCAN_MAX_DATA, *value; WL_TRACE(("%s: SIOCGIWSCAN\n", dev->name)); if (!extra) return -EINVAL; /* Get scan results (too large to put on the stack) */ list = kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); if (!list) return -ENOMEM; memset(list, 0, WLC_IOCTL_MAXLEN); list->buflen = WLC_IOCTL_MAXLEN; if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, WLC_IOCTL_MAXLEN))) { kfree(list); return error; } ASSERT(list->version == WL_BSS_INFO_VERSION); for (i = 0; i < list->count && i < IW_MAX_AP; i++) { bi = bi ? (wl_bss_info_t *)((unsigned) bi + bi->length) : list->bss_info; ASSERT(((unsigned) bi + bi->length) <= ((unsigned) list + WLC_IOCTL_MAXLEN)); /* First entry must be the BSSID */ iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN); event = iwe_stream_add_event(event, end, &iwe, IW_EV_ADDR_LEN); /* SSID */ iwe.u.data.length = bi->SSID_len; iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; event = iwe_stream_add_point(event, end, &iwe, bi->SSID); /* Mode */ if (bi->capability & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) { iwe.cmd = SIOCGIWMODE; if (bi->capability & DOT11_CAP_ESS) iwe.u.mode = IW_MODE_INFRA; else iwe.u.mode = IW_MODE_ADHOC; event = iwe_stream_add_event(event, end, &iwe, IW_EV_UINT_LEN); } /* Channel */ iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = bi->channel; iwe.u.freq.e = 0; event = iwe_stream_add_event(event, end, &iwe, IW_EV_FREQ_LEN); /* Channel quality */ iwe.cmd = IWEVQUAL; iwe.u.qual.qual = rssi_to_qual(bi->RSSI); iwe.u.qual.level = 0x100 + bi->RSSI; iwe.u.qual.noise = 0x100 + bi->phy_noise; event = iwe_stream_add_event(event, end, &iwe, IW_EV_QUAL_LEN);#if WIRELESS_EXT > 17 /* wpa_ie */ if (bi->ie_length) { /* look for wpa/rsn ies in the ie list... */ bcm_tlv_t *ie; uint8*ptr= ((uint8 *)bi) + sizeof(wl_bss_info_t); int ptr_len = bi->ie_length;#ifdef BCMWPA2 if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID))) { iwe.cmd = IWEVGENIE; iwe.u.data.length = ie->len + 2; event = iwe_stream_add_point(event, end, &iwe, (char *)ie); } ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);#endif /* BCMWPA2 */ while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) { if (ie_is_wpa_ie(((uint8 **)&ie), &ptr, &ptr_len)) { iwe.cmd = IWEVGENIE; iwe.u.data.length = ie->len + 2; event = iwe_stream_add_point(event, end, &iwe, (char *)ie); goto done; } } }done:#endif /* Encryption */ iwe.cmd = SIOCGIWENCODE; if (bi->capability & DOT11_CAP_PRIVACY) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; event = iwe_stream_add_point(event, end, &iwe, (char *)event); /* Rates */ if (bi->rateset.count) { value = event + IW_EV_LCP_LEN; iwe.cmd = SIOCGIWRATE; /* Those two flags are ignored... */ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) { iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000; value = iwe_stream_add_value(event, value, end, &iwe, IW_EV_PARAM_LEN); } event = value; } } kfree(list); dwrq->length = event - extra; dwrq->flags = 0; /* todo */ return 0;}#endif /* WIRELESS_EXT > 13 */static intwl_iw_set_essid( struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra){ wlc_ssid_t ssid; int error; WL_TRACE(("%s: SIOCSIWESSID\n", dev->name)); if (dwrq->length && extra) { ssid.SSID_len = MIN(sizeof(ssid.SSID), dwrq->length - 1); memcpy(ssid.SSID, extra, ssid.SSID_len); } else { /* Broadcast SSID */ ssid.SSID_len = 0; } if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid)))) return error; return 0;}static intwl_iw_get_essid( struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra){ wlc_ssid_t ssid; int error; WL_TRACE(("%s: SIOCGIWESSID\n", dev->name)); if (!extra) return -EINVAL; if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) { WL_ERROR(("Error getting the SSID\n")); return error; } /* Get the current SSID */ memcpy(extra, ssid.SSID, ssid.SSID_len); extra[ssid.SSID_len] = '\0'; dwrq->length = ssid.SSID_len ; dwrq->flags = 1; /* active */ return 0;}static intwl_iw_set_nick( struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra){ wl_iw_t *iw = dev->priv; WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name)); if (!extra) return -EINVAL; /* Check the size of the string */ if (dwrq->length > sizeof(iw->nickname)) return -E2BIG; memcpy(iw->nickname, extra, dwrq->length); iw->nickname[dwrq->length - 1] = '\0'; return 0;}static intwl_iw_get_nick( struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra){ wl_iw_t *iw = dev->priv; WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name)); if (!extra) return -EINVAL; strcpy(extra, iw->nickname); dwrq->length = strlen(extra) + 1; return 0;}static int wl_iw_set_rate( struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra){ wl_rateset_t rateset; int error, rate, i, error_bg, error_a; WL_TRACE(("%s: SIOCSIWRITE\n", dev->name)); /* Get current rateset */ if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) return error; if (vwrq->value < 0) { /* Select maximum rate */ rate = rateset.rates[rateset.count - 1] & 0x7f; } else if (vwrq->value < rateset.count) { /* Select rate by rateset index */ rate = rateset.rates[vwrq->value] & 0x7f; } else { /* Specified rate in bps */ rate = vwrq->value / 500000; } if (vwrq->fixed) { /* Set rate override, Since the is a/b/g-blind, both a/bg_rate are enforced. */ error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate); error_a = dev_wlc_intvar_set(dev, "a_rate", rate); if (error_bg && error_a) return (error_bg | error_a); } else { /* clear rate override Since the is a/b/g-blind, both a/bg_rate are enforced. */ /* 0 is for clearing rate override */ error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0); /* 0 is for clearing rate override */ error_a = dev_wlc_intvar_set(dev, "a_rate", 0); if (error_bg && error_a) return (error_bg | error_a); /* Remove rates above selected rate */ for (i = 0; i < rateset.count; i++) if ((rateset.rates[i] & 0x7f) > rate) break; rateset.count = i; /* Set current rateset */ if ((error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset, sizeof(rateset)))) return error; } return 0;}static int wl_iw_get_rate( struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra){ int error, rate; WL_TRACE(("%s: SIOCGIWRATE\n", dev->name)); /* Report the current tx rate */ if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate)))) return error; vwrq->value = (rate & 0x7f) * 500000; return 0;}static intwl_iw_set_rts( struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra){ int error, rts; WL_TRACE(("%s: SIOCSIWRTS\n", dev->name)); if (vwrq->disabled)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -