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

📄 dn_dev.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * DECnet       An implementation of the DECnet protocol suite for the LINUX *              operating system.  DECnet is implemented using the  BSD Socket *              interface as the means of communication with the user level. * *              DECnet Device Layer * * Authors:     Steve Whitehouse <SteveW@ACM.org> *              Eduardo Marcelo Serrat <emserrat@geocities.com> * * Changes: *          Steve Whitehouse : Devices now see incoming frames so they *                             can mark on who it came from. *          Steve Whitehouse : Fixed bug in creating neighbours. Each neighbour *                             can now have a device specific setup func. *          Steve Whitehouse : Added /proc/sys/net/decnet/conf/<dev>/ *          Steve Whitehouse : Fixed bug which sometimes killed timer *          Steve Whitehouse : Multiple ifaddr support *          Steve Whitehouse : SIOCGIFCONF is now a compile time option *          Steve Whitehouse : /proc/sys/net/decnet/conf/<sys>/forwarding *          Steve Whitehouse : Removed timer1 - it's a user space issue now *         Patrick Caulfield : Fixed router hello message format *          Steve Whitehouse : Got rid of constant sizes for blksize for *                             devices. All mtu based now. */#include <linux/capability.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/net.h>#include <linux/netdevice.h>#include <linux/proc_fs.h>#include <linux/seq_file.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/if_addr.h>#include <linux/if_arp.h>#include <linux/if_ether.h>#include <linux/skbuff.h>#include <linux/sysctl.h>#include <linux/notifier.h>#include <asm/uaccess.h>#include <asm/system.h>#include <net/net_namespace.h>#include <net/neighbour.h>#include <net/dst.h>#include <net/flow.h>#include <net/fib_rules.h>#include <net/netlink.h>#include <net/dn.h>#include <net/dn_dev.h>#include <net/dn_route.h>#include <net/dn_neigh.h>#include <net/dn_fib.h>#define DN_IFREQ_SIZE (sizeof(struct ifreq) - sizeof(struct sockaddr) + sizeof(struct sockaddr_dn))static char dn_rt_all_end_mcast[ETH_ALEN] = {0xAB,0x00,0x00,0x04,0x00,0x00};static char dn_rt_all_rt_mcast[ETH_ALEN]  = {0xAB,0x00,0x00,0x03,0x00,0x00};static char dn_hiord[ETH_ALEN]            = {0xAA,0x00,0x04,0x00,0x00,0x00};static unsigned char dn_eco_version[3]    = {0x02,0x00,0x00};extern struct neigh_table dn_neigh_table;/* * decnet_address is kept in network order. */__le16 decnet_address = 0;static DEFINE_RWLOCK(dndev_lock);static struct net_device *decnet_default_device;static BLOCKING_NOTIFIER_HEAD(dnaddr_chain);static struct dn_dev *dn_dev_create(struct net_device *dev, int *err);static void dn_dev_delete(struct net_device *dev);static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa);static int dn_eth_up(struct net_device *);static void dn_eth_down(struct net_device *);static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa);static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa);static struct dn_dev_parms dn_dev_list[] =  {{	.type =		ARPHRD_ETHER, /* Ethernet */	.mode =		DN_DEV_BCAST,	.state =	DN_DEV_S_RU,	.t2 =		1,	.t3 =		10,	.name =		"ethernet",	.ctl_name =	NET_DECNET_CONF_ETHER,	.up =		dn_eth_up,	.down = 	dn_eth_down,	.timer3 =	dn_send_brd_hello,},{	.type =		ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */	.mode =		DN_DEV_BCAST,	.state =	DN_DEV_S_RU,	.t2 =		1,	.t3 =		10,	.name =		"ipgre",	.ctl_name =	NET_DECNET_CONF_GRE,	.timer3 =	dn_send_brd_hello,},#if 0{	.type =		ARPHRD_X25, /* Bog standard X.25 */	.mode =		DN_DEV_UCAST,	.state =	DN_DEV_S_DS,	.t2 =		1,	.t3 =		120,	.name =		"x25",	.ctl_name =	NET_DECNET_CONF_X25,	.timer3 =	dn_send_ptp_hello,},#endif#if 0{	.type =		ARPHRD_PPP, /* DECnet over PPP */	.mode =		DN_DEV_BCAST,	.state =	DN_DEV_S_RU,	.t2 =		1,	.t3 =		10,	.name =		"ppp",	.ctl_name =	NET_DECNET_CONF_PPP,	.timer3 =	dn_send_brd_hello,},#endif{	.type =		ARPHRD_DDCMP, /* DECnet over DDCMP */	.mode =		DN_DEV_UCAST,	.state =	DN_DEV_S_DS,	.t2 =		1,	.t3 =		120,	.name =		"ddcmp",	.ctl_name =	NET_DECNET_CONF_DDCMP,	.timer3 =	dn_send_ptp_hello,},{	.type =		ARPHRD_LOOPBACK, /* Loopback interface - always last */	.mode =		DN_DEV_BCAST,	.state =	DN_DEV_S_RU,	.t2 =		1,	.t3 =		10,	.name =		"loopback",	.ctl_name =	NET_DECNET_CONF_LOOPBACK,	.timer3 =	dn_send_brd_hello,}};#define DN_DEV_LIST_SIZE ARRAY_SIZE(dn_dev_list)#define DN_DEV_PARMS_OFFSET(x) ((int) ((char *) &((struct dn_dev_parms *)0)->x))#ifdef CONFIG_SYSCTLstatic int min_t2[] = { 1 };static int max_t2[] = { 60 }; /* No max specified, but this seems sensible */static int min_t3[] = { 1 };static int max_t3[] = { 8191 }; /* Must fit in 16 bits when multiplied by BCT3MULT or T3MULT */static int min_priority[1];static int max_priority[] = { 127 }; /* From DECnet spec */static int dn_forwarding_proc(ctl_table *, int, struct file *,			void __user *, size_t *, loff_t *);static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen,			void __user *oldval, size_t __user *oldlenp,			void __user *newval, size_t newlen);static struct dn_dev_sysctl_table {	struct ctl_table_header *sysctl_header;	ctl_table dn_dev_vars[5];	ctl_table dn_dev_dev[2];	ctl_table dn_dev_conf_dir[2];	ctl_table dn_dev_proto_dir[2];	ctl_table dn_dev_root_dir[2];} dn_dev_sysctl = {	NULL,	{	{		.ctl_name = NET_DECNET_CONF_DEV_FORWARDING,		.procname = "forwarding",		.data = (void *)DN_DEV_PARMS_OFFSET(forwarding),		.maxlen = sizeof(int),		.mode = 0644,		.proc_handler = dn_forwarding_proc,		.strategy = dn_forwarding_sysctl,	},	{		.ctl_name = NET_DECNET_CONF_DEV_PRIORITY,		.procname = "priority",		.data = (void *)DN_DEV_PARMS_OFFSET(priority),		.maxlen = sizeof(int),		.mode = 0644,		.proc_handler = proc_dointvec_minmax,		.strategy = sysctl_intvec,		.extra1 = &min_priority,		.extra2 = &max_priority	},	{		.ctl_name = NET_DECNET_CONF_DEV_T2,		.procname = "t2",		.data = (void *)DN_DEV_PARMS_OFFSET(t2),		.maxlen = sizeof(int),		.mode = 0644,		.proc_handler = proc_dointvec_minmax,		.strategy = sysctl_intvec,		.extra1 = &min_t2,		.extra2 = &max_t2	},	{		.ctl_name = NET_DECNET_CONF_DEV_T3,		.procname = "t3",		.data = (void *)DN_DEV_PARMS_OFFSET(t3),		.maxlen = sizeof(int),		.mode = 0644,		.proc_handler = proc_dointvec_minmax,		.strategy = sysctl_intvec,		.extra1 = &min_t3,		.extra2 = &max_t3	},	{0}	},	{{		.ctl_name = 0,		.procname = "",		.mode = 0555,		.child = dn_dev_sysctl.dn_dev_vars	}, {0}},	{{		.ctl_name = NET_DECNET_CONF,		.procname = "conf",		.mode = 0555,		.child = dn_dev_sysctl.dn_dev_dev	}, {0}},	{{		.ctl_name = NET_DECNET,		.procname = "decnet",		.mode = 0555,		.child = dn_dev_sysctl.dn_dev_conf_dir	}, {0}},	{{		.ctl_name = CTL_NET,		.procname = "net",		.mode = 0555,		.child = dn_dev_sysctl.dn_dev_proto_dir	}, {0}}};static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms){	struct dn_dev_sysctl_table *t;	int i;	t = kmemdup(&dn_dev_sysctl, sizeof(*t), GFP_KERNEL);	if (t == NULL)		return;	for(i = 0; i < ARRAY_SIZE(t->dn_dev_vars) - 1; i++) {		long offset = (long)t->dn_dev_vars[i].data;		t->dn_dev_vars[i].data = ((char *)parms) + offset;	}	if (dev) {		t->dn_dev_dev[0].procname = dev->name;		t->dn_dev_dev[0].ctl_name = dev->ifindex;	} else {		t->dn_dev_dev[0].procname = parms->name;		t->dn_dev_dev[0].ctl_name = parms->ctl_name;	}	t->dn_dev_dev[0].child = t->dn_dev_vars;	t->dn_dev_conf_dir[0].child = t->dn_dev_dev;	t->dn_dev_proto_dir[0].child = t->dn_dev_conf_dir;	t->dn_dev_root_dir[0].child = t->dn_dev_proto_dir;	t->dn_dev_vars[0].extra1 = (void *)dev;	t->sysctl_header = register_sysctl_table(t->dn_dev_root_dir);	if (t->sysctl_header == NULL)		kfree(t);	else		parms->sysctl = t;}static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms){	if (parms->sysctl) {		struct dn_dev_sysctl_table *t = parms->sysctl;		parms->sysctl = NULL;		unregister_sysctl_table(t->sysctl_header);		kfree(t);	}}static int dn_forwarding_proc(ctl_table *table, int write,				struct file *filep,				void __user *buffer,				size_t *lenp, loff_t *ppos){#ifdef CONFIG_DECNET_ROUTER	struct net_device *dev = table->extra1;	struct dn_dev *dn_db;	int err;	int tmp, old;	if (table->extra1 == NULL)		return -EINVAL;	dn_db = dev->dn_ptr;	old = dn_db->parms.forwarding;	err = proc_dointvec(table, write, filep, buffer, lenp, ppos);	if ((err >= 0) && write) {		if (dn_db->parms.forwarding < 0)			dn_db->parms.forwarding = 0;		if (dn_db->parms.forwarding > 2)			dn_db->parms.forwarding = 2;		/*		 * What an ugly hack this is... its works, just. It		 * would be nice if sysctl/proc were just that little		 * bit more flexible so I don't have to write a special		 * routine, or suffer hacks like this - SJW		 */		tmp = dn_db->parms.forwarding;		dn_db->parms.forwarding = old;		if (dn_db->parms.down)			dn_db->parms.down(dev);		dn_db->parms.forwarding = tmp;		if (dn_db->parms.up)			dn_db->parms.up(dev);	}	return err;#else	return -EINVAL;#endif}static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen,			void __user *oldval, size_t __user *oldlenp,			void __user *newval, size_t newlen){#ifdef CONFIG_DECNET_ROUTER	struct net_device *dev = table->extra1;	struct dn_dev *dn_db;	int value;	if (table->extra1 == NULL)		return -EINVAL;	dn_db = dev->dn_ptr;	if (newval && newlen) {		if (newlen != sizeof(int))			return -EINVAL;		if (get_user(value, (int __user *)newval))			return -EFAULT;		if (value < 0)			return -EINVAL;		if (value > 2)			return -EINVAL;		if (dn_db->parms.down)			dn_db->parms.down(dev);		dn_db->parms.forwarding = value;		if (dn_db->parms.up)			dn_db->parms.up(dev);	}	return 0;#else	return -EINVAL;#endif}#else /* CONFIG_SYSCTL */static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms){}static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms){}#endif /* CONFIG_SYSCTL */static inline __u16 mtu2blksize(struct net_device *dev){	u32 blksize = dev->mtu;	if (blksize > 0xffff)		blksize = 0xffff;	if (dev->type == ARPHRD_ETHER ||	    dev->type == ARPHRD_PPP ||	    dev->type == ARPHRD_IPGRE ||	    dev->type == ARPHRD_LOOPBACK)		blksize -= 2;	return (__u16)blksize;}static struct dn_ifaddr *dn_dev_alloc_ifa(void){	struct dn_ifaddr *ifa;	ifa = kzalloc(sizeof(*ifa), GFP_KERNEL);	return ifa;}static __inline__ void dn_dev_free_ifa(struct dn_ifaddr *ifa){	kfree(ifa);}static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int destroy){	struct dn_ifaddr *ifa1 = *ifap;	unsigned char mac_addr[6];	struct net_device *dev = dn_db->dev;	ASSERT_RTNL();	*ifap = ifa1->ifa_next;	if (dn_db->dev->type == ARPHRD_ETHER) {		if (ifa1->ifa_local != dn_eth2dn(dev->dev_addr)) {			dn_dn2eth(mac_addr, ifa1->ifa_local);			dev_mc_delete(dev, mac_addr, ETH_ALEN, 0);		}	}	dn_ifaddr_notify(RTM_DELADDR, ifa1);	blocking_notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1);	if (destroy) {		dn_dev_free_ifa(ifa1);		if (dn_db->ifa_list == NULL)			dn_dev_delete(dn_db->dev);	}}static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa){	struct net_device *dev = dn_db->dev;	struct dn_ifaddr *ifa1;	unsigned char mac_addr[6];	ASSERT_RTNL();	/* Check for duplicates */	for(ifa1 = dn_db->ifa_list; ifa1; ifa1 = ifa1->ifa_next) {		if (ifa1->ifa_local == ifa->ifa_local)			return -EEXIST;	}	if (dev->type == ARPHRD_ETHER) {		if (ifa->ifa_local != dn_eth2dn(dev->dev_addr)) {			dn_dn2eth(mac_addr, ifa->ifa_local);			dev_mc_add(dev, mac_addr, ETH_ALEN, 0);		}	}	ifa->ifa_next = dn_db->ifa_list;	dn_db->ifa_list = ifa;	dn_ifaddr_notify(RTM_NEWADDR, ifa);	blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);	return 0;}static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa){	struct dn_dev *dn_db = dev->dn_ptr;	int rv;	if (dn_db == NULL) {		int err;		dn_db = dn_dev_create(dev, &err);		if (dn_db == NULL)			return err;	}	ifa->ifa_dev = dn_db;	if (dev->flags & IFF_LOOPBACK)		ifa->ifa_scope = RT_SCOPE_HOST;	rv = dn_dev_insert_ifa(dn_db, ifa);	if (rv)		dn_dev_free_ifa(ifa);	return rv;}

⌨️ 快捷键说明

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