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

📄 devinet.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *	NET3	IP device support routines. * *	Version: $Id: devinet.c,v 1.44 2001/10/31 21:55:54 davem Exp $ * *		This program is free software; you can redistribute it and/or *		modify it under the terms of the GNU General Public License *		as published by the Free Software Foundation; either version *		2 of the License, or (at your option) any later version. * *	Derived from the IP parts of dev.c 1.0.19 * 		Authors:	Ross Biro, <bir7@leland.Stanford.Edu> *				Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> *				Mark Evans, <evansmp@uhura.aston.ac.uk> * *	Additional Authors: *		Alan Cox, <gw4pts@gw4pts.ampr.org> *		Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * *	Changes: *		Alexey Kuznetsov:	pa_* fields are replaced with ifaddr *					lists. *		Cyrus Durgin:		updated for kmod *		Matthias Andree:	in devinet_ioctl, compare label and *					address (4.4BSD alias style support), *					fall back to comparing just the label *					if no match found. */#include <linux/config.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/bitops.h>#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/in.h>#include <linux/errno.h>#include <linux/interrupt.h>#include <linux/if_ether.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/rtnetlink.h>#include <linux/init.h>#include <linux/notifier.h>#include <linux/inetdevice.h>#include <linux/igmp.h>#ifdef CONFIG_SYSCTL#include <linux/sysctl.h>#endif#include <linux/kmod.h>#include <net/ip.h>#include <net/route.h>#include <net/ip_fib.h>struct ipv4_devconf ipv4_devconf = {	.accept_redirects = 1,	.send_redirects =  1,	.secure_redirects = 1,	.shared_media =	  1,};static struct ipv4_devconf ipv4_devconf_dflt = {	.accept_redirects =  1,	.send_redirects =    1,	.secure_redirects =  1,	.shared_media =	     1,	.accept_source_route = 1,};static void rtmsg_ifa(int event, struct in_ifaddr *);static struct notifier_block *inetaddr_chain;static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,			 int destroy);#ifdef CONFIG_SYSCTLstatic void devinet_sysctl_register(struct in_device *in_dev,				    struct ipv4_devconf *p);static void devinet_sysctl_unregister(struct ipv4_devconf *p);#endif/* Locks all the inet devices. */static struct in_ifaddr *inet_alloc_ifa(void){	struct in_ifaddr *ifa = kmalloc(sizeof(*ifa), GFP_KERNEL);	if (ifa) {		memset(ifa, 0, sizeof(*ifa));		INIT_RCU_HEAD(&ifa->rcu_head);	}	return ifa;}static void inet_rcu_free_ifa(struct rcu_head *head){	struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);	if (ifa->ifa_dev)		in_dev_put(ifa->ifa_dev);	kfree(ifa);}static inline void inet_free_ifa(struct in_ifaddr *ifa){	call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);}void in_dev_finish_destroy(struct in_device *idev){	struct net_device *dev = idev->dev;	BUG_TRAP(!idev->ifa_list);	BUG_TRAP(!idev->mc_list);#ifdef NET_REFCNT_DEBUG	printk(KERN_DEBUG "in_dev_finish_destroy: %p=%s\n",	       idev, dev ? dev->name : "NIL");#endif	dev_put(dev);	if (!idev->dead)		printk("Freeing alive in_device %p\n", idev);	else {		kfree(idev);	}}struct in_device *inetdev_init(struct net_device *dev){	struct in_device *in_dev;	ASSERT_RTNL();	in_dev = kmalloc(sizeof(*in_dev), GFP_KERNEL);	if (!in_dev)		goto out;	memset(in_dev, 0, sizeof(*in_dev));	INIT_RCU_HEAD(&in_dev->rcu_head);	memcpy(&in_dev->cnf, &ipv4_devconf_dflt, sizeof(in_dev->cnf));	in_dev->cnf.sysctl = NULL;	in_dev->dev = dev;	if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL)		goto out_kfree;	/* Reference in_dev->dev */	dev_hold(dev);#ifdef CONFIG_SYSCTL	neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,			      NET_IPV4_NEIGH, "ipv4", NULL);#endif	/* Account for reference dev->ip_ptr */	in_dev_hold(in_dev);	smp_wmb();	dev->ip_ptr = in_dev;#ifdef CONFIG_SYSCTL	devinet_sysctl_register(in_dev, &in_dev->cnf);#endif	ip_mc_init_dev(in_dev);	if (dev->flags & IFF_UP)		ip_mc_up(in_dev);out:	return in_dev;out_kfree:	kfree(in_dev);	in_dev = NULL;	goto out;}static void in_dev_rcu_put(struct rcu_head *head){	struct in_device *idev = container_of(head, struct in_device, rcu_head);	in_dev_put(idev);}static void inetdev_destroy(struct in_device *in_dev){	struct in_ifaddr *ifa;	struct net_device *dev;	ASSERT_RTNL();	in_dev->dead = 1;	ip_mc_destroy_dev(in_dev);	while ((ifa = in_dev->ifa_list) != NULL) {		inet_del_ifa(in_dev, &in_dev->ifa_list, 0);		inet_free_ifa(ifa);	}#ifdef CONFIG_SYSCTL	devinet_sysctl_unregister(&in_dev->cnf);#endif	dev = in_dev->dev;	dev->ip_ptr = NULL;#ifdef CONFIG_SYSCTL	neigh_sysctl_unregister(in_dev->arp_parms);#endif	neigh_parms_release(&arp_tbl, in_dev->arp_parms);	arp_ifdown(dev);	call_rcu(&in_dev->rcu_head, in_dev_rcu_put);}int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b){	rcu_read_lock();	for_primary_ifa(in_dev) {		if (inet_ifa_match(a, ifa)) {			if (!b || inet_ifa_match(b, ifa)) {				rcu_read_unlock();				return 1;			}		}	} endfor_ifa(in_dev);	rcu_read_unlock();	return 0;}static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,			 int destroy){	struct in_ifaddr *ifa1 = *ifap;	ASSERT_RTNL();	/* 1. Deleting primary ifaddr forces deletion all secondaries */	if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {		struct in_ifaddr *ifa;		struct in_ifaddr **ifap1 = &ifa1->ifa_next;		while ((ifa = *ifap1) != NULL) {			if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||			    ifa1->ifa_mask != ifa->ifa_mask ||			    !inet_ifa_match(ifa1->ifa_address, ifa)) {				ifap1 = &ifa->ifa_next;				continue;			}			*ifap1 = ifa->ifa_next;			rtmsg_ifa(RTM_DELADDR, ifa);			notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa);			inet_free_ifa(ifa);		}	}	/* 2. Unlink it */	*ifap = ifa1->ifa_next;	/* 3. Announce address deletion */	/* Send message first, then call notifier.	   At first sight, FIB update triggered by notifier	   will refer to already deleted ifaddr, that could confuse	   netlink listeners. It is not true: look, gated sees	   that route deleted and if it still thinks that ifaddr	   is valid, it will try to restore deleted routes... Grr.	   So that, this order is correct.	 */	rtmsg_ifa(RTM_DELADDR, ifa1);	notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);	if (destroy) {		inet_free_ifa(ifa1);		if (!in_dev->ifa_list)			inetdev_destroy(in_dev);	}}static int inet_insert_ifa(struct in_ifaddr *ifa){	struct in_device *in_dev = ifa->ifa_dev;	struct in_ifaddr *ifa1, **ifap, **last_primary;	ASSERT_RTNL();	if (!ifa->ifa_local) {		inet_free_ifa(ifa);		return 0;	}	ifa->ifa_flags &= ~IFA_F_SECONDARY;	last_primary = &in_dev->ifa_list;	for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;	     ifap = &ifa1->ifa_next) {		if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&		    ifa->ifa_scope <= ifa1->ifa_scope)			last_primary = &ifa1->ifa_next;		if (ifa1->ifa_mask == ifa->ifa_mask &&		    inet_ifa_match(ifa1->ifa_address, ifa)) {			if (ifa1->ifa_local == ifa->ifa_local) {				inet_free_ifa(ifa);				return -EEXIST;			}			if (ifa1->ifa_scope != ifa->ifa_scope) {				inet_free_ifa(ifa);				return -EINVAL;			}			ifa->ifa_flags |= IFA_F_SECONDARY;		}	}	if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {		net_srandom(ifa->ifa_local);		ifap = last_primary;	}	ifa->ifa_next = *ifap;	*ifap = ifa;	/* Send message first, then call notifier.	   Notifier will trigger FIB update, so that	   listeners of netlink will know about new ifaddr */	rtmsg_ifa(RTM_NEWADDR, ifa);	notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);	return 0;}static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa){	struct in_device *in_dev = __in_dev_get(dev);	ASSERT_RTNL();	if (!in_dev) {		in_dev = inetdev_init(dev);		if (!in_dev) {			inet_free_ifa(ifa);			return -ENOBUFS;		}	}	if (ifa->ifa_dev != in_dev) {		BUG_TRAP(!ifa->ifa_dev);		in_dev_hold(in_dev);		ifa->ifa_dev = in_dev;	}	if (LOOPBACK(ifa->ifa_local))		ifa->ifa_scope = RT_SCOPE_HOST;	return inet_insert_ifa(ifa);}struct in_device *inetdev_by_index(int ifindex){	struct net_device *dev;	struct in_device *in_dev = NULL;	read_lock(&dev_base_lock);	dev = __dev_get_by_index(ifindex);	if (dev)		in_dev = in_dev_get(dev);	read_unlock(&dev_base_lock);	return in_dev;}/* Called only from RTNL semaphored context. No locks. */struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix,				    u32 mask){	ASSERT_RTNL();	for_primary_ifa(in_dev) {		if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))			return ifa;	} endfor_ifa(in_dev);	return NULL;}int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){	struct rtattr **rta = arg;	struct in_device *in_dev;	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);	struct in_ifaddr *ifa, **ifap;	ASSERT_RTNL();	if ((in_dev = inetdev_by_index(ifm->ifa_index)) == NULL)		goto out;	__in_dev_put(in_dev);	for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;	     ifap = &ifa->ifa_next) {		if ((rta[IFA_LOCAL - 1] &&		     memcmp(RTA_DATA(rta[IFA_LOCAL - 1]),			    &ifa->ifa_local, 4)) ||		    (rta[IFA_LABEL - 1] &&		     strcmp(RTA_DATA(rta[IFA_LABEL - 1]), ifa->ifa_label)) ||		    (rta[IFA_ADDRESS - 1] &&		     (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||		      !inet_ifa_match(*(u32*)RTA_DATA(rta[IFA_ADDRESS - 1]),			      	      ifa))))			continue;		inet_del_ifa(in_dev, ifap, 1);		return 0;	}out:	return -EADDRNOTAVAIL;}int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){	struct rtattr **rta = arg;	struct net_device *dev;	struct in_device *in_dev;	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);	struct in_ifaddr *ifa;	int rc = -EINVAL;	ASSERT_RTNL();	if (ifm->ifa_prefixlen > 32 || !rta[IFA_LOCAL - 1])		goto out;	rc = -ENODEV;	if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL)		goto out;	rc = -ENOBUFS;	if ((in_dev = __in_dev_get(dev)) == NULL) {		in_dev = inetdev_init(dev);		if (!in_dev)			goto out;	}	if ((ifa = inet_alloc_ifa()) == NULL)		goto out;	if (!rta[IFA_ADDRESS - 1])		rta[IFA_ADDRESS - 1] = rta[IFA_LOCAL - 1];	memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL - 1]), 4);	memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS - 1]), 4);	ifa->ifa_prefixlen = ifm->ifa_prefixlen;	ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);	if (rta[IFA_BROADCAST - 1])		memcpy(&ifa->ifa_broadcast,		       RTA_DATA(rta[IFA_BROADCAST - 1]), 4);	if (rta[IFA_ANYCAST - 1])		memcpy(&ifa->ifa_anycast, RTA_DATA(rta[IFA_ANYCAST - 1]), 4);	ifa->ifa_flags = ifm->ifa_flags;	ifa->ifa_scope = ifm->ifa_scope;	in_dev_hold(in_dev);	ifa->ifa_dev   = in_dev;	if (rta[IFA_LABEL - 1])		memcpy(ifa->ifa_label, RTA_DATA(rta[IFA_LABEL - 1]), IFNAMSIZ);	else		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);	rc = inet_insert_ifa(ifa);out:	return rc;}/* *	Determine a default network mask, based on the IP address. */static __inline__ int inet_abc_len(u32 addr){	int rc = -1;	/* Something else, probably a multicast. */  	if (ZERONET(addr))  		rc = 0;	else {		addr = ntohl(addr);		if (IN_CLASSA(addr))			rc = 8;		else if (IN_CLASSB(addr))			rc = 16;		else if (IN_CLASSC(addr))			rc = 24;	}  	return rc;}int devinet_ioctl(unsigned int cmd, void __user *arg){	struct ifreq ifr;	struct sockaddr_in sin_orig;	struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;	struct in_device *in_dev;	struct in_ifaddr **ifap = NULL;	struct in_ifaddr *ifa = NULL;

⌨️ 快捷键说明

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