📄 wl_iw.c
字号:
/* * Linux Wireless Extensions support * * Copyright 2005-2006, Broadcom Corporation * All Rights Reserved. * * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. * $Id$ */#include <linux/if_arp.h>#include <asm/uaccess.h>#include <wlc_cfg.h>#include <typedefs.h>#include <linux/module.h>#include <osl.h>#include <bcmutils.h>#include <proto/ethernet.h>#include <proto/802.11.h>typedef void wlc_info_t;typedef void wl_info_t;typedef const struct sb_pub sb_t;#include <wlioctl.h>#include <wlc_pub.h>#include <wl_dbg.h>#include <wl_iw.h>static intdev_wlc_ioctl( struct net_device *dev, int cmd, void *arg, int len){ struct ifreq ifr; wl_ioctl_t ioc; mm_segment_t fs; int ret; ioc.cmd = cmd; ioc.buf = arg; ioc.len = len; strcpy(ifr.ifr_name, dev->name); ifr.ifr_data = (caddr_t) &ioc; /* Must be up for virtually all useful ioctls */ dev_open(dev); fs = get_fs(); set_fs(get_ds()); ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE); set_fs(fs); return ret;}/*set named driver variable to int value and return error indicationcalling example: dev_wlc_intvar_set(dev, "arate", rate)*/static intdev_wlc_intvar_set( struct net_device *dev, char *name, int val){ char buf[WLC_IOCTL_SMLEN]; uint len; len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf)); ASSERT(len); return (dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len));}#if WIRELESS_EXT > 17static intdev_wlc_bufvar_set( struct net_device *dev, char *name, char *buf, int len){ char ioctlbuf[WLC_IOCTL_SMLEN]; uint buflen; buflen = bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf)); ASSERT(buflen); return (dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen));}/*get named driver variable to int value and return error indicationcalling example: dev_wlc_intvar_get(dev, "arate", &rate)*/static intdev_wlc_bufvar_get( struct net_device *dev, char *name, char *buf, int buflen){ char ioctlbuf[WLC_IOCTL_SMLEN]; int error; uint len; len = bcm_mkiovar(name, NULL, 0, ioctlbuf, sizeof(ioctlbuf)); ASSERT(len); error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf, len); bcopy(ioctlbuf, buf, buflen); return (error);}#endif/*get named driver variable to int value and return error indicationcalling example: dev_wlc_intvar_get(dev, "arate", &rate)*/static intdev_wlc_intvar_get( struct net_device *dev, char *name, int *retval){ union { char buf[WLC_IOCTL_SMLEN]; int val; } var; int error; uint len; uint data_null; len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf)); ASSERT(len); error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len); *retval = var.val; return (error);}/* Maintain backward compatibility */#if WIRELESS_EXT < 13struct iw_request_info{ __u16 cmd; /* Wireless Extension command */ __u16 flags; /* More to come ;-) */};typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, void *wrqu, char *extra);#endif /* WIRELESS_EXT < 13 */static intwl_iw_config_commit( struct net_device *dev, struct iw_request_info *info, void *zwrq, char *extra){ wlc_ssid_t ssid; int error; struct sockaddr bssid; WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev->name)); if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) return error; if (!ssid.SSID_len) return 0; bzero(&bssid, sizeof(struct sockaddr)); if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN))) { WL_ERROR(("Invalid ioctl data.\n")); return error; } return 0;}static intwl_iw_get_name( struct net_device *dev, struct iw_request_info *info, char *cwrq, char *extra){ WL_TRACE(("%s: SIOCGIWNAME\n", dev->name)); strcpy(cwrq, "IEEE 802.11-DS"); return 0;}static intwl_iw_set_freq( struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra){ int error, chan; WL_TRACE(("%s: SIOCSIWFREQ\n", dev->name)); /* Setting by channel number */ if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) { chan = fwrq->m; } /* Setting by frequency */ else { /* Convert to MHz as best we can */ if (fwrq->e >= 6) { fwrq->e -= 6; while (fwrq->e--) fwrq->m *= 10; } else if (fwrq->e < 6) { while (fwrq->e++ < 6) fwrq->m /= 10; } chan = wlc_freq2channel(fwrq->m); } if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan)))) return error; /* -EINPROGRESS: Call commit handler */ return -EINPROGRESS;}static intwl_iw_get_freq( struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra){ channel_info_t ci; int error; WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name)); if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci)))) return error; /* Return radio channel in channel form */ fwrq->m = ci.hw_channel; fwrq->e = 0; return 0;}static intwl_iw_set_mode( struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra){ int infra = 0, ap = 0, error = 0; WL_TRACE(("%s: SIOCSIWMODE\n", dev->name)); switch (*uwrq) { case IW_MODE_MASTER: infra = ap = 1; break; case IW_MODE_ADHOC: case IW_MODE_AUTO: break; case IW_MODE_INFRA: infra = 1; break; default: return -EINVAL; } if ((error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra)))) return error; /* -EINPROGRESS: Call commit handler */ return -EINPROGRESS;}static intwl_iw_get_mode( struct net_device *dev, struct iw_request_info *info, __u32 *uwrq, char *extra){ int error, infra = 0, ap = 0; WL_TRACE(("%s: SIOCGIWMODE\n", dev->name)); if ((error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra))) || (error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap)))) return error; *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC; return 0;}static intwl_iw_get_range( struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra){ struct iw_range *range = (struct iw_range *) extra; int channels[MAXCHANNEL]; wl_uint32_list_t *list = (wl_uint32_list_t *) channels; wl_rateset_t rateset; int error, i; WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name)); if (!extra) return -EINVAL; dwrq->length = sizeof(struct iw_range); memset(range, 0, sizeof(range)); /* We don't use nwids */ range->min_nwid = range->max_nwid = 0; /* Set available channels/frequencies */ list->count = MAXCHANNEL; if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, sizeof(channels)))) return error; for (i = 0; i < list->count && i < IW_MAX_FREQUENCIES; i++) { range->freq[i].i = list->element[i]; range->freq[i].m = wlc_channel2freq(list->element[i]); range->freq[i].e = 6; } range->num_frequency = range->num_channels = i; /* Link quality (use NDIS cutoffs) */ range->max_qual.qual = 5; /* Signal level (use RSSI) */ range->max_qual.level = 0x100 - 200; /* -200 dBm */ /* Noise level (use noise) */ range->max_qual.noise = 0x100 - 200; /* -200 dBm */ /* Signal level threshold range (?) */ range->sensitivity = 65535;#if WIRELESS_EXT > 11 /* Link quality (use NDIS cutoffs) */ range->avg_qual.qual = 3; /* Signal level (use RSSI) */ range->avg_qual.level = 0x100 + WLC_RSSI_GOOD; /* Noise level (use noise) */ range->avg_qual.noise = 0x100 - 75; /* -75 dBm */#endif /* WIRELESS_EXT > 11 */ /* Set available bitrates */ if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) return error; range->num_bitrates = rateset.count; for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++) range->bitrate[i] = (rateset.rates[i] & 0x7f) * 500000; /* convert to bps */ /* Set an indication of the max TCP throughput * in bit/s that we can expect using this interface. * May be use for QoS stuff... Jean II */ if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) return error; if (i == PHY_TYPE_A) range->throughput = 24000000; /* 24 Mbits/s */ else range->throughput = 1500000; /* 1.5 Mbits/s */ /* RTS and fragmentation thresholds */ range->min_rts = 0; range->max_rts = 2347; range->min_frag = 256; range->max_frag = 2346; range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS; range->num_encoding_sizes = 4; range->encoding_size[0] = WEP1_KEY_SIZE; range->encoding_size[1] = WEP128_KEY_SIZE;#if WIRELESS_EXT > 17 range->encoding_size[2] = TKIP_KEY_SIZE;#else range->encoding_size[2] = 0;#endif range->encoding_size[3] = AES_KEY_SIZE; /* Do not support power micro-management */ range->min_pmp = 0; range->max_pmp = 0; range->min_pmt = 0; range->max_pmt = 0; range->pmp_flags = 0; range->pm_capa = 0; /* Transmit Power - values are in mW */ range->num_txpower = 2; range->txpower[0] = 1; range->txpower[1] = 255; range->txpower_capa = IW_TXPOW_MWATT;#if WIRELESS_EXT > 10 range->we_version_compiled = WIRELESS_EXT; range->we_version_source = 18; /* Only support retry limits */ range->retry_capa = IW_RETRY_LIMIT; range->retry_flags = IW_RETRY_LIMIT; range->r_time_flags = 0; /* SRL and LRL limits */ range->min_retry = 1; range->max_retry = 255; /* Retry lifetime limits unsupported */ range->min_r_time = 0; range->max_r_time = 0;#endif /* WIRELESS_EXT > 10 */#if WIRELESS_EXT > 17 range->enc_capa = IW_ENC_CAPA_WPA; range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP; range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;#ifdef BCMWPA2 range->enc_capa |= IW_ENC_CAPA_WPA2;#endif#endif /* WIRELESS_EXT > 17 */ return 0;}static intrssi_to_qual(int rssi){ if (rssi <= WLC_RSSI_NO_SIGNAL) return 0; else if (rssi <= WLC_RSSI_VERY_LOW) return 1; else if (rssi <= WLC_RSSI_LOW) return 2; else if (rssi <= WLC_RSSI_GOOD) return 3; else if (rssi <= WLC_RSSI_VERY_GOOD) return 4; else return 5;}static intwl_iw_set_spy( struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra){ wl_iw_t *iw = dev->priv; struct sockaddr *addr = (struct sockaddr *) extra; int i; WL_TRACE(("%s: SIOCSIWSPY\n", dev->name)); if (!extra) return -EINVAL; iw->spy_num = MIN(ARRAYSIZE(iw->spy_addr), dwrq->length); for (i = 0; i < iw->spy_num; i++) memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN); memset(iw->spy_qual, 0, sizeof(iw->spy_qual)); return 0;}static intwl_iw_get_spy( struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra){ wl_iw_t *iw = dev->priv; struct sockaddr *addr = (struct sockaddr *) extra; struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num]; int i; WL_TRACE(("%s: SIOCGIWSPY\n", dev->name)); if (!extra) return -EINVAL; dwrq->length = iw->spy_num; for (i = 0; i < iw->spy_num; i++) { memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN); addr[i].sa_family = AF_UNIX; memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality)); iw->spy_qual[i].updated = 0; } return 0;}static intwl_iw_set_wap(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -