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

📄 devinet.c

📁 GNU Hurd 源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	NET3	IP device support routines. * *	Version: $Id: devinet.c,v 1.28.2.2 1999/08/07 10:56:18 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 */#include <linux/config.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/bitops.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#ifdef CONFIG_KMOD#include <linux/kmod.h>#endif#include <net/ip.h>#include <net/route.h>#include <net/ip_fib.h>struct ipv4_devconf ipv4_devconf = { 1, 1, 1, 1, 0, };static struct ipv4_devconf ipv4_devconf_dflt = { 1, 1, 1, 1, 1, };#ifdef CONFIG_RTNETLINKstatic void rtmsg_ifa(int event, struct in_ifaddr *);#else#define rtmsg_ifa(a,b)	do { } while(0)#endifstatic 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);#endifint inet_ifa_count;int inet_dev_count;static struct in_ifaddr * inet_alloc_ifa(void){	struct in_ifaddr *ifa;	ifa = kmalloc(sizeof(*ifa), GFP_KERNEL);	if (ifa) {		memset(ifa, 0, sizeof(*ifa));		inet_ifa_count++;	}	return ifa;}static __inline__ void inet_free_ifa(struct in_ifaddr *ifa){	kfree_s(ifa, sizeof(*ifa));	inet_ifa_count--;}struct in_device *inetdev_init(struct device *dev){	struct in_device *in_dev;	if (dev->mtu < 68)		return NULL;	in_dev = kmalloc(sizeof(*in_dev), GFP_KERNEL);	if (!in_dev)		return NULL;	inet_dev_count++;	memset(in_dev, 0, sizeof(*in_dev));	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) {		kfree(in_dev);		return NULL;	}#ifdef CONFIG_SYSCTL	neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");#endif	dev->ip_ptr = in_dev;#ifdef CONFIG_SYSCTL	devinet_sysctl_register(in_dev, &in_dev->cnf);#endif	if (dev->flags&IFF_UP)		ip_mc_up(in_dev);	return in_dev;}static void inetdev_destroy(struct in_device *in_dev){	struct in_ifaddr *ifa;	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	in_dev->dev->ip_ptr = NULL;	synchronize_bh();	neigh_parms_release(&arp_tbl, in_dev->arp_parms);	kfree(in_dev);}struct in_ifaddr * inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b){	for_primary_ifa(in_dev) {		if (inet_ifa_match(a, ifa)) {			if (!b || inet_ifa_match(b, ifa))				return ifa;		}	} endfor_ifa(in_dev);	return NULL;}static voidinet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy){	struct in_ifaddr *ifa1 = *ifap;	/* 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;			synchronize_bh();			rtmsg_ifa(RTM_DELADDR, ifa);			notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa);			inet_free_ifa(ifa);		}	}	/* 2. Unlink it */	*ifap = ifa1->ifa_next;	synchronize_bh();	/* 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 == NULL)			inetdev_destroy(in_dev);	}}static intinet_insert_ifa(struct in_device *in_dev, struct in_ifaddr *ifa){	struct in_ifaddr *ifa1, **ifap, **last_primary;	if (ifa->ifa_local == 0) {		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;	wmb();	*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 intinet_set_ifa(struct device *dev, struct in_ifaddr *ifa){	struct in_device *in_dev = dev->ip_ptr;	if (in_dev == NULL) {		in_dev = inetdev_init(dev);		if (in_dev == NULL) {			inet_free_ifa(ifa);			return -ENOBUFS;		}	}	ifa->ifa_dev = in_dev;	if (LOOPBACK(ifa->ifa_local))		ifa->ifa_scope = RT_SCOPE_HOST;	return inet_insert_ifa(in_dev, ifa);}struct in_device *inetdev_by_index(int ifindex){	struct device *dev;	dev = dev_get_by_index(ifindex);	if (dev)		return dev->ip_ptr;	return NULL;}struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask){	for_primary_ifa(in_dev) {		if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))			return ifa;	} endfor_ifa(in_dev);	return NULL;}#ifdef CONFIG_RTNETLINK/* rtm_{add|del} functions are not reenterable, so that   this structure can be made static */intinet_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;	if ((in_dev = inetdev_by_index(ifm->ifa_index)) == NULL)		return -EADDRNOTAVAIL;	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;	}	return -EADDRNOTAVAIL;}intinet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){	struct rtattr **rta = arg;	struct device *dev;	struct in_device *in_dev;	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);	struct in_ifaddr *ifa;	if (ifm->ifa_prefixlen > 32 || rta[IFA_LOCAL-1] == NULL)		return -EINVAL;	if ((dev = dev_get_by_index(ifm->ifa_index)) == NULL)		return -ENODEV;	if ((in_dev = dev->ip_ptr) == NULL) {		in_dev = inetdev_init(dev);		if (!in_dev)			return -ENOBUFS;	}	if ((ifa = inet_alloc_ifa()) == NULL)		return -ENOBUFS;	if (rta[IFA_ADDRESS-1] == NULL)		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;	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);	return inet_insert_ifa(in_dev, ifa);}#endif/* *	Determine a default network mask, based on the IP address. */static __inline__ int inet_abc_len(u32 addr){  	if (ZERONET(addr))  		return 0;  	addr = ntohl(addr);  	if (IN_CLASSA(addr))  		return 8;  	if (IN_CLASSB(addr))  		return 16;  	if (IN_CLASSC(addr))  		return 24;	/*	 *	Something else, probably a multicast.	 */  	return -1;}#ifdef _HURD_#define devinet_ioctl 0error_tconfigure_device (struct device *dev,		  uint32_t addr, uint32_t netmask, uint32_t peer,		  uint32_t broadcast){  struct in_device *in_dev = dev->ip_ptr;  struct in_ifaddr *ifa = in_dev ? in_dev->ifa_list : 0;  if (ifa)    {      inet_del_ifa (in_dev, &in_dev->ifa_list, 0);      ifa->ifa_broadcast = 0;      ifa->ifa_anycast = 0;    }  else    {      ifa = inet_alloc_ifa ();      if (!ifa)	return ENOBUFS;      memcpy (ifa->ifa_label, dev->name, IFNAMSIZ);      ifa->ifa_address = INADDR_NONE;      ifa->ifa_mask = INADDR_NONE;      ifa->ifa_broadcast = INADDR_NONE;      ifa->ifa_local = INADDR_NONE;    }  if (addr != INADDR_NONE)    ifa->ifa_address = ifa->ifa_local = addr;  if (netmask != INADDR_NONE && !(dev->flags & IFF_POINTOPOINT))    {      ifa->ifa_mask = netmask;      ifa->ifa_prefixlen = inet_mask_len (ifa->ifa_mask);      if ((dev->flags&IFF_BROADCAST) && ifa->ifa_prefixlen < 31)	ifa->ifa_broadcast = ifa->ifa_address|~ifa->ifa_mask;      else	ifa->ifa_broadcast = 0;    }  if (peer != INADDR_NONE && (dev->flags & IFF_POINTOPOINT))    {      ifa->ifa_prefixlen = 32;      ifa->ifa_mask = inet_make_mask(32);      ifa->ifa_address = peer;    }  if (broadcast != INADDR_NONE)    ifa->ifa_broadcast = broadcast;  return - (inet_set_ifa (dev, ifa)	    ?: dev_change_flags (dev, dev->flags | IFF_UP));}voidinquire_device (struct device *dev,		uint32_t *addr, uint32_t *netmask, uint32_t *peer,		uint32_t *broadcast){  struct in_device *in_dev = dev->ip_ptr;  struct in_ifaddr *ifa = in_dev ? in_dev->ifa_list : 0;  if (ifa)    {      *addr = ifa->ifa_local;      *netmask = ifa->ifa_mask;      *peer = ifa->ifa_address;      *broadcast = ifa->ifa_broadcast;    }  else    *addr = *netmask = *peer = *broadcast = INADDR_NONE;}#elseint devinet_ioctl(unsigned int cmd, void *arg){	struct ifreq ifr;	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;	struct device *dev;#ifdef CONFIG_IP_ALIAS	char *colon;#endif	int exclusive = 0;	int ret = 0;	/*	 *	Fetch the caller's info block into kernel space	 */	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))		return -EFAULT;	ifr.ifr_name[IFNAMSIZ-1] = 0;#ifdef CONFIG_IP_ALIAS	colon = strchr(ifr.ifr_name, ':');	if (colon)		*colon = 0;#endif#ifdef CONFIG_KMOD	dev_load(ifr.ifr_name);#endif	switch(cmd) {	case SIOCGIFADDR:	/* Get interface address */	case SIOCGIFBRDADDR:	/* Get the broadcast address */	case SIOCGIFDSTADDR:	/* Get the destination address */	case SIOCGIFNETMASK:	/* Get the netmask for the interface */		/* Note that this ioctls will not sleep,		   so that we do not impose a lock.		   One day we will be forced to put shlock here (I mean SMP)		 */		memset(sin, 0, sizeof(*sin));		sin->sin_family = AF_INET;		break;	case SIOCSIFFLAGS:		if (!capable(CAP_NET_ADMIN))			return -EACCES;		rtnl_lock();		exclusive = 1;		break;	case SIOCSIFADDR:	/* Set interface address (and family) */	case SIOCSIFBRDADDR:	/* Set the broadcast address */	case SIOCSIFDSTADDR:	/* Set the destination address */	case SIOCSIFNETMASK: 	/* Set the netmask for the interface */		if (!capable(CAP_NET_ADMIN))			return -EACCES;		if (sin->sin_family != AF_INET)			return -EINVAL;		rtnl_lock();		exclusive = 1;		break;	default:		return -EINVAL;	}	if ((dev = dev_get(ifr.ifr_name)) == NULL) {		ret = -ENODEV;		goto done;	}#ifdef CONFIG_IP_ALIAS	if (colon)		*colon = ':';#endif	if ((in_dev=dev->ip_ptr) != NULL) {		for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next)			if (strcmp(ifr.ifr_name, ifa->ifa_label) == 0)				break;	}	if (ifa == NULL && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS) {		ret = -EADDRNOTAVAIL;		goto done;	}

⌨️ 快捷键说明

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