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

📄 dn_dev.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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 - its a user space issue now *         Patrick Caulfield : Fixed router hello message format */#include <linux/config.h>#include <linux/net.h>#include <linux/netdevice.h>#include <linux/proc_fs.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/if_arp.h>#include <linux/if_ether.h>#include <linux/init.h>#include <linux/skbuff.h>#include <linux/rtnetlink.h>#include <linux/sysctl.h>#include <asm/uaccess.h>#include <net/neighbour.h>#include <net/dst.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;struct net_device *decnet_default_device = NULL;static struct dn_dev *dn_dev_create(struct net_device *dev, int *err);static void dn_dev_delete(struct net_device *dev);#ifdef CONFIG_RTNETLINKstatic void rtmsg_ifa(int event, struct dn_ifaddr *ifa);#endifstatic int dn_eth_up(struct net_device *);static void dn_send_brd_hello(struct net_device *dev);#if 0static void dn_send_ptp_hello(struct net_device *dev);#endifstatic struct dn_dev_parms dn_dev_list[] =  {{	ARPHRD_ETHER, /* Ethernet */	DN_DEV_BCAST,	DN_DEV_S_RU,	0,	1498,	1,	10,	0,	"ethernet",	NET_DECNET_CONF_ETHER,	dn_eth_up,	NULL,	dn_send_brd_hello,	NULL},{	ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */	DN_DEV_BCAST,	DN_DEV_S_RU,	0,	1400,	1,	10,	0,	"ipgre",	NET_DECNET_CONF_GRE,	NULL,	NULL,	dn_send_brd_hello,	NULL},#if 0{	ARPHRD_X25, /* Bog standard X.25 */	DN_DEV_UCAST,	DN_DEV_S_DS,	0,	230,	1,	120,	0,	"x25",	NET_DECNET_CONF_X25,	NULL,	NULL,	dn_send_ptp_hello,	NULL},#endif#if 0{	ARPHRD_PPP, /* DECnet over PPP */	DN_DEV_BCAST,	DN_DEV_S_RU,	0,	230,	1,	10,	0,	"ppp",	NET_DECNET_CONF_PPP,	NULL,	NULL,	dn_send_brd_hello,	NULL},#endif#if 0{	ARPHRD_DDCMP, /* DECnet over DDCMP */	DN_DEV_UCAST,	DN_DEV_S_DS,	0,	230,	1,	120,	0,	"ddcmp",	NET_DECNET_CONF_DDCMP,	NULL,	NULL,	dn_send_ptp_hello,	NULL},#endif{	ARPHRD_LOOPBACK, /* Loopback interface - always last */	DN_DEV_BCAST,	DN_DEV_S_RU,	0,	1498,	1,	10,	0,	"loopback",	NET_DECNET_CONF_LOOPBACK,	NULL,	NULL,	dn_send_brd_hello,	NULL}};#define DN_DEV_LIST_SIZE (sizeof(dn_dev_list)/sizeof(struct dn_dev_parms))#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[] = { 0 };static int max_priority[] = { 127 }; /* From DECnet spec */static int dn_forwarding_proc(ctl_table *, int, struct file *,			void *, size_t *);static int dn_forwarding_sysctl(ctl_table *table, int *name, int nlen,			void *oldval, size_t *oldlenp,			void *newval, size_t newlen,			void **context);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,	{	{NET_DECNET_CONF_DEV_FORWARDING, "forwarding",	(void *)DN_DEV_PARMS_OFFSET(forwarding),	sizeof(int), 0644, NULL,	dn_forwarding_proc, dn_forwarding_sysctl,	NULL, NULL, NULL},	{NET_DECNET_CONF_DEV_PRIORITY, "priority",	(void *)DN_DEV_PARMS_OFFSET(priority),	sizeof(int), 0644, NULL,	proc_dointvec_minmax, sysctl_intvec,	NULL, &min_priority, &max_priority},	{NET_DECNET_CONF_DEV_T2, "t2", (void *)DN_DEV_PARMS_OFFSET(t2),	sizeof(int), 0644, NULL,	proc_dointvec_minmax, sysctl_intvec,	NULL, &min_t2, &max_t2},	{NET_DECNET_CONF_DEV_T3, "t3", (void *)DN_DEV_PARMS_OFFSET(t3),	sizeof(int), 0644, NULL,	proc_dointvec_minmax, sysctl_intvec,	NULL, &min_t3, &max_t3},	{0}	},	{{0, "", NULL, 0, 0555, dn_dev_sysctl.dn_dev_vars}, {0}},	{{NET_DECNET_CONF, "conf", NULL, 0, 0555, dn_dev_sysctl.dn_dev_dev}, {0}},	{{NET_DECNET, "decnet", NULL, 0, 0555, dn_dev_sysctl.dn_dev_conf_dir}, {0}},	{{CTL_NET, "net", NULL, 0, 0555, 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 = kmalloc(sizeof(*t), GFP_KERNEL);	if (t == NULL)		return;	memcpy(t, &dn_dev_sysctl, sizeof(*t));	for(i = 0; i < (sizeof(t->dn_dev_vars)/sizeof(t->dn_dev_vars[0]) - 1); i++) {		long offset = (long)t->dn_dev_vars[i].data;		t->dn_dev_vars[i].data = ((char *)parms) + offset;		t->dn_dev_vars[i].de = NULL;	}	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_dev[0].de = NULL;	t->dn_dev_conf_dir[0].child = t->dn_dev_dev;	t->dn_dev_conf_dir[0].de = NULL;	t->dn_dev_proto_dir[0].child = t->dn_dev_conf_dir;	t->dn_dev_proto_dir[0].de = NULL;	t->dn_dev_root_dir[0].child = t->dn_dev_proto_dir;	t->dn_dev_root_dir[0].de = NULL;	t->dn_dev_vars[0].extra1 = (void *)dev;	t->sysctl_header = register_sysctl_table(t->dn_dev_root_dir, 0);	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 *buffer, size_t *lenp){#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);	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 *name, int nlen,			void *oldval, size_t *oldlenp,			void *newval, size_t newlen,			void **context){#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;		get_user(value, (int *)newval);		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 struct dn_ifaddr *dn_dev_alloc_ifa(void){	struct dn_ifaddr *ifa;	ifa = kmalloc(sizeof(*ifa), GFP_KERNEL);	if (ifa) {		memset(ifa, 0, sizeof(*ifa));	}	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;	*ifap = ifa1->ifa_next;#ifdef CONFIG_RTNETLINK	rtmsg_ifa(RTM_DELADDR, ifa1);#endif /* CONFIG_RTNETLINK */	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){	/*	 * FIXME: Duplicate check here.	 */	ifa->ifa_next = dn_db->ifa_list;	dn_db->ifa_list = ifa;#ifdef CONFIG_RTNETLINK	rtmsg_ifa(RTM_NEWADDR, ifa);#endif /* CONFIG_RTNETLINK */	return 0;}static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa){	struct dn_dev *dn_db = dev->dn_ptr;	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;	return dn_dev_insert_ifa(dn_db, ifa);}int dn_dev_ioctl(unsigned int cmd, void *arg){	char buffer[DN_IFREQ_SIZE];	struct ifreq *ifr = (struct ifreq *)buffer;	struct sockaddr_dn *sdn = (struct sockaddr_dn *)&ifr->ifr_addr;	struct dn_dev *dn_db;	struct net_device *dev;	struct dn_ifaddr *ifa = NULL, **ifap = NULL;	int exclusive = 0;	int ret = 0;	if (copy_from_user(ifr, arg, DN_IFREQ_SIZE))		return -EFAULT;	ifr->ifr_name[IFNAMSIZ-1] = 0;#ifdef CONFIG_KMOD	dev_load(ifr->ifr_name);#endif	switch(cmd) {		case SIOCGIFADDR:			break;		case SIOCSIFADDR:			if (!capable(CAP_NET_ADMIN))				return -EACCES;			if (sdn->sdn_family != AF_DECnet)				return -EINVAL;			rtnl_lock();			exclusive = 1;			break;		default:			return -EINVAL;	}	if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) {		ret = -ENODEV;		goto done;	}	if ((dn_db = dev->dn_ptr) != NULL) {		for (ifap = &dn_db->ifa_list; (ifa=*ifap) != NULL; ifap = &ifa->ifa_next)			if (strcmp(ifr->ifr_name, ifa->ifa_label) == 0)				break;	}	if (ifa == NULL && cmd != SIOCSIFADDR) {		ret = -EADDRNOTAVAIL;		goto done;	}	switch(cmd) {		case SIOCGIFADDR:			*((dn_address *)sdn->sdn_nodeaddr) = ifa->ifa_local;			goto rarok;		case SIOCSIFADDR:			if (!ifa) {				if ((ifa = dn_dev_alloc_ifa()) == NULL) {					ret = -ENOBUFS;					break;				}				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);			} else {				if (ifa->ifa_local == dn_saddr2dn(sdn))					break;				dn_dev_del_ifa(dn_db, ifap, 0);			}			ifa->ifa_local = dn_saddr2dn(sdn);			ret = dn_dev_set_ifa(dev, ifa);	}done:	if (exclusive)		rtnl_unlock();	return ret;rarok:	if (copy_to_user(arg, ifr, DN_IFREQ_SIZE))		return -EFAULT;	return 0;}#ifdef CONFIG_RTNETLINKstatic struct dn_dev *dn_dev_by_index(int ifindex){	struct net_device *dev;	struct dn_dev *dn_dev = NULL;	dev = dev_get_by_index(ifindex);	if (dev) {		dn_dev = dev->dn_ptr;		dev_put(dev);	}	return dn_dev;}static int dn_dev_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){	struct rtattr **rta = arg;	struct dn_dev *dn_db;	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);	struct dn_ifaddr *ifa, **ifap;	if ((dn_db = dn_dev_by_index(ifm->ifa_index)) == NULL)		return -EADDRNOTAVAIL;	for(ifap = &dn_db->ifa_list; (ifa=*ifap) != NULL; ifap = &ifa->ifa_next) {		void *tmp = rta[IFA_LOCAL-1];		if ((tmp && memcmp(RTA_DATA(tmp), &ifa->ifa_local, 2)) ||				(rta[IFA_LABEL-1] && strcmp(RTA_DATA(rta[IFA_LABEL-1]), ifa->ifa_label)))			continue;		dn_dev_del_ifa(dn_db, ifap, 1);		return 0;	}	return -EADDRNOTAVAIL;}static int dn_dev_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){	struct rtattr **rta = arg;	struct net_device *dev;	struct dn_dev *dn_db;	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);	struct dn_ifaddr *ifa;	if (rta[IFA_LOCAL-1] == NULL)		return -EINVAL;	if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL)		return -ENODEV;	if ((dn_db = dev->dn_ptr) == NULL) {		int err;		dn_db = dn_dev_create(dev, &err);		if (!dn_db)			return err;	}		if ((ifa = dn_dev_alloc_ifa()) == NULL)		return -ENOBUFS;	memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL-1]), 2);	ifa->ifa_flags = ifm->ifa_flags;	ifa->ifa_scope = ifm->ifa_scope;	ifa->ifa_dev = dn_db;	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 dn_dev_insert_ifa(dn_db, ifa);}static int dn_dev_fill_ifaddr(struct sk_buff *skb, struct dn_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_DECnet;	ifm->ifa_prefixlen = 16;	ifm->ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT;	ifm->ifa_scope = ifa->ifa_scope;	ifm->ifa_index = ifa->ifa_dev->dev->ifindex;	RTA_PUT(skb, IFA_LOCAL, 2, &ifa->ifa_local);	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 void rtmsg_ifa(int event, struct dn_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_DECnet_IFADDR, ENOBUFS);		return;	}	if (dn_dev_fill_ifaddr(skb, ifa, 0, 0, event) < 0) {		kfree_skb(skb);		netlink_set_err(rtnl, 0, RTMGRP_DECnet_IFADDR, EINVAL);		return;	}	NETLINK_CB(skb).dst_groups = RTMGRP_DECnet_IFADDR;	netlink_broadcast(rtnl, skb, 0, RTMGRP_DECnet_IFADDR, GFP_KERNEL);

⌨️ 快捷键说明

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