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

📄 dn_dev.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
int dn_dev_ioctl(unsigned int cmd, void __user *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 ret = 0;	if (copy_from_user(ifr, arg, DN_IFREQ_SIZE))		return -EFAULT;	ifr->ifr_name[IFNAMSIZ-1] = 0;#ifdef CONFIG_KMOD	dev_load(&init_net, 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;			break;		default:			return -EINVAL;	}	rtnl_lock();	if ((dev = __dev_get_by_name(&init_net, 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:			*((__le16 *)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 = ifa->ifa_address = dn_saddr2dn(sdn);			ret = dn_dev_set_ifa(dev, ifa);	}done:	rtnl_unlock();	return ret;rarok:	if (copy_to_user(arg, ifr, DN_IFREQ_SIZE))		ret = -EFAULT;	goto done;}struct net_device *dn_dev_get_default(void){	struct net_device *dev;	read_lock(&dndev_lock);	dev = decnet_default_device;	if (dev) {		if (dev->dn_ptr)			dev_hold(dev);		else			dev = NULL;	}	read_unlock(&dndev_lock);	return dev;}int dn_dev_set_default(struct net_device *dev, int force){	struct net_device *old = NULL;	int rv = -EBUSY;	if (!dev->dn_ptr)		return -ENODEV;	write_lock(&dndev_lock);	if (force || decnet_default_device == NULL) {		old = decnet_default_device;		decnet_default_device = dev;		rv = 0;	}	write_unlock(&dndev_lock);	if (old)		dev_put(old);	return rv;}static void dn_dev_check_default(struct net_device *dev){	write_lock(&dndev_lock);	if (dev == decnet_default_device) {		decnet_default_device = NULL;	} else {		dev = NULL;	}	write_unlock(&dndev_lock);	if (dev)		dev_put(dev);}static struct dn_dev *dn_dev_by_index(int ifindex){	struct net_device *dev;	struct dn_dev *dn_dev = NULL;	dev = dev_get_by_index(&init_net, ifindex);	if (dev) {		dn_dev = dev->dn_ptr;		dev_put(dev);	}	return dn_dev;}static const struct nla_policy dn_ifa_policy[IFA_MAX+1] = {	[IFA_ADDRESS]		= { .type = NLA_U16 },	[IFA_LOCAL]		= { .type = NLA_U16 },	[IFA_LABEL]		= { .type = NLA_STRING,				    .len = IFNAMSIZ - 1 },};static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){	struct nlattr *tb[IFA_MAX+1];	struct dn_dev *dn_db;	struct ifaddrmsg *ifm;	struct dn_ifaddr *ifa, **ifap;	int err;	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy);	if (err < 0)		goto errout;	err = -ENODEV;	ifm = nlmsg_data(nlh);	if ((dn_db = dn_dev_by_index(ifm->ifa_index)) == NULL)		goto errout;	err = -EADDRNOTAVAIL;	for (ifap = &dn_db->ifa_list; (ifa = *ifap); ifap = &ifa->ifa_next) {		if (tb[IFA_LOCAL] &&		    nla_memcmp(tb[IFA_LOCAL], &ifa->ifa_local, 2))			continue;		if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))			continue;		dn_dev_del_ifa(dn_db, ifap, 1);		return 0;	}errout:	return err;}static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg){	struct nlattr *tb[IFA_MAX+1];	struct net_device *dev;	struct dn_dev *dn_db;	struct ifaddrmsg *ifm;	struct dn_ifaddr *ifa;	int err;	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, dn_ifa_policy);	if (err < 0)		return err;	if (tb[IFA_LOCAL] == NULL)		return -EINVAL;	ifm = nlmsg_data(nlh);	if ((dev = __dev_get_by_index(&init_net, 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;	if (tb[IFA_ADDRESS] == NULL)		tb[IFA_ADDRESS] = tb[IFA_LOCAL];	ifa->ifa_local = nla_get_le16(tb[IFA_LOCAL]);	ifa->ifa_address = nla_get_le16(tb[IFA_ADDRESS]);	ifa->ifa_flags = ifm->ifa_flags;	ifa->ifa_scope = ifm->ifa_scope;	ifa->ifa_dev = dn_db;	if (tb[IFA_LABEL])		nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);	else		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);	err = dn_dev_insert_ifa(dn_db, ifa);	if (err)		dn_dev_free_ifa(ifa);	return err;}static inline size_t dn_ifaddr_nlmsg_size(void){	return NLMSG_ALIGN(sizeof(struct ifaddrmsg))	       + nla_total_size(IFNAMSIZ) /* IFA_LABEL */	       + nla_total_size(2) /* IFA_ADDRESS */	       + nla_total_size(2); /* IFA_LOCAL */}static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_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_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;	if (ifa->ifa_address)		NLA_PUT_LE16(skb, IFA_ADDRESS, ifa->ifa_address);	if (ifa->ifa_local)		NLA_PUT_LE16(skb, IFA_LOCAL, ifa->ifa_local);	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 void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa){	struct sk_buff *skb;	int err = -ENOBUFS;	skb = alloc_skb(dn_ifaddr_nlmsg_size(), GFP_KERNEL);	if (skb == NULL)		goto errout;	err = dn_nl_fill_ifaddr(skb, ifa, 0, 0, event, 0);	if (err < 0) {		/* -EMSGSIZE implies BUG in dn_ifaddr_nlmsg_size() */		WARN_ON(err == -EMSGSIZE);		kfree_skb(skb);		goto errout;	}	err = rtnl_notify(skb, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);errout:	if (err < 0)		rtnl_set_sk_err(RTNLGRP_DECnet_IFADDR, err);}static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb){	int idx, dn_idx = 0, skip_ndevs, skip_naddr;	struct net_device *dev;	struct dn_dev *dn_db;	struct dn_ifaddr *ifa;	skip_ndevs = cb->args[0];	skip_naddr = cb->args[1];	idx = 0;	for_each_netdev(&init_net, dev) {		if (idx < skip_ndevs)			goto cont;		else if (idx > skip_ndevs) {			/* Only skip over addresses for first dev dumped			 * in this iteration (idx == skip_ndevs) */			skip_naddr = 0;		}		if ((dn_db = dev->dn_ptr) == NULL)			goto cont;		for (ifa = dn_db->ifa_list, dn_idx = 0; ifa;		     ifa = ifa->ifa_next, dn_idx++) {			if (dn_idx < skip_naddr)				continue;			if (dn_nl_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] = dn_idx;	return skb->len;}static int dn_dev_get_first(struct net_device *dev, __le16 *addr){	struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;	struct dn_ifaddr *ifa;	int rv = -ENODEV;	if (dn_db == NULL)		goto out;	ifa = dn_db->ifa_list;	if (ifa != NULL) {		*addr = ifa->ifa_local;		rv = 0;	}out:	return rv;}/* * Find a default address to bind to. * * This is one of those areas where the initial VMS concepts don't really * map onto the Linux concepts, and since we introduced multiple addresses * per interface we have to cope with slightly odd ways of finding out what * "our address" really is. Mostly it's not a problem; for this we just guess * a sensible default. Eventually the routing code will take care of all the * nasties for us I hope. */int dn_dev_bind_default(__le16 *addr){	struct net_device *dev;	int rv;	dev = dn_dev_get_default();last_chance:	if (dev) {		read_lock(&dev_base_lock);		rv = dn_dev_get_first(dev, addr);		read_unlock(&dev_base_lock);		dev_put(dev);		if (rv == 0 || dev == init_net.loopback_dev)			return rv;	}	dev = init_net.loopback_dev;	dev_hold(dev);	goto last_chance;}static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa){	struct endnode_hello_message *msg;	struct sk_buff *skb = NULL;	__le16 *pktlen;	struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;	if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL)		return;	skb->dev = dev;	msg = (struct endnode_hello_message *)skb_put(skb,sizeof(*msg));	msg->msgflg  = 0x0D;	memcpy(msg->tiver, dn_eco_version, 3);	dn_dn2eth(msg->id, ifa->ifa_local);	msg->iinfo   = DN_RT_INFO_ENDN;	msg->blksize = dn_htons(mtu2blksize(dev));	msg->area    = 0x00;	memset(msg->seed, 0, 8);	memcpy(msg->neighbor, dn_hiord, ETH_ALEN);	if (dn_db->router) {		struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;		dn_dn2eth(msg->neighbor, dn->addr);	}	msg->timer   = dn_htons((unsigned short)dn_db->parms.t3);	msg->mpd     = 0x00;	msg->datalen = 0x02;	memset(msg->data, 0xAA, 2);	pktlen = (__le16 *)skb_push(skb,2);	*pktlen = dn_htons(skb->len - 2);	skb_reset_network_header(skb);	dn_rt_finish_output(skb, dn_rt_all_rt_mcast, msg->id);}#define DRDELAY (5 * HZ)static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db, struct dn_ifaddr *ifa){	/* First check time since device went up */	if ((jiffies - dn_db->uptime) < DRDELAY)		return 0;	/* If there is no router, then yes... */	if (!dn_db->router)		return 1;	/* otherwise only if we have a higher priority or.. */	if (dn->priority < dn_db->parms.priority)		return 1;	/* if we have equal priority and a higher node number */	if (dn->priority != dn_db->parms.priority)		return 0;	if (dn_ntohs(dn->addr) < dn_ntohs(ifa->ifa_local))		return 1;	return 0;}static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa){	int n;	struct dn_dev *dn_db = dev->dn_ptr;	struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;	struct sk_buff *skb;	size_t size;	unsigned char *ptr;	unsigned char *i1, *i2;	__le16 *pktlen;	char *src;	if (mtu2blksize(dev) < (26 + 7))		return;	n = mtu2blksize(dev) - 26;	n /= 7;	if (n > 32)		n = 32;	size = 2 + 26 + 7 * n;	if ((skb = dn_alloc_skb(NULL, size, GFP_ATOMIC)) == NULL)		return;	skb->dev = dev;	ptr = skb_put(skb, size);	*ptr++ = DN_RT_PKT_CNTL | DN_RT_PKT_ERTH;	*ptr++ = 2; /* ECO */	*ptr++ = 0;	*ptr++ = 0;	dn_dn2eth(ptr, ifa->ifa_local);	src = ptr;	ptr += ETH_ALEN;	*ptr++ = dn_db->parms.forwarding == 1 ?			DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;	*((__le16 *)ptr) = dn_htons(mtu2blksize(dev));	ptr += 2;	*ptr++ = dn_db->parms.priority; /* Priority */	*ptr++ = 0; /* Area: Reserved */	*((__le16 *)ptr) = dn_htons((unsigned short)dn_db->parms.t3);	ptr += 2;	*ptr++ = 0; /* MPD: Reserved */	i1 = ptr++;	memset(ptr, 0, 7); /* Name: Reserved */

⌨️ 快捷键说明

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