⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wireless.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
			if (!netif_device_present(dev))				return -ENODEV;			/* New driver API : try to find the handler */			handler = get_handler(dev, cmd);			if(handler != NULL) {				/* Standard and private are not the same */				if(cmd < SIOCIWFIRSTPRIV)					return ioctl_standard_call(dev,								   ifr,								   cmd,								   handler);				else					return ioctl_private_call(dev,								  ifr,								  cmd,								  handler);			}			/* Old driver API : call driver ioctl handler */			if (dev->do_ioctl) {				return dev->do_ioctl(dev, ifr, cmd);			}			return -EOPNOTSUPP;	}	/* Not reached */	return -EINVAL;}/************************* EVENT PROCESSING *************************//* * Process events generated by the wireless layer or the driver. * Most often, the event will be propagated through rtnetlink */#ifdef WE_EVENT_NETLINK/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here. * It is declared in <linux/rtnetlink.h> *//* ---------------------------------------------------------------- *//* * Fill a rtnetlink message with our event data. * Note that we propage only the specified event and don't dump the * current wireless config. Dumping the wireless config is far too * expensive (for each parameter, the driver need to query the hardware). */static inline int rtnetlink_fill_iwinfo(struct sk_buff *	skb,					struct net_device *	dev,					int			type,					char *			event,					int			event_len){	struct ifinfomsg *r;	struct nlmsghdr  *nlh;	unsigned char	 *b = skb->tail;	nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));	r = NLMSG_DATA(nlh);	r->ifi_family = AF_UNSPEC;	r->ifi_type = dev->type;	r->ifi_index = dev->ifindex;	r->ifi_flags = dev->flags;	r->ifi_change = 0;	/* Wireless changes don't affect those flags */	/* Add the wireless events in the netlink packet */	RTA_PUT(skb, IFLA_WIRELESS,		event_len, event);	nlh->nlmsg_len = skb->tail - b;	return skb->len;nlmsg_failure:rtattr_failure:	skb_trim(skb, b - skb->data);	return -1;}/* ---------------------------------------------------------------- *//* * Create and broadcast and send it on the standard rtnetlink socket * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field * within a RTM_NEWLINK event. */static inline void rtmsg_iwinfo(struct net_device *	dev,				char *			event,				int			event_len){	struct sk_buff *skb;	int size = NLMSG_GOODSIZE;	skb = alloc_skb(size, GFP_ATOMIC);	if (!skb)		return;	if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,				  event, event_len) < 0) {		kfree_skb(skb);		return;	}	NETLINK_CB(skb).dst_groups = RTMGRP_LINK;	netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC);}#endif	/* WE_EVENT_NETLINK *//* ---------------------------------------------------------------- *//* * Main event dispatcher. Called from other parts and drivers. * Send the event on the appropriate channels. * May be called from interrupt context. */void wireless_send_event(struct net_device *	dev,			 unsigned int		cmd,			 union iwreq_data *	wrqu,			 char *			extra){	const struct iw_ioctl_description *	descr = NULL;	int extra_len = 0;	struct iw_event  *event;		/* Mallocated whole event */	int event_len;				/* Its size */	int hdr_len;				/* Size of the event header */	/* Don't "optimise" the following variable, it will crash */	unsigned	cmd_index;		/* *MUST* be unsigned */	/* Get the description of the IOCTL */	if(cmd <= SIOCIWLAST) {		cmd_index = cmd - SIOCIWFIRST;		if(cmd_index < standard_ioctl_num)			descr = &(standard_ioctl[cmd_index]);	} else {		cmd_index = cmd - IWEVFIRST;		if(cmd_index < standard_event_num)			descr = &(standard_event[cmd_index]);	}	/* Don't accept unknown events */	if(descr == NULL) {		/* Note : we don't return an error to the driver, because		 * the driver would not know what to do about it. It can't		 * return an error to the user, because the event is not		 * initiated by a user request.		 * The best the driver could do is to log an error message.		 * We will do it ourselves instead...		 */	  	printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",		       dev->name, cmd);		return;	}#ifdef WE_EVENT_DEBUG	printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n",	       dev->name, cmd);	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);#endif	/* WE_EVENT_DEBUG */	/* Check extra parameters and set extra_len */	if(descr->header_type == IW_HEADER_TYPE_POINT) {		/* Check if number of token fits within bounds */		if(wrqu->data.length > descr->max_tokens) {		  	printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);			return;		}		if(wrqu->data.length < descr->min_tokens) {		  	printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);			return;		}		/* Calculate extra_len - extra is NULL for restricted events */		if(extra != NULL)			extra_len = wrqu->data.length * descr->token_size;#ifdef WE_EVENT_DEBUG		printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len);#endif	/* WE_EVENT_DEBUG */	}	/* Total length of the event */	hdr_len = event_type_size[descr->header_type];	event_len = hdr_len + extra_len;#ifdef WE_EVENT_DEBUG	printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len);#endif	/* WE_EVENT_DEBUG */	/* Create temporary buffer to hold the event */	event = kmalloc(event_len, GFP_ATOMIC);	if(event == NULL)		return;	/* Fill event */	event->len = event_len;	event->cmd = cmd;	memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN);	if(extra != NULL)		memcpy(((char *) event) + hdr_len, extra, extra_len);#ifdef WE_EVENT_NETLINK	/* rtnetlink event channel */	rtmsg_iwinfo(dev, (char *) event, event_len);#endif	/* WE_EVENT_NETLINK */	/* Cleanup */	kfree(event);	return;		/* Always success, I guess ;-) */}/********************** ENHANCED IWSPY SUPPORT **********************//* * In the old days, the driver was handling spy support all by itself. * Now, the driver can delegate this task to Wireless Extensions. * It needs to use those standard spy iw_handler in struct iw_handler_def, * push data to us via wireless_spy_update() and include struct iw_spy_data * in its private part (and advertise it in iw_handler_def->spy_offset). * One of the main advantage of centralising spy support here is that * it becomes much easier to improve and extend it without having to touch * the drivers. One example is the addition of the Spy-Threshold events. * Note : IW_WIRELESS_SPY is defined in iw_handler.h *//*------------------------------------------------------------------*//* * Standard Wireless Handler : set Spy List */int iw_handler_set_spy(struct net_device *	dev,		       struct iw_request_info *	info,		       union iwreq_data *	wrqu,		       char *			extra){#ifdef IW_WIRELESS_SPY	struct iw_spy_data *	spydata = (dev->priv +					   dev->wireless_handlers->spy_offset);	struct sockaddr *	address = (struct sockaddr *) extra;	/* Disable spy collection while we copy the addresses.	 * As we don't disable interrupts, we need to do this to avoid races.	 * As we are the only writer, this is good enough. */	spydata->spy_number = 0;	/* Are there are addresses to copy? */	if(wrqu->data.length > 0) {		int i;		/* Copy addresses */		for(i = 0; i < wrqu->data.length; i++)			memcpy(spydata->spy_address[i], address[i].sa_data,			       ETH_ALEN);		/* Reset stats */		memset(spydata->spy_stat, 0,		       sizeof(struct iw_quality) * IW_MAX_SPY);#ifdef WE_SPY_DEBUG		printk(KERN_DEBUG "iw_handler_set_spy() :  offset %ld, spydata %p, num %d\n", dev->wireless_handlers->spy_offset, spydata, wrqu->data.length);		for (i = 0; i < wrqu->data.length; i++)			printk(KERN_DEBUG			       "%02X:%02X:%02X:%02X:%02X:%02X \n",			       spydata->spy_address[i][0],			       spydata->spy_address[i][1],			       spydata->spy_address[i][2],			       spydata->spy_address[i][3],			       spydata->spy_address[i][4],			       spydata->spy_address[i][5]);#endif	/* WE_SPY_DEBUG */	}	/* Enable addresses */	spydata->spy_number = wrqu->data.length;	return 0;#else /* IW_WIRELESS_SPY */	return -EOPNOTSUPP;#endif /* IW_WIRELESS_SPY */}/*------------------------------------------------------------------*//* * Standard Wireless Handler : get Spy List */int iw_handler_get_spy(struct net_device *	dev,		       struct iw_request_info *	info,		       union iwreq_data *	wrqu,		       char *			extra){#ifdef IW_WIRELESS_SPY	struct iw_spy_data *	spydata = (dev->priv +					   dev->wireless_handlers->spy_offset);	struct sockaddr *	address = (struct sockaddr *) extra;	int			i;	wrqu->data.length = spydata->spy_number;	/* Copy addresses. */	for(i = 0; i < spydata->spy_number; i++) 	{		memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);		address[i].sa_family = AF_UNIX;	}	/* Copy stats to the user buffer (just after). */	if(spydata->spy_number > 0)		memcpy(extra  + (sizeof(struct sockaddr) *spydata->spy_number),		       spydata->spy_stat,		       sizeof(struct iw_quality) * spydata->spy_number);	/* Reset updated flags. */	for(i = 0; i < spydata->spy_number; i++)		spydata->spy_stat[i].updated = 0;	return 0;#else /* IW_WIRELESS_SPY */	return -EOPNOTSUPP;#endif /* IW_WIRELESS_SPY */}/*------------------------------------------------------------------*//* * Standard Wireless Handler : set spy threshold */int iw_handler_set_thrspy(struct net_device *	dev,			  struct iw_request_info *info,			  union iwreq_data *	wrqu,			  char *		extra){#ifdef IW_WIRELESS_THRSPY	struct iw_spy_data *	spydata = (dev->priv +					   dev->wireless_handlers->spy_offset);	struct iw_thrspy *	threshold = (struct iw_thrspy *) extra;	/* Just do it */	memcpy(&(spydata->spy_thr_low), &(threshold->low),	       2 * sizeof(struct iw_quality));	/* Clear flag */	memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));#ifdef WE_SPY_DEBUG	printk(KERN_DEBUG "iw_handler_set_thrspy() :  low %d ; high %d\n", spydata->spy_thr_low.level, spydata->spy_thr_high.level);#endif	/* WE_SPY_DEBUG */	return 0;#else /* IW_WIRELESS_THRSPY */	return -EOPNOTSUPP;#endif /* IW_WIRELESS_THRSPY */}/*------------------------------------------------------------------*//* * Standard Wireless Handler : get spy threshold */int iw_handler_get_thrspy(struct net_device *	dev,			  struct iw_request_info *info,			  union iwreq_data *	wrqu,			  char *		extra){#ifdef IW_WIRELESS_THRSPY	struct iw_spy_data *	spydata = (dev->priv +					   dev->wireless_handlers->spy_offset);	struct iw_thrspy *	threshold = (struct iw_thrspy *) extra;	/* Just do it */	memcpy(&(threshold->low), &(spydata->spy_thr_low),	       2 * sizeof(struct iw_quality));	return 0;#else /* IW_WIRELESS_THRSPY */	return -EOPNOTSUPP;#endif /* IW_WIRELESS_THRSPY */}#ifdef IW_WIRELESS_THRSPY/*------------------------------------------------------------------*//* * Prepare and send a Spy Threshold event */static void iw_send_thrspy_event(struct net_device *	dev,				 struct iw_spy_data *	spydata,				 unsigned char *	address,				 struct iw_quality *	wstats){	union iwreq_data	wrqu;	struct iw_thrspy	threshold;	/* Init */	wrqu.data.length = 1;	wrqu.data.flags = 0;	/* Copy address */	memcpy(threshold.addr.sa_data, address, ETH_ALEN);	threshold.addr.sa_family = ARPHRD_ETHER;	/* Copy stats */	memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));	/* Copy also thresholds */	memcpy(&(threshold.low), &(spydata->spy_thr_low),	       2 * sizeof(struct iw_quality));#ifdef WE_SPY_DEBUG	printk(KERN_DEBUG "iw_send_thrspy_event() : address %02X:%02X:%02X:%02X:%02X:%02X, level %d, up = %d\n",	       threshold.addr.sa_data[0],	       threshold.addr.sa_data[1],	       threshold.addr.sa_data[2],	       threshold.addr.sa_data[3],	       threshold.addr.sa_data[4],	       threshold.addr.sa_data[5], threshold.qual.level);#endif	/* WE_SPY_DEBUG */	/* Send event to user space */	wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);}#endif /* IW_WIRELESS_THRSPY *//* ---------------------------------------------------------------- *//* * Call for the driver to update the spy data. * For now, the spy data is a simple array. As the size of the array is * small, this is good enough. If we wanted to support larger number of * spy addresses, we should use something more efficient... */void wireless_spy_update(struct net_device *	dev,			 unsigned char *	address,			 struct iw_quality *	wstats){#ifdef IW_WIRELESS_SPY	struct iw_spy_data *	spydata = (dev->priv +					   dev->wireless_handlers->spy_offset);	int			i;	int			match = -1;#ifdef WE_SPY_DEBUG	printk(KERN_DEBUG "wireless_spy_update() :  offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);#endif	/* WE_SPY_DEBUG */	/* Update all records that match */	for(i = 0; i < spydata->spy_number; i++)		if(!memcmp(address, spydata->spy_address[i], ETH_ALEN)) {			memcpy(&(spydata->spy_stat[i]), wstats,			       sizeof(struct iw_quality));			match = i;		}#ifdef IW_WIRELESS_THRSPY	/* Generate an event if we cross the spy threshold.	 * To avoid event storms, we have a simple hysteresis : we generate	 * event only when we go under the low threshold or above the	 * high threshold. */	if(match >= 0) {		if(spydata->spy_thr_under[match]) {			if(wstats->level > spydata->spy_thr_high.level) {				spydata->spy_thr_under[match] = 0;				iw_send_thrspy_event(dev, spydata,						     address, wstats);			}		} else {			if(wstats->level < spydata->spy_thr_low.level) {				spydata->spy_thr_under[match] = 1;				iw_send_thrspy_event(dev, spydata,						     address, wstats);			}		}	}#endif /* IW_WIRELESS_THRSPY */#endif /* IW_WIRELESS_SPY */}EXPORT_SYMBOL(iw_handler_get_spy);EXPORT_SYMBOL(iw_handler_get_thrspy);EXPORT_SYMBOL(iw_handler_set_spy);EXPORT_SYMBOL(iw_handler_set_thrspy);EXPORT_SYMBOL(wireless_send_event);EXPORT_SYMBOL(wireless_spy_update);

⌨️ 快捷键说明

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