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

📄 devinet.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	ASSERT_RTNL();	if (!in_dev) {		if (event == NETDEV_REGISTER) {			in_dev = inetdev_init(dev);			if (!in_dev)				return notifier_from_errno(-ENOMEM);			if (dev->flags & IFF_LOOPBACK) {				IN_DEV_CONF_SET(in_dev, NOXFRM, 1);				IN_DEV_CONF_SET(in_dev, NOPOLICY, 1);			}		}		goto out;	}	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->flags & IFF_LOOPBACK) {			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:		/* Do not notify about label change, this event is		 * not interesting to applications using netlink.		 */		inetdev_changename(dev, in_dev);#ifdef CONFIG_SYSCTL		devinet_sysctl_unregister(&in_dev->cnf);		neigh_sysctl_unregister(in_dev->arp_parms);		neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,				      NET_IPV4_NEIGH, "ipv4", NULL, NULL);		devinet_sysctl_register(in_dev, &in_dev->cnf);#endif		break;	}out:	return NOTIFY_DONE;}static struct notifier_block ip_netdev_notifier = {	.notifier_call =inetdev_event,};static inline size_t inet_nlmsg_size(void){	return NLMSG_ALIGN(sizeof(struct ifaddrmsg))	       + nla_total_size(4) /* IFA_ADDRESS */	       + nla_total_size(4) /* IFA_LOCAL */	       + nla_total_size(4) /* IFA_BROADCAST */	       + nla_total_size(4) /* IFA_ANYCAST */	       + nla_total_size(IFNAMSIZ); /* IFA_LABEL */}static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,			    u32 pid, u32 seq, int event, unsigned int flags){	struct ifaddrmsg *ifm;	struct nlmsghdr  *nlh;	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags);	if (nlh == NULL)		return -EMSGSIZE;	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)		NLA_PUT_BE32(skb, IFA_ADDRESS, ifa->ifa_address);	if (ifa->ifa_local)		NLA_PUT_BE32(skb, IFA_LOCAL, ifa->ifa_local);	if (ifa->ifa_broadcast)		NLA_PUT_BE32(skb, IFA_BROADCAST, ifa->ifa_broadcast);	if (ifa->ifa_anycast)		NLA_PUT_BE32(skb, IFA_ANYCAST, ifa->ifa_anycast);	if (ifa->ifa_label[0])		NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label);	return nlmsg_end(skb, nlh);nla_put_failure:	nlmsg_cancel(skb, nlh);	return -EMSGSIZE;}static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb){	int idx, ip_idx;	struct net_device *dev;	struct in_device *in_dev;	struct in_ifaddr *ifa;	int s_ip_idx, s_idx = cb->args[0];	s_ip_idx = ip_idx = cb->args[1];	idx = 0;	for_each_netdev(&init_net, dev) {		if (idx < s_idx)			goto cont;		if (idx > s_idx)			s_ip_idx = 0;		if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)			goto cont;		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, NLM_F_MULTI) <= 0)				goto done;		}cont:		idx++;	}done:	cb->args[0] = idx;	cb->args[1] = ip_idx;	return skb->len;}static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,		      u32 pid){	struct sk_buff *skb;	u32 seq = nlh ? nlh->nlmsg_seq : 0;	int err = -ENOBUFS;	skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);	if (skb == NULL)		goto errout;	err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0);	if (err < 0) {		/* -EMSGSIZE implies BUG in inet_nlmsg_size() */		WARN_ON(err == -EMSGSIZE);		kfree_skb(skb);		goto errout;	}	err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);errout:	if (err < 0)		rtnl_set_sk_err(RTNLGRP_IPV4_IFADDR, err);}#ifdef CONFIG_SYSCTLstatic void devinet_copy_dflt_conf(int i){	struct net_device *dev;	read_lock(&dev_base_lock);	for_each_netdev(&init_net, dev) {		struct in_device *in_dev;		rcu_read_lock();		in_dev = __in_dev_get_rcu(dev);		if (in_dev && !test_bit(i, in_dev->cnf.state))			in_dev->cnf.data[i] = ipv4_devconf_dflt.data[i];		rcu_read_unlock();	}	read_unlock(&dev_base_lock);}static int devinet_conf_proc(ctl_table *ctl, int write,			     struct file* filp, void __user *buffer,			     size_t *lenp, loff_t *ppos){	int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);	if (write) {		struct ipv4_devconf *cnf = ctl->extra1;		int i = (int *)ctl->data - cnf->data;		set_bit(i, cnf->state);		if (cnf == &ipv4_devconf_dflt)			devinet_copy_dflt_conf(i);	}	return ret;}static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,			       void __user *oldval, size_t __user *oldlenp,			       void __user *newval, size_t newlen){	struct ipv4_devconf *cnf;	int *valp = table->data;	int new;	int i;	if (!newval || !newlen)		return 0;	if (newlen != sizeof(int))		return -EINVAL;	if (get_user(new, (int __user *)newval))		return -EFAULT;	if (new == *valp)		return 0;	if (oldval && oldlenp) {		size_t len;		if (get_user(len, oldlenp))			return -EFAULT;		if (len) {			if (len > table->maxlen)				len = table->maxlen;			if (copy_to_user(oldval, valp, len))				return -EFAULT;			if (put_user(len, oldlenp))				return -EFAULT;		}	}	*valp = new;	cnf = table->extra1;	i = (int *)table->data - cnf->data;	set_bit(i, cnf->state);	if (cnf == &ipv4_devconf_dflt)		devinet_copy_dflt_conf(i);	return 1;}void inet_forward_change(void){	struct net_device *dev;	int on = IPV4_DEVCONF_ALL(FORWARDING);	IPV4_DEVCONF_ALL(ACCEPT_REDIRECTS) = !on;	IPV4_DEVCONF_DFLT(FORWARDING) = on;	read_lock(&dev_base_lock);	for_each_netdev(&init_net, dev) {		struct in_device *in_dev;		rcu_read_lock();		in_dev = __in_dev_get_rcu(dev);		if (in_dev)			IN_DEV_CONF_SET(in_dev, FORWARDING, on);		rcu_read_unlock();	}	read_unlock(&dev_base_lock);	rt_cache_flush(0);}static int devinet_sysctl_forward(ctl_table *ctl, int write,				  struct file* filp, void __user *buffer,				  size_t *lenp, loff_t *ppos){	int *valp = ctl->data;	int val = *valp;	int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);	if (write && *valp != val) {		if (valp == &IPV4_DEVCONF_ALL(FORWARDING))			inet_forward_change();		else if (valp != &IPV4_DEVCONF_DFLT(FORWARDING))			rt_cache_flush(0);	}	return ret;}int ipv4_doint_and_flush(ctl_table *ctl, int write,			 struct file* filp, void __user *buffer,			 size_t *lenp, loff_t *ppos){	int *valp = ctl->data;	int val = *valp;	int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);	if (write && *valp != val)		rt_cache_flush(0);	return ret;}int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,				  void __user *oldval, size_t __user *oldlenp,				  void __user *newval, size_t newlen){	int ret = devinet_conf_sysctl(table, name, nlen, oldval, oldlenp,				      newval, newlen);	if (ret == 1)		rt_cache_flush(0);	return ret;}#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc, sysctl) \	{ \		.ctl_name	= NET_IPV4_CONF_ ## attr, \		.procname	= name, \		.data		= ipv4_devconf.data + \				  NET_IPV4_CONF_ ## attr - 1, \		.maxlen		= sizeof(int), \		.mode		= mval, \		.proc_handler	= proc, \		.strategy	= sysctl, \		.extra1		= &ipv4_devconf, \	}#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \	DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc, \			     devinet_conf_sysctl)#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \	DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc, \			     devinet_conf_sysctl)#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc, sysctl) \	DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc, sysctl)#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \	DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush, \				     ipv4_doint_and_flush_strategy)static struct devinet_sysctl_table {	struct ctl_table_header *sysctl_header;	ctl_table		devinet_vars[__NET_IPV4_CONF_MAX];	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 = {	.devinet_vars = {		DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",					     devinet_sysctl_forward,					     devinet_conf_sysctl),		DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),		DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),		DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),		DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"),		DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"),		DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),		DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,					"accept_source_route"),		DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),		DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),		DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),		DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),		DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),		DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"),		DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),		DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),		DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),		DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),		DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),		DEVINET_SYSCTL_FLUSHING_ENTRY(FORCE_IGMP_VERSION,					      "force_igmp_version"),		DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES,					      "promote_secondaries"),	},	.devinet_dev = {		{			.ctl_name	= NET_PROTO_CONF_ALL,			.procname	= "all",			.mode		= 0555,			.child		= devinet_sysctl.devinet_vars,		},	},	.devinet_conf_dir = {		{			.ctl_name	= NET_IPV4_CONF,			.procname	= "conf",			.mode		= 0555,			.child		= devinet_sysctl.devinet_dev,		},	},	.devinet_proto_dir = {		{			.ctl_name	= NET_IPV4,			.procname	= "ipv4",			.mode		= 0555,			.child 		= devinet_sysctl.devinet_conf_dir,		},	},	.devinet_root_dir = {		{			.ctl_name	= CTL_NET,			.procname 	= "net",			.mode		= 0555,			.child		= devinet_sysctl.devinet_proto_dir,		},	},};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 = kmemdup(&devinet_sysctl, sizeof(*t),						 GFP_KERNEL);	char *dev_name = NULL;	if (!t)		return;	for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {		t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;		t->devinet_vars[i].extra1 = p;	}	if (dev) {		dev_name = dev->name;		t->devinet_dev[0].ctl_name = dev->ifindex;	} else {		dev_name = "default";		t->devinet_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT;	}	/*	 * Make a copy of dev_name, because '.procname' is regarded as const	 * by sysctl and we wouldn't want anyone to change it under our feet	 * (see SIOCSIFNAME).	 */	dev_name = kstrdup(dev_name, GFP_KERNEL);	if (!dev_name)	    goto free;	t->devinet_dev[0].procname    = dev_name;	t->devinet_dev[0].child	      = t->devinet_vars;	t->devinet_conf_dir[0].child  = t->devinet_dev;	t->devinet_proto_dir[0].child = t->devinet_conf_dir;	t->devinet_root_dir[0].child  = t->devinet_proto_dir;	t->sysctl_header = register_sysctl_table(t->devinet_root_dir);	if (!t->sysctl_header)	    goto free_procname;	p->sysctl = t;	return;	/* error path */ free_procname:	kfree(dev_name); free:	kfree(t);	return;}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->devinet_dev[0].procname);		kfree(t);	}}#endifvoid __init devinet_init(void){	register_gifconf(PF_INET, inet_gifconf);	register_netdevice_notifier(&ip_netdev_notifier);	rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL);	rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL);	rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr);#ifdef CONFIG_SYSCTL	devinet_sysctl.sysctl_header =		register_sysctl_table(devinet_sysctl.devinet_root_dir);	devinet_sysctl_register(NULL, &ipv4_devconf_dflt);#endif}EXPORT_SYMBOL(in_dev_finish_destroy);EXPORT_SYMBOL(inet_select_addr);EXPORT_SYMBOL(inetdev_by_index);EXPORT_SYMBOL(register_inetaddr_notifier);EXPORT_SYMBOL(unregister_inetaddr_notifier);

⌨️ 快捷键说明

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