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

📄 dev.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 *	Called from the PROCfs module. This now uses the new arbitrary sized /proc/net interface *	to create /proc/net/dev */ static int dev_get_info(char *buffer, char **start, off_t offset, int length){	int len = 0;	off_t begin = 0;	off_t pos = 0;	int size;	struct net_device *dev;	size = sprintf(buffer, 		"Inter-|   Receive                                                |  Transmit\n"		" face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed\n");		pos += size;	len += size;		read_lock(&dev_base_lock);	for (dev = dev_base; dev != NULL; dev = dev->next) {		size = sprintf_stats(buffer+len, dev);		len += size;		pos = begin + len;						if (pos < offset) {			len = 0;			begin = pos;		}		if (pos > offset + length)			break;	}	read_unlock(&dev_base_lock);	*start = buffer + (offset - begin);	/* Start of wanted data */	len -= (offset - begin);		/* Start slop */	if (len > length)		len = length;			/* Ending slop */	if (len < 0)		len = 0;	return len;}static int dev_proc_stats(char *buffer, char **start, off_t offset,			  int length, int *eof, void *data){	int i, lcpu;	int len=0;	for (lcpu=0; lcpu<smp_num_cpus; lcpu++) {		i = cpu_logical_map(lcpu);		len += sprintf(buffer+len, "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n",			       netdev_rx_stat[i].total,			       netdev_rx_stat[i].dropped,			       netdev_rx_stat[i].time_squeeze,			       netdev_rx_stat[i].throttled,			       netdev_rx_stat[i].fastroute_hit,			       netdev_rx_stat[i].fastroute_success,			       netdev_rx_stat[i].fastroute_defer,			       netdev_rx_stat[i].fastroute_deferred_out,#if 0			       netdev_rx_stat[i].fastroute_latency_reduction#else			       netdev_rx_stat[i].cpu_collision#endif			       );	}	len -= offset;	if (len > length)		len = length;	if (len < 0)		len = 0;	*start = buffer + offset;	*eof = 1;	return len;}#endif	/* CONFIG_PROC_FS */#ifdef WIRELESS_EXT#ifdef CONFIG_PROC_FS/* * Print one entry of /proc/net/wireless * This is a clone of /proc/net/dev (just above) */static int sprintf_wireless_stats(char *buffer, struct net_device *dev){	/* Get stats from the driver */	struct iw_statistics *stats = (dev->get_wireless_stats ?				       dev->get_wireless_stats(dev) :				       (struct iw_statistics *) NULL);	int size;	if (stats != (struct iw_statistics *) NULL) {		size = sprintf(buffer,			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d\n",			       dev->name,			       stats->status,			       stats->qual.qual,			       stats->qual.updated & 1 ? '.' : ' ',			       stats->qual.level,			       stats->qual.updated & 2 ? '.' : ' ',			       stats->qual.noise,			       stats->qual.updated & 4 ? '.' : ' ',			       stats->discard.nwid,			       stats->discard.code,			       stats->discard.misc);		stats->qual.updated = 0;	}	else		size = 0;	return size;}/* * Print info for /proc/net/wireless (print all entries) * This is a clone of /proc/net/dev (just above) */static int dev_get_wireless_info(char * buffer, char **start, off_t offset,			  int length){	int		len = 0;	off_t		begin = 0;	off_t		pos = 0;	int		size;		struct net_device *	dev;	size = sprintf(buffer,		       "Inter-| sta-|   Quality        |   Discarded packets\n"		       " face | tus | link level noise |  nwid  crypt   misc\n"			);		pos += size;	len += size;	read_lock(&dev_base_lock);	for (dev = dev_base; dev != NULL; dev = dev->next) {		size = sprintf_wireless_stats(buffer + len, dev);		len += size;		pos = begin + len;		if (pos < offset) {			len = 0;			begin = pos;		}		if (pos > offset + length)			break;	}	read_unlock(&dev_base_lock);	*start = buffer + (offset - begin);	/* Start of wanted data */	len -= (offset - begin);		/* Start slop */	if (len > length)		len = length;			/* Ending slop */	if (len < 0)		len = 0;	return len;}#endif	/* CONFIG_PROC_FS */#endif	/* WIRELESS_EXT *//** *	netdev_set_master	-	set up master/slave pair *	@slave: slave device *	@master: new master device * *	Changes the master device of the slave. Pass %NULL to break the *	bonding. The caller must hold the RTNL semaphore. On a failure *	a negative errno code is returned. On success the reference counts *	are adjusted, %RTM_NEWLINK is sent to the routing socket and the *	function returns zero. */ int netdev_set_master(struct net_device *slave, struct net_device *master){	struct net_device *old = slave->master;	ASSERT_RTNL();	if (master) {		if (old)			return -EBUSY;		dev_hold(master);	}	br_write_lock_bh(BR_NETPROTO_LOCK);	slave->master = master;	br_write_unlock_bh(BR_NETPROTO_LOCK);	if (old)		dev_put(old);	if (master)		slave->flags |= IFF_SLAVE;	else		slave->flags &= ~IFF_SLAVE;	rtmsg_ifinfo(RTM_NEWLINK, slave, IFF_SLAVE);	return 0;}/** *	dev_set_promiscuity	- update promiscuity count on a device *	@dev: device *	@inc: modifier * *	Add or remove promsicuity from a device. While the count in the device *	remains above zero the interface remains promiscuous. Once it hits zero *	the device reverts back to normal filtering operation. A negative inc *	value is used to drop promiscuity on the device. */ void dev_set_promiscuity(struct net_device *dev, int inc){	unsigned short old_flags = dev->flags;	dev->flags |= IFF_PROMISC;	if ((dev->promiscuity += inc) == 0)		dev->flags &= ~IFF_PROMISC;	if (dev->flags^old_flags) {#ifdef CONFIG_NET_FASTROUTE		if (dev->flags&IFF_PROMISC) {			netdev_fastroute_obstacles++;			dev_clear_fastroute(dev);		} else			netdev_fastroute_obstacles--;#endif		dev_mc_upload(dev);		printk(KERN_INFO "device %s %s promiscuous mode\n",		       dev->name, (dev->flags&IFF_PROMISC) ? "entered" : "left");	}}/** *	dev_set_allmulti	- update allmulti count on a device *	@dev: device *	@inc: modifier * *	Add or remove reception of all multicast frames to a device. While the *	count in the device remains above zero the interface remains listening *	to all interfaces. Once it hits zero the device reverts back to normal *	filtering operation. A negative @inc value is used to drop the counter *	when releasing a resource needing all multicasts. */void dev_set_allmulti(struct net_device *dev, int inc){	unsigned short old_flags = dev->flags;	dev->flags |= IFF_ALLMULTI;	if ((dev->allmulti += inc) == 0)		dev->flags &= ~IFF_ALLMULTI;	if (dev->flags^old_flags)		dev_mc_upload(dev);}int dev_change_flags(struct net_device *dev, unsigned flags){	int ret;	int old_flags = dev->flags;	/*	 *	Set the flags on our device.	 */	dev->flags = (flags & (IFF_DEBUG|IFF_NOTRAILERS|IFF_NOARP|IFF_DYNAMIC|			       IFF_MULTICAST|IFF_PORTSEL|IFF_AUTOMEDIA)) |				       (dev->flags & (IFF_UP|IFF_VOLATILE|IFF_PROMISC|IFF_ALLMULTI));	/*	 *	Load in the correct multicast list now the flags have changed.	 */					dev_mc_upload(dev);	/*	 *	Have we downed the interface. We handle IFF_UP ourselves	 *	according to user attempts to set it, rather than blindly	 *	setting it.	 */	ret = 0;	if ((old_flags^flags)&IFF_UP)	/* Bit is different  ? */	{		ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev);		if (ret == 0) 			dev_mc_upload(dev);	}	if (dev->flags&IFF_UP &&	    ((old_flags^dev->flags)&~(IFF_UP|IFF_PROMISC|IFF_ALLMULTI|IFF_VOLATILE)))		notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);	if ((flags^dev->gflags)&IFF_PROMISC) {		int inc = (flags&IFF_PROMISC) ? +1 : -1;		dev->gflags ^= IFF_PROMISC;		dev_set_promiscuity(dev, inc);	}	/* NOTE: order of synchronization of IFF_PROMISC and IFF_ALLMULTI	   is important. Some (broken) drivers set IFF_PROMISC, when	   IFF_ALLMULTI is requested not asking us and not reporting.	 */	if ((flags^dev->gflags)&IFF_ALLMULTI) {		int inc = (flags&IFF_ALLMULTI) ? +1 : -1;		dev->gflags ^= IFF_ALLMULTI;		dev_set_allmulti(dev, inc);	}	if (old_flags^dev->flags)		rtmsg_ifinfo(RTM_NEWLINK, dev, old_flags^dev->flags);	return ret;}/* *	Perform the SIOCxIFxxx calls.  */ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd){	struct net_device *dev;	int err;	if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)		return -ENODEV;	switch(cmd) 	{		case SIOCGIFFLAGS:	/* Get interface flags */			ifr->ifr_flags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI|IFF_RUNNING))				|(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI));			if (netif_running(dev) && netif_carrier_ok(dev))				ifr->ifr_flags |= IFF_RUNNING;			return 0;		case SIOCSIFFLAGS:	/* Set interface flags */			return dev_change_flags(dev, ifr->ifr_flags);				case SIOCGIFMETRIC:	/* Get the metric on the interface (currently unused) */			ifr->ifr_metric = 0;			return 0;					case SIOCSIFMETRIC:	/* Set the metric on the interface (currently unused) */			return -EOPNOTSUPP;			case SIOCGIFMTU:	/* Get the MTU of a device */			ifr->ifr_mtu = dev->mtu;			return 0;			case SIOCSIFMTU:	/* Set the MTU of a device */			if (ifr->ifr_mtu == dev->mtu)				return 0;			/*			 *	MTU must be positive.			 */			 			if (ifr->ifr_mtu<0)				return -EINVAL;			if (!netif_device_present(dev))				return -ENODEV;			if (dev->change_mtu)				err = dev->change_mtu(dev, ifr->ifr_mtu);			else {				dev->mtu = ifr->ifr_mtu;				err = 0;			}			if (!err && dev->flags&IFF_UP)				notifier_call_chain(&netdev_chain, NETDEV_CHANGEMTU, dev);			return err;		case SIOCGIFHWADDR:			memcpy(ifr->ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN);			ifr->ifr_hwaddr.sa_family=dev->type;			return 0;						case SIOCSIFHWADDR:			if (dev->set_mac_address == NULL)				return -EOPNOTSUPP;			if (ifr->ifr_hwaddr.sa_family!=dev->type)				return -EINVAL;			if (!netif_device_present(dev))				return -ENODEV;			err = dev->set_mac_address(dev, &ifr->ifr_hwaddr);			if (!err)				notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);			return err;					case SIOCSIFHWBROADCAST:			if (ifr->ifr_hwaddr.sa_family!=dev->type)				return -EINVAL;			memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, MAX_ADDR_LEN);			notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);			return 0;		case SIOCGIFMAP:			ifr->ifr_map.mem_start=dev->mem_start;			ifr->ifr_map.mem_end=dev->mem_end;			ifr->ifr_map.base_addr=dev->base_addr;			ifr->ifr_map.irq=dev->irq;			ifr->ifr_map.dma=dev->dma;			ifr->ifr_map.port=dev->if_port;			return 0;					case SIOCSIFMAP:			if (dev->set_config) {				if (!netif_device_present(dev))					return -ENODEV;				return dev->set_config(dev,&ifr->ifr_map);			}			return -EOPNOTSUPP;					case SIOCADDMULTI:			if (dev->set_multicast_list == NULL ||			    ifr->ifr_hwaddr.sa_family != AF_UNSPEC)				return -EINVAL;			if (!netif_device_present(dev))				return -ENODEV;			dev_mc_add(dev,ifr->ifr_hwaddr.sa_data, dev->addr_len, 1);			return 0;		case SIOCDELMULTI:			if (dev->set_multicast_list == NULL ||			    ifr->ifr_hwaddr.sa_family!=AF_UNSPEC)				return -EINVAL;			if (!netif_device_present(dev))				return -ENODEV;			dev_mc_delete(dev,ifr->ifr_hwaddr.sa_data,dev->addr_len, 1);			return 0;		case SIOCGIFINDEX:			ifr->ifr_ifindex = dev->ifindex;			return 0;		case SIOCGIFTXQLEN:			ifr->ifr_qlen = dev->tx_queue_len;			return 0;		case SIOCSIFTXQLEN:			if (ifr->ifr_qlen<0)				return -EINVAL;			dev->tx_queue_len = ifr->ifr_qlen;			return 0;		case SIOCSIFNAME:			if (dev->flags&IFF_UP)				return -EBUSY;			if (__dev_get_by_name(ifr->ifr_newname))				return -EEXIST;			memcpy(dev->name, ifr->ifr_newname, IFNAMSIZ);			dev->name[IFNAMSIZ-1] = 0;			notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);			return 0;		/*		 *	Unknown or private ioctl		 */		default:			if ((cmd >= SIOCDEVPRIVATE &&			    cmd <= SIOCDEVPRIVATE + 15) ||			    cmd == SIOCETHTOOL) {				if (dev->do_ioctl) {					if (!netif_device_present(dev))						return -ENODEV;					return dev->do_ioctl(dev, ifr, cmd);				}				return -EOPNOTSUPP;			}#ifdef WIRELESS_EXT			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {				if (dev->do_ioctl) {					if (!netif_device_present(dev))						return -ENODEV;					return dev->do_ioctl(dev, ifr, cmd);				}				return -EOPNOTSUPP;			}#endif	/* WIRELESS_EXT */	}	return -EINVAL;}/* *	This function handles all "interface"-type I/O control requests. The actual *	'doing' part of this is dev_ifsioc above. *//** *	dev_ioctl	-	network device ioctl *	@cmd: command to issue *	@arg: pointer to a struct ifreq in user space * *	Issue ioctl functions to devices. This is normally called by the *	user space syscall interfaces but can sometimes be useful for  *	other purposes. The return value is the return from the syscall if *	positive or a negative errno code on error. */int dev_ioctl(unsigned int cmd, void *arg){	struct ifreq ifr;	int ret;	char *colon;	/* One special case: SIOCGIFCONF takes ifconf argument	   and requires shared lock, because it sleeps writing	   to user space.	 */	   	if (cmd == SIOCGIFCONF) {		rtnl_shlock();		ret = dev_ifconf((char *) arg);		rtnl_shunlock();		return ret;	}	if (cmd == SIOCGIFNAME) {		return dev_ifname((struct ifreq *)arg);

⌨️ 快捷键说明

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