📄 isl_ioctl.c
字号:
/* Note: currently, use hostapd ioctl from the Host AP driver for WPA * support. This is to be replaced with Linux wireless extensions once they * get WPA support. *//* Note II: please leave all this together as it will be easier to remove later, * once wireless extensions add WPA support -mcgrof *//* PRISM54_HOSTAPD ioctl() cmd: */enum { PRISM2_SET_ENCRYPTION = 6, PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12, PRISM2_HOSTAPD_MLME = 13, PRISM2_HOSTAPD_SCAN_REQ = 14,};#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12#define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25#define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))/* Maximum length for algorithm names (-1 for nul termination) * used in ioctl() */#define HOSTAP_CRYPT_ALG_NAME_LEN 16 struct prism2_hostapd_param { u32 cmd; u8 sta_addr[ETH_ALEN]; union { struct { u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN]; u32 flags; u32 err; u8 idx; u8 seq[8]; /* sequence counter (set: RX, get: TX) */ u16 key_len; u8 key[0]; } crypt; struct { u8 len; u8 data[0]; } generic_elem; struct {#define MLME_STA_DEAUTH 0#define MLME_STA_DISASSOC 1 u16 cmd; u16 reason_code; } mlme; struct { u8 ssid_len; u8 ssid[32]; } scan_req; } u;};static intprism2_ioctl_set_encryption(struct net_device *dev, struct prism2_hostapd_param *param, int param_len){ islpci_private *priv = netdev_priv(dev); int rvalue = 0, force = 0; int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; union oid_res_t r; /* with the new API, it's impossible to get a NULL pointer. * New version of iwconfig set the IW_ENCODE_NOKEY flag * when no key is given, but older versions don't. */ if (param->u.crypt.key_len > 0) { /* we have a key to set */ int index = param->u.crypt.idx; int current_index; struct obj_key key = { DOT11_PRIV_TKIP, 0, "" }; /* get the current key index */ rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); current_index = r.u; /* Verify that the key is not marked as invalid */ if (!(param->u.crypt.flags & IW_ENCODE_NOKEY)) { key.length = param->u.crypt.key_len > sizeof (param->u.crypt.key) ? sizeof (param->u.crypt.key) : param->u.crypt.key_len; memcpy(key.key, param->u.crypt.key, key.length); if (key.length == 32) /* we want WPA-PSK */ key.type = DOT11_PRIV_TKIP; if ((index < 0) || (index > 3)) /* no index provided use the current one */ index = current_index; /* now send the key to the card */ rvalue |= mgt_set_request(priv, DOT11_OID_DEFKEYX, index, &key); } /* * If a valid key is set, encryption should be enabled * (user may turn it off later). * This is also how "iwconfig ethX key on" works */ if ((index == current_index) && (key.length > 0)) force = 1; } else { int index = (param->u.crypt.flags & IW_ENCODE_INDEX) - 1; if ((index >= 0) && (index <= 3)) { /* we want to set the key index */ rvalue |= mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &index); } else { if (!param->u.crypt.flags & IW_ENCODE_MODE) { /* we cannot do anything. Complain. */ return -EINVAL; } } } /* now read the flags */ if (param->u.crypt.flags & IW_ENCODE_DISABLED) { /* Encoding disabled, * authen = DOT11_AUTH_OS; * invoke = 0; * exunencrypt = 0; */ } if (param->u.crypt.flags & IW_ENCODE_OPEN) /* Encode but accept non-encoded packets. No auth */ invoke = 1; if ((param->u.crypt.flags & IW_ENCODE_RESTRICTED) || force) { /* Refuse non-encoded packets. Auth */ authen = DOT11_AUTH_BOTH; invoke = 1; exunencrypt = 1; } /* do the change if requested */ if ((param->u.crypt.flags & IW_ENCODE_MODE) || force) { rvalue |= mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); rvalue |= mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke); rvalue |= mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &exunencrypt); } return rvalue;}static intprism2_ioctl_set_generic_element(struct net_device *ndev, struct prism2_hostapd_param *param, int param_len){ islpci_private *priv = netdev_priv(ndev); int max_len, len, alen, ret=0; struct obj_attachment *attach; len = param->u.generic_elem.len; max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN; if (max_len < 0 || max_len < len) return -EINVAL; alen = sizeof(*attach) + len; attach = kmalloc(alen, GFP_KERNEL); if (attach == NULL) return -ENOMEM; memset(attach, 0, alen);#define WLAN_FC_TYPE_MGMT 0#define WLAN_FC_STYPE_ASSOC_REQ 0#define WLAN_FC_STYPE_REASSOC_REQ 2 /* Note: endianness is covered by mgt_set_varlen */ attach->type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ASSOC_REQ << 4); attach->id = -1; attach->size = len; memcpy(attach->data, param->u.generic_elem.data, len); ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len); if (ret == 0) { attach->type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_REASSOC_REQ << 4); ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len); if (ret == 0) printk(KERN_DEBUG "%s: WPA IE Attachment was set\n", ndev->name); } kfree(attach); return ret;}static intprism2_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param){ return -EOPNOTSUPP;}static intprism2_ioctl_scan_req(struct net_device *ndev, struct prism2_hostapd_param *param){ islpci_private *priv = netdev_priv(ndev); int i, rvalue; struct obj_bsslist *bsslist; u32 noise = 0; char *extra = ""; char *current_ev = "foo"; union oid_res_t r; if (islpci_get_state(priv) < PRV_STATE_INIT) { /* device is not ready, fail gently */ return 0; } /* first get the noise value. We will use it to report the link quality */ rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); noise = r.u; /* Ask the device for a list of known bss. We can report at most * IW_MAX_AP=64 to the range struct. But the device won't repport anything * if you change the value of IWMAX_BSS=24. */ rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r); bsslist = r.ptr; /* ok now, scan the list and translate its info */ for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++) current_ev = prism54_translate_bss(ndev, current_ev, extra + IW_SCAN_MAX_DATA, &(bsslist->bsslist[i]), noise); kfree(bsslist); return rvalue;}static intprism54_hostapd(struct net_device *ndev, struct iw_point *p){ struct prism2_hostapd_param *param; int ret = 0; u32 uwrq; printk(KERN_DEBUG "prism54_hostapd - len=%d\n", p->length); if (p->length < sizeof(struct prism2_hostapd_param) || p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer) return -EINVAL; param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL); if (param == NULL) return -ENOMEM; if (copy_from_user(param, p->pointer, p->length)) { kfree(param); return -EFAULT; } switch (param->cmd) { case PRISM2_SET_ENCRYPTION: printk(KERN_DEBUG "%s: Caught WPA supplicant set encryption request\n", ndev->name); ret = prism2_ioctl_set_encryption(ndev, param, p->length); break; case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT: printk(KERN_DEBUG "%s: Caught WPA supplicant set WPA IE request\n", ndev->name); ret = prism2_ioctl_set_generic_element(ndev, param, p->length); break; case PRISM2_HOSTAPD_MLME: printk(KERN_DEBUG "%s: Caught WPA supplicant MLME request\n", ndev->name); ret = prism2_ioctl_mlme(ndev, param); break; case PRISM2_HOSTAPD_SCAN_REQ: printk(KERN_DEBUG "%s: Caught WPA supplicant scan request\n", ndev->name); ret = prism2_ioctl_scan_req(ndev, param); break; case PRISM54_SET_WPA: printk(KERN_DEBUG "%s: Caught WPA supplicant wpa init request\n", ndev->name); uwrq = 1; ret = prism54_set_wpa(ndev, NULL, &uwrq, NULL); break; case PRISM54_DROP_UNENCRYPTED: printk(KERN_DEBUG "%s: Caught WPA drop unencrypted request\n", ndev->name);#if 0 uwrq = 0x01; mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &uwrq); down_write(&priv->mib_sem); mgt_commit(priv); up_write(&priv->mib_sem);#endif /* Not necessary, as set_wpa does it, should we just do it here though? */ ret = 0; break; default: printk(KERN_DEBUG "%s: Caught a WPA supplicant request that is not supported\n", ndev->name); ret = -EOPNOTSUPP; break; } if (ret == 0 && copy_to_user(p->pointer, param, p->length)) ret = -EFAULT; kfree(param); return ret;}static intprism54_set_wpa(struct net_device *ndev, struct iw_request_info *info, __u32 * uwrq, char *extra){ islpci_private *priv = netdev_priv(ndev); u32 mlme, authen, dot1x, filter, wep; if (islpci_get_state(priv) < PRV_STATE_INIT) return 0; wep = 1; /* For privacy invoked */ filter = 1; /* Filter out all unencrypted frames */ dot1x = 0x01; /* To enable eap filter */ mlme = DOT11_MLME_EXTENDED; authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */ down_write(&priv->mib_sem); priv->wpa = *uwrq; switch (priv->wpa) { default: case 0: /* Clears/disables WPA and friends */ wep = 0; filter = 0; /* Do not filter un-encrypted data */ dot1x = 0; mlme = DOT11_MLME_AUTO; printk("%s: Disabling WPA\n", ndev->name); break; case 2: case 1: /* WPA */ printk("%s: Enabling WPA\n", ndev->name); break; } up_write(&priv->mib_sem); mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &wep); mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &filter); mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x); mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlme); return 0;}static intprism54_get_wpa(struct net_device *ndev, struct iw_request_info *info, __u32 * uwrq, char *extra){ islpci_private *priv = netdev_priv(ndev); *uwrq = priv->wpa; return 0;}static intprism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info, __u32 * uwrq, char *extra){ islpci_private *priv = netdev_priv(ndev); priv->monitor_type = (*uwrq ? ARPHRD_IEEE80211_PRISM : ARPHRD_IEEE80211); if (priv->iw_mode == IW_MODE_MONITOR) priv->ndev->type = priv->monitor_type; return 0;}static intprism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info, __u32 * uwrq, char *extra){ islpci_private *priv = netdev_priv(ndev); *uwrq = (priv->monitor_type == ARPHRD_IEEE80211_PRISM); return 0;}static intprism54_debug_oid(struct net_device *ndev, struct iw_request_info *info, __u32 * uwrq, char *extra){ islpci_private *priv = netdev_priv(ndev); priv->priv_oid = *uwrq; printk("%s: oid 0x%08X\n", ndev->name, *uwrq); return 0;}static intprism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info, struct iw_point *data, char *extra){ islpci_private *priv = netdev_priv(ndev); struct islpci_mgmtframe *response; int ret = -EIO; printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid); data->length = 0; if (islpci_get_state(priv) >= PRV_STATE_INIT) { ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, priv->priv_oid, extra, 256, &response); printk("%s: ret: %i\n", ndev->name, ret); if (ret || !response || response->header->operation == PIMFOR_OP_ERROR) { if (response) { islpci_mgt_release(response); } printk("%s: EIO\n", ndev->name); ret = -EIO; } if (!ret) { data->length = response->header->length; memcpy(extra, response->data, data->length); islpci_mgt_release(response); printk("%s: len: %i\n", ndev->name, data->length); } } return ret;}static intprism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info, struct iw_point *data, char *extra){ islpci_private *priv = netdev_priv(ndev); struct islpci_mgmtframe *response; int ret = 0, response_op = PIMFOR_OP_ERROR; printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid, data->length); if (islpci_get_state(priv) >= PRV_STATE_INIT) { ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, priv->priv_oid, extra, data->length, &response); printk("%s: ret: %i\n", ndev->name, ret); if (ret || !response || response->header->operation == PIMFOR_OP_ERROR) { if (response) { islpci_mgt_release(response); } printk("%s: EIO\n", ndev->name); ret = -EIO; } if (!ret) { response_op = response->header->operation; printk("%s: response_op: %i\n", ndev->name, response_op); islpci_mgt_release(response); } } return (ret ? ret : -EINPROGRESS);}static intprism54_set_spy(struct net_device *ndev, struct iw_request_info *info, union iwreq_data *uwrq, char *extra){ islpci_private *priv = netdev_priv(ndev); u32 u, oid = OID_INL_CONFIG; down_write(&priv->mib_sem); mgt_get(priv, OID_INL_CONFIG, &u); if ((uwrq->data.length == 0) && (priv->spy_data.spy_number > 0)) /* disable spy */ u &= ~INL_CONFIG_RXANNEX; else if ((uwrq->data.length > 0) && (priv->spy_data.spy_number == 0)) /* enable spy */ u |= INL_CONFIG_RXANNEX; mgt_set(priv, OID_INL_CONFIG, &u); mgt_commit_l
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -