isl_ioctl.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,270 行 · 第 1/5 页

C
2,270
字号
	struct mac_entry *entry;	struct list_head *ptr;	struct sockaddr *dst = (struct sockaddr *) extra;	dwrq->length = 0;	if (down_interruptible(&acl->sem))		return -ERESTARTSYS;	for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {		entry = list_entry(ptr, struct mac_entry, _list);		memcpy(dst->sa_data, entry->addr, ETH_ALEN);		dst->sa_family = ARPHRD_ETHER;		dwrq->length++;		dst++;	}	up(&acl->sem);	return 0;}/* Setting policy also clears the MAC acl, even if we don't change the defaut * policy */static intprism54_set_policy(struct net_device *ndev, struct iw_request_info *info,		   __u32 * uwrq, char *extra){	islpci_private *priv = netdev_priv(ndev);	struct islpci_acl *acl = &priv->acl;	u32 mlmeautolevel;	prism54_clear_mac(acl);	if ((*uwrq < MAC_POLICY_OPEN) || (*uwrq > MAC_POLICY_REJECT))		return -EINVAL;	down_write(&priv->mib_sem);	acl->policy = *uwrq;	/* the ACL code needs an intermediate mlmeautolevel */	if ((priv->iw_mode == IW_MODE_MASTER) &&	    (acl->policy != MAC_POLICY_OPEN))		mlmeautolevel = DOT11_MLME_INTERMEDIATE;	else		mlmeautolevel = CARD_DEFAULT_MLME_MODE;	if (priv->wpa)		mlmeautolevel = DOT11_MLME_EXTENDED;	mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);	/* restart the card with our new policy */	mgt_commit(priv);	up_write(&priv->mib_sem);	return 0;}static intprism54_get_policy(struct net_device *ndev, struct iw_request_info *info,		   __u32 * uwrq, char *extra){	islpci_private *priv = netdev_priv(ndev);	struct islpci_acl *acl = &priv->acl;	*uwrq = acl->policy;	return 0;}/* Return 1 only if client should be accepted. */static intprism54_mac_accept(struct islpci_acl *acl, char *mac){	struct list_head *ptr;	struct mac_entry *entry;	int res = 0;	if (down_interruptible(&acl->sem))		return -ERESTARTSYS;	if (acl->policy == MAC_POLICY_OPEN) {		up(&acl->sem);		return 1;	}	for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {		entry = list_entry(ptr, struct mac_entry, _list);		if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {			res = 1;			break;		}	}	res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res;	up(&acl->sem);	return res;}static intprism54_kick_all(struct net_device *ndev, struct iw_request_info *info,		 struct iw_point *dwrq, char *extra){	struct obj_mlme *mlme;	int rvalue;	mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL);	if (mlme == NULL)		return -ENOMEM;	/* Tell the card to kick every client */	mlme->id = 0;	rvalue =	    mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);	kfree(mlme);	return rvalue;}static intprism54_kick_mac(struct net_device *ndev, struct iw_request_info *info,		 struct sockaddr *awrq, char *extra){	struct obj_mlme *mlme;	struct sockaddr *addr = (struct sockaddr *) extra;	int rvalue;	if (addr->sa_family != ARPHRD_ETHER)		return -EOPNOTSUPP;	mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL);	if (mlme == NULL)		return -ENOMEM;	/* Tell the card to only kick the corresponding bastard */	memcpy(mlme->address, addr->sa_data, ETH_ALEN);	mlme->id = -1;	rvalue =	    mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);	kfree(mlme);	return rvalue;}/* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */static voidformat_event(islpci_private *priv, char *dest, const char *str,	     const struct obj_mlme *mlme, u16 *length, int error){	const u8 *a = mlme->address;	int n = snprintf(dest, IW_CUSTOM_MAX,			 "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s (%2.2X)",			 str,			 ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"),			 a[0], a[1], a[2], a[3], a[4], a[5],			 (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ")			  : ""), mlme->code);	BUG_ON(n > IW_CUSTOM_MAX);	*length = n;}static voidsend_formatted_event(islpci_private *priv, const char *str,		     const struct obj_mlme *mlme, int error){	union iwreq_data wrqu;	wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);	if (!wrqu.data.pointer)		return;	wrqu.data.length = 0;	format_event(priv, wrqu.data.pointer, str, mlme, &wrqu.data.length,		     error);	wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer);	kfree(wrqu.data.pointer);}static voidsend_simple_event(islpci_private *priv, const char *str){	union iwreq_data wrqu;	int n = strlen(str);	wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);	if (!wrqu.data.pointer)		return;	BUG_ON(n > IW_CUSTOM_MAX);	wrqu.data.length = n;	strcpy(wrqu.data.pointer, str);	wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer);	kfree(wrqu.data.pointer);}static voidlink_changed(struct net_device *ndev, u32 bitrate){	islpci_private *priv = netdev_priv(ndev);	if (bitrate) {		if (priv->iw_mode == IW_MODE_INFRA) {			union iwreq_data uwrq;			prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq,					NULL);			wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL);		} else			send_simple_event(netdev_priv(ndev),					  "Link established");	} else		send_simple_event(netdev_priv(ndev), "Link lost");}/* Beacon/ProbeResp payload header */struct ieee80211_beacon_phdr {	u8 timestamp[8];	u16 beacon_int;	u16 capab_info;} __attribute__ ((packed));#define WLAN_EID_GENERIC 0xddstatic u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"voidprism54_wpa_ie_add(islpci_private *priv, u8 *bssid,		   u8 *wpa_ie, size_t wpa_ie_len){	struct list_head *ptr;	struct islpci_bss_wpa_ie *bss = NULL;	if (wpa_ie_len > MAX_WPA_IE_LEN)		wpa_ie_len = MAX_WPA_IE_LEN;	if (down_interruptible(&priv->wpa_sem))		return;	/* try to use existing entry */	list_for_each(ptr, &priv->bss_wpa_list) {		bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);		if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) {			list_move(&bss->list, &priv->bss_wpa_list);			break;		}		bss = NULL;	}	if (bss == NULL) {		/* add a new BSS entry; if max number of entries is already		 * reached, replace the least recently updated */		if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) {			bss = list_entry(priv->bss_wpa_list.prev,					 struct islpci_bss_wpa_ie, list);			list_del(&bss->list);		} else {			bss = kmalloc(sizeof (*bss), GFP_ATOMIC);			if (bss != NULL) {				priv->num_bss_wpa++;				memset(bss, 0, sizeof (*bss));			}		}		if (bss != NULL) {			memcpy(bss->bssid, bssid, ETH_ALEN);			list_add(&bss->list, &priv->bss_wpa_list);		}	}	if (bss != NULL) {		memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len);		bss->wpa_ie_len = wpa_ie_len;		bss->last_update = jiffies;	} else {		printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR		       "\n", MAC2STR(bssid));	}	/* expire old entries from WPA list */	while (priv->num_bss_wpa > 0) {		bss = list_entry(priv->bss_wpa_list.prev,				 struct islpci_bss_wpa_ie, list);		if (!time_after(jiffies, bss->last_update + 60 * HZ))			break;		list_del(&bss->list);		priv->num_bss_wpa--;		kfree(bss);	}	up(&priv->wpa_sem);}size_tprism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie){	struct list_head *ptr;	struct islpci_bss_wpa_ie *bss = NULL;	size_t len = 0;	if (down_interruptible(&priv->wpa_sem))		return 0;	list_for_each(ptr, &priv->bss_wpa_list) {		bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);		if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0)			break;		bss = NULL;	}	if (bss) {		len = bss->wpa_ie_len;		memcpy(wpa_ie, bss->wpa_ie, len);	}	up(&priv->wpa_sem);	return len;}voidprism54_wpa_ie_init(islpci_private *priv){	INIT_LIST_HEAD(&priv->bss_wpa_list);	sema_init(&priv->wpa_sem, 1);}voidprism54_wpa_ie_clean(islpci_private *priv){	struct list_head *ptr, *n;	list_for_each_safe(ptr, n, &priv->bss_wpa_list) {		struct islpci_bss_wpa_ie *bss;		bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);		kfree(bss);	}}static voidprism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,			 u8 *payload, size_t len){	struct ieee80211_beacon_phdr *hdr;	u8 *pos, *end;	if (!priv->wpa)		return;	hdr = (struct ieee80211_beacon_phdr *) payload;	pos = (u8 *) (hdr + 1);	end = payload + len;	while (pos < end) {		if (pos + 2 + pos[1] > end) {			printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed "			       "for " MACSTR "\n", MAC2STR(addr));			return;		}		if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&		    memcmp(pos + 2, wpa_oid, 4) == 0) {			prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2);			return;		}		pos += 2 + pos[1];	}}static voidhandle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid){	if (((mlme->state == DOT11_STATE_AUTHING) ||	     (mlme->state == DOT11_STATE_ASSOCING))	    && mgt_mlme_answer(priv)) {		/* Someone is requesting auth and we must respond. Just send back		 * the trap with error code set accordingly.		 */		mlme->code = prism54_mac_accept(&priv->acl,						mlme->address) ? 0 : 1;		mgt_set_request(priv, oid, 0, mlme);	}}intprism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,			    char *data){	struct obj_mlme *mlme = (struct obj_mlme *) data;	size_t len;	u8 *payload, *pos = (u8 *) (mlme + 1);	len = pos[0] | (pos[1] << 8);	/* little endian data length */	payload = pos + 2;	/* I think all trapable objects are listed here.	 * Some oids have a EX version. The difference is that they are emitted	 * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL)	 * with more info.	 * The few events already defined by the wireless tools are not really	 * suited. We use the more flexible custom event facility.	 */	/* I fear prism54_process_bss_data won't work with big endian data */	if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE))		prism54_process_bss_data(priv, oid, mlme->address,					 payload, len);	mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme);	switch (oid) {	case GEN_OID_LINKSTATE:		link_changed(priv->ndev, (u32) *data);		break;	case DOT11_OID_MICFAILURE:		send_simple_event(priv, "Mic failure");		break;	case DOT11_OID_DEAUTHENTICATE:		send_formatted_event(priv, "DeAuthenticate request", mlme, 0);		break;	case DOT11_OID_AUTHENTICATE:		handle_request(priv, mlme, oid);		send_formatted_event(priv, "Authenticate request", mlme, 1);		break;	case DOT11_OID_DISASSOCIATE:		send_formatted_event(priv, "Disassociate request", mlme, 0);		break;	case DOT11_OID_ASSOCIATE:		handle_request(priv, mlme, oid);		send_formatted_event(priv, "Associate request", mlme, 1);		break;	case DOT11_OID_REASSOCIATE:		handle_request(priv, mlme, oid);		send_formatted_event(priv, "ReAssociate request", mlme, 1);		break;	case DOT11_OID_BEACON:		send_formatted_event(priv,				     "Received a beacon from an unkown AP",				     mlme, 0);		break;	case DOT11_OID_PROBE:		/* we received a probe from a client. */		send_formatted_event(priv, "Received a probe from client", mlme,				     0);		break;		/* Note : "mlme" is actually a "struct obj_mlmeex *" here, but this		 * is backward compatible layout-wise with "struct obj_mlme".

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?