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

📄 devinet.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
				break;			}			ret = dev_change_flags(dev, ifr.ifr_flags);			break;			case SIOCSIFADDR:	/* Set interface address (and family) */			if (inet_abc_len(sin->sin_addr.s_addr) < 0) {				ret = -EINVAL;				break;			}			if (!ifa) {				if ((ifa = inet_alloc_ifa()) == NULL) {					ret = -ENOBUFS;					break;				}				if (colon)					memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);				else					memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);			} else {				ret = 0;				if (ifa->ifa_local == sin->sin_addr.s_addr)					break;				inet_del_ifa(in_dev, ifap, 0);				ifa->ifa_broadcast = 0;				ifa->ifa_anycast = 0;			}			ifa->ifa_address =			ifa->ifa_local = sin->sin_addr.s_addr;			if (!(dev->flags&IFF_POINTOPOINT)) {				ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);				ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);				if ((dev->flags&IFF_BROADCAST) && ifa->ifa_prefixlen < 31)					ifa->ifa_broadcast = ifa->ifa_address|~ifa->ifa_mask;			} else {				ifa->ifa_prefixlen = 32;				ifa->ifa_mask = inet_make_mask(32);			}			ret = inet_set_ifa(dev, ifa);			break;		case SIOCSIFBRDADDR:	/* Set the broadcast address */			if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {				inet_del_ifa(in_dev, ifap, 0);				ifa->ifa_broadcast = sin->sin_addr.s_addr;				inet_insert_ifa(ifa);			}			break;			case SIOCSIFDSTADDR:	/* Set the destination address */			if (ifa->ifa_address != sin->sin_addr.s_addr) {				if (inet_abc_len(sin->sin_addr.s_addr) < 0) {					ret = -EINVAL;					break;				}				inet_del_ifa(in_dev, ifap, 0);				ifa->ifa_address = sin->sin_addr.s_addr;				inet_insert_ifa(ifa);			}			break;		case SIOCSIFNETMASK: 	/* Set the netmask for the interface */			/*			 *	The mask we set must be legal.			 */			if (bad_mask(sin->sin_addr.s_addr, 0)) {				ret = -EINVAL;				break;			}			if (ifa->ifa_mask != sin->sin_addr.s_addr) {				inet_del_ifa(in_dev, ifap, 0);				ifa->ifa_mask = sin->sin_addr.s_addr;				ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);				inet_insert_ifa(ifa);			}			break;	}done:	rtnl_unlock();	dev_probe_unlock();	return ret;rarok:	rtnl_unlock();	dev_probe_unlock();	if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))		return -EFAULT;	return 0;}static intinet_gifconf(struct net_device *dev, char *buf, int len){	struct in_device *in_dev = __in_dev_get(dev);	struct in_ifaddr *ifa;	struct ifreq ifr;	int done=0;	if (in_dev==NULL || (ifa=in_dev->ifa_list)==NULL)		return 0;	for ( ; ifa; ifa = ifa->ifa_next) {		if (!buf) {			done += sizeof(ifr);			continue;		}		if (len < (int) sizeof(ifr))			return done;		memset(&ifr, 0, sizeof(struct ifreq));		if (ifa->ifa_label)			strcpy(ifr.ifr_name, ifa->ifa_label);		else			strcpy(ifr.ifr_name, dev->name);		(*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = AF_INET;		(*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = ifa->ifa_local;		if (copy_to_user(buf, &ifr, sizeof(struct ifreq)))			return -EFAULT;		buf += sizeof(struct ifreq);		len -= sizeof(struct ifreq);		done += sizeof(struct ifreq);	}	return done;}u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope){	u32 addr = 0;	struct in_device *in_dev;	read_lock(&inetdev_lock);	in_dev = __in_dev_get(dev);	if (in_dev == NULL) {		read_unlock(&inetdev_lock);		return 0;	}	read_lock(&in_dev->lock);	for_primary_ifa(in_dev) {		if (ifa->ifa_scope > scope)			continue;		if (!dst || inet_ifa_match(dst, ifa)) {			addr = ifa->ifa_local;			break;		}		if (!addr)			addr = ifa->ifa_local;	} endfor_ifa(in_dev);	read_unlock(&in_dev->lock);	read_unlock(&inetdev_lock);	if (addr)		return addr;	/* Not loopback addresses on loopback should be preferred	   in this case. It is importnat that lo is the first interface	   in dev_base list.	 */	read_lock(&dev_base_lock);	read_lock(&inetdev_lock);	for (dev=dev_base; dev; dev=dev->next) {		if ((in_dev=__in_dev_get(dev)) == NULL)			continue;		read_lock(&in_dev->lock);		for_primary_ifa(in_dev) {			if (ifa->ifa_scope != RT_SCOPE_LINK &&			    ifa->ifa_scope <= scope) {				read_unlock(&in_dev->lock);				read_unlock(&inetdev_lock);				read_unlock(&dev_base_lock);				return ifa->ifa_local;			}		} endfor_ifa(in_dev);		read_unlock(&in_dev->lock);	}	read_unlock(&inetdev_lock);	read_unlock(&dev_base_lock);	return 0;}/* *	Device notifier */int register_inetaddr_notifier(struct notifier_block *nb){	return notifier_chain_register(&inetaddr_chain, nb);}int unregister_inetaddr_notifier(struct notifier_block *nb){	return notifier_chain_unregister(&inetaddr_chain,nb);}/* Called only under RTNL semaphore */static int inetdev_event(struct notifier_block *this, unsigned long event, void *ptr){	struct net_device *dev = ptr;	struct in_device *in_dev = __in_dev_get(dev);	ASSERT_RTNL();	if (in_dev == NULL)		return NOTIFY_DONE;	switch (event) {	case NETDEV_REGISTER:		printk(KERN_DEBUG "inetdev_event: bug\n");		dev->ip_ptr = NULL;		break;	case NETDEV_UP:		if (dev->mtu < 68)			break;		if (dev == &loopback_dev) {			struct in_ifaddr *ifa;			if ((ifa = inet_alloc_ifa()) != NULL) {				ifa->ifa_local =				ifa->ifa_address = htonl(INADDR_LOOPBACK);				ifa->ifa_prefixlen = 8;				ifa->ifa_mask = inet_make_mask(8);				in_dev_hold(in_dev);				ifa->ifa_dev = in_dev;				ifa->ifa_scope = RT_SCOPE_HOST;				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);				inet_insert_ifa(ifa);			}		}		ip_mc_up(in_dev);		break;	case NETDEV_DOWN:		ip_mc_down(in_dev);		break;	case NETDEV_CHANGEMTU:		if (dev->mtu >= 68)			break;		/* MTU falled under 68, disable IP */	case NETDEV_UNREGISTER:		inetdev_destroy(in_dev);		break;	case NETDEV_CHANGENAME:		if (in_dev->ifa_list) {			struct in_ifaddr *ifa;			for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next)				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);			/* Do not notify about label change, this event is			   not interesting to applications using netlink.			 */		}		break;	}	return NOTIFY_DONE;}struct notifier_block ip_netdev_notifier={	inetdev_event,	NULL,	0};#ifdef CONFIG_RTNETLINKstatic int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,			    u32 pid, u32 seq, int event){	struct ifaddrmsg *ifm;	struct nlmsghdr  *nlh;	unsigned char	 *b = skb->tail;	nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm));	ifm = NLMSG_DATA(nlh);	ifm->ifa_family = AF_INET;	ifm->ifa_prefixlen = ifa->ifa_prefixlen;	ifm->ifa_flags = ifa->ifa_flags|IFA_F_PERMANENT;	ifm->ifa_scope = ifa->ifa_scope;	ifm->ifa_index = ifa->ifa_dev->dev->ifindex;	if (ifa->ifa_address)		RTA_PUT(skb, IFA_ADDRESS, 4, &ifa->ifa_address);	if (ifa->ifa_local)		RTA_PUT(skb, IFA_LOCAL, 4, &ifa->ifa_local);	if (ifa->ifa_broadcast)		RTA_PUT(skb, IFA_BROADCAST, 4, &ifa->ifa_broadcast);	if (ifa->ifa_anycast)		RTA_PUT(skb, IFA_ANYCAST, 4, &ifa->ifa_anycast);	if (ifa->ifa_label[0])		RTA_PUT(skb, IFA_LABEL, IFNAMSIZ, &ifa->ifa_label);	nlh->nlmsg_len = skb->tail - b;	return skb->len;nlmsg_failure:rtattr_failure:	skb_trim(skb, b - skb->data);	return -1;}static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb){	int idx, ip_idx;	int s_idx, s_ip_idx;	struct net_device *dev;	struct in_device *in_dev;	struct in_ifaddr *ifa;	s_idx = cb->args[0];	s_ip_idx = ip_idx = cb->args[1];	read_lock(&dev_base_lock);	for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {		if (idx < s_idx)			continue;		if (idx > s_idx)			s_ip_idx = 0;		read_lock(&inetdev_lock);		if ((in_dev = __in_dev_get(dev)) == NULL) {			read_unlock(&inetdev_lock);			continue;		}		read_lock(&in_dev->lock);		for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;		     ifa = ifa->ifa_next, ip_idx++) {			if (ip_idx < s_ip_idx)				continue;			if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,					     cb->nlh->nlmsg_seq, RTM_NEWADDR) <= 0) {				read_unlock(&in_dev->lock);				read_unlock(&inetdev_lock);				goto done;			}		}		read_unlock(&in_dev->lock);		read_unlock(&inetdev_lock);	}done:	read_unlock(&dev_base_lock);	cb->args[0] = idx;	cb->args[1] = ip_idx;	return skb->len;}static void rtmsg_ifa(int event, struct in_ifaddr * ifa){	struct sk_buff *skb;	int size = NLMSG_SPACE(sizeof(struct ifaddrmsg)+128);	skb = alloc_skb(size, GFP_KERNEL);	if (!skb) {		netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, ENOBUFS);		return;	}	if (inet_fill_ifaddr(skb, ifa, 0, 0, event) < 0) {		kfree_skb(skb);		netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, EINVAL);		return;	}	NETLINK_CB(skb).dst_groups = RTMGRP_IPV4_IFADDR;	netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV4_IFADDR, GFP_KERNEL);}static struct rtnetlink_link inet_rtnetlink_table[RTM_MAX-RTM_BASE+1] ={	{ NULL,			NULL,			},	{ NULL,			NULL,			},	{ NULL,			NULL,			},	{ NULL,			NULL,			},	{ inet_rtm_newaddr,	NULL,			},	{ inet_rtm_deladdr,	NULL,			},	{ NULL,			inet_dump_ifaddr,	},	{ NULL,			NULL,			},	{ inet_rtm_newroute,	NULL,			},	{ inet_rtm_delroute,	NULL,			},	{ inet_rtm_getroute,	inet_dump_fib,		},	{ NULL,			NULL,			},	{ NULL,			NULL,			},	{ NULL,			NULL,			},	{ NULL,			NULL,			},	{ NULL,			NULL,			},#ifdef CONFIG_IP_MULTIPLE_TABLES	{ inet_rtm_newrule,	NULL,			},	{ inet_rtm_delrule,	NULL,			},	{ NULL,			inet_dump_rules,	},	{ NULL,			NULL,			},#else	{ NULL,			NULL,			},	{ NULL,			NULL,			},	{ NULL,			NULL,			},	{ NULL,			NULL,			},#endif};#endif /* CONFIG_RTNETLINK */#ifdef CONFIG_SYSCTLvoid inet_forward_change(){	struct net_device *dev;	int on = ipv4_devconf.forwarding;	ipv4_devconf.accept_redirects = !on;	ipv4_devconf_dflt.forwarding = on;	read_lock(&dev_base_lock);	for (dev = dev_base; dev; dev = dev->next) {		struct in_device *in_dev;		read_lock(&inetdev_lock);		in_dev = __in_dev_get(dev);		if (in_dev)			in_dev->cnf.forwarding = on;		read_unlock(&inetdev_lock);	}	read_unlock(&dev_base_lock);	rt_cache_flush(0);}staticint devinet_sysctl_forward(ctl_table *ctl, int write, struct file * filp,			   void *buffer, size_t *lenp){	int *valp = ctl->data;	int val = *valp;	int ret;	ret = proc_dointvec(ctl, write, filp, buffer, lenp);	if (write && *valp != val) {		if (valp == &ipv4_devconf.forwarding)			inet_forward_change();		else if (valp != &ipv4_devconf_dflt.forwarding)			rt_cache_flush(0);	}        return ret;}static struct devinet_sysctl_table{	struct ctl_table_header *sysctl_header;	ctl_table devinet_vars[13];	ctl_table devinet_dev[2];	ctl_table devinet_conf_dir[2];	ctl_table devinet_proto_dir[2];	ctl_table devinet_root_dir[2];} devinet_sysctl = {	NULL,	{{NET_IPV4_CONF_FORWARDING, "forwarding",         &ipv4_devconf.forwarding, sizeof(int), 0644, NULL,         &devinet_sysctl_forward},	{NET_IPV4_CONF_MC_FORWARDING, "mc_forwarding",         &ipv4_devconf.mc_forwarding, sizeof(int), 0444, NULL,         &proc_dointvec},	{NET_IPV4_CONF_ACCEPT_REDIRECTS, "accept_redirects",         &ipv4_devconf.accept_redirects, sizeof(int), 0644, NULL,         &proc_dointvec},	{NET_IPV4_CONF_SECURE_REDIRECTS, "secure_redirects",         &ipv4_devconf.secure_redirects, sizeof(int), 0644, NULL,         &proc_dointvec},	{NET_IPV4_CONF_SHARED_MEDIA, "shared_media",         &ipv4_devconf.shared_media, sizeof(int), 0644, NULL,         &proc_dointvec},	{NET_IPV4_CONF_RP_FILTER, "rp_filter",         &ipv4_devconf.rp_filter, sizeof(int), 0644, NULL,         &proc_dointvec},	{NET_IPV4_CONF_SEND_REDIRECTS, "send_redirects",         &ipv4_devconf.send_redirects, sizeof(int), 0644, NULL,         &proc_dointvec},	{NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE, "accept_source_route",         &ipv4_devconf.accept_source_route, sizeof(int), 0644, NULL,         &proc_dointvec},	{NET_IPV4_CONF_PROXY_ARP, "proxy_arp",         &ipv4_devconf.proxy_arp, sizeof(int), 0644, NULL,         &proc_dointvec},	{NET_IPV4_CONF_BOOTP_RELAY, "bootp_relay",         &ipv4_devconf.bootp_relay, sizeof(int), 0644, NULL,         &proc_dointvec},        {NET_IPV4_CONF_LOG_MARTIANS, "log_martians",         &ipv4_devconf.log_martians, sizeof(int), 0644, NULL,         &proc_dointvec},	{NET_IPV4_CONF_TAG, "tag",	 &ipv4_devconf.tag, sizeof(int), 0644, NULL,	 &proc_dointvec},	 {0}},	{{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, devinet_sysctl.devinet_vars},{0}},	{{NET_IPV4_CONF, "conf", NULL, 0, 0555, devinet_sysctl.devinet_dev},{0}},	{{NET_IPV4, "ipv4", NULL, 0, 0555, devinet_sysctl.devinet_conf_dir},{0}},	{{CTL_NET, "net", NULL, 0, 0555, devinet_sysctl.devinet_proto_dir},{0}}};static void devinet_sysctl_register(struct in_device *in_dev, struct ipv4_devconf *p){	int i;	struct net_device *dev = in_dev ? in_dev->dev : NULL;	struct devinet_sysctl_table *t;	t = kmalloc(sizeof(*t), GFP_KERNEL);	if (t == NULL)		return;	memcpy(t, &devinet_sysctl, sizeof(*t));	for (i=0; i<sizeof(t->devinet_vars)/sizeof(t->devinet_vars[0])-1; i++) {		t->devinet_vars[i].data += (char*)p - (char*)&ipv4_devconf;		t->devinet_vars[i].de = NULL;	}	if (dev) {		t->devinet_dev[0].procname = dev->name;		t->devinet_dev[0].ctl_name = dev->ifindex;	} else {		t->devinet_dev[0].procname = "default";		t->devinet_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT;	}	t->devinet_dev[0].child = t->devinet_vars;	t->devinet_dev[0].de = NULL;	t->devinet_conf_dir[0].child = t->devinet_dev;	t->devinet_conf_dir[0].de = NULL;	t->devinet_proto_dir[0].child = t->devinet_conf_dir;	t->devinet_proto_dir[0].de = NULL;	t->devinet_root_dir[0].child = t->devinet_proto_dir;	t->devinet_root_dir[0].de = NULL;	t->sysctl_header = register_sysctl_table(t->devinet_root_dir, 0);	if (t->sysctl_header == NULL)		kfree(t);	else		p->sysctl = t;}static void devinet_sysctl_unregister(struct ipv4_devconf *p){	if (p->sysctl) {		struct devinet_sysctl_table *t = p->sysctl;		p->sysctl = NULL;		unregister_sysctl_table(t->sysctl_header);		kfree(t);	}}#endifvoid __init devinet_init(void){	register_gifconf(PF_INET, inet_gifconf);	register_netdevice_notifier(&ip_netdev_notifier);#ifdef CONFIG_RTNETLINK	rtnetlink_links[PF_INET] = inet_rtnetlink_table;#endif#ifdef CONFIG_SYSCTL	devinet_sysctl.sysctl_header =		register_sysctl_table(devinet_sysctl.devinet_root_dir, 0);	devinet_sysctl_register(NULL, &ipv4_devconf_dflt);#endif}

⌨️ 快捷键说明

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