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

📄 dn_dev.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
	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(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(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 = 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(dev);	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(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;	int rv;	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;	if (!rta[IFA_ADDRESS - 1])		rta[IFA_ADDRESS - 1] = rta[IFA_LOCAL - 1];	memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL-1]), 2);	memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS-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);	rv = dn_dev_insert_ifa(dn_db, ifa);	if (rv)		dn_dev_free_ifa(ifa);	return rv;}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;	if (ifa->ifa_address)		RTA_PUT(skb, IFA_ADDRESS, 2, &ifa->ifa_address);	if (ifa->ifa_local)		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);}static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb){	int idx, dn_idx;	int s_idx, s_dn_idx;	struct net_device *dev;	struct dn_dev *dn_db;	struct dn_ifaddr *ifa;	s_idx = cb->args[0];	s_dn_idx = dn_idx = cb->args[1];	read_lock(&dev_base_lock);	for(dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {		if (idx < s_idx)			continue;		if (idx > s_idx)			s_dn_idx = 0;		if ((dn_db = dev->dn_ptr) == NULL)			continue;		for(ifa = dn_db->ifa_list, dn_idx = 0; ifa; ifa = ifa->ifa_next, dn_idx++) {			if (dn_idx < s_dn_idx)				continue;			if (dn_dev_fill_ifaddr(skb, ifa,					       NETLINK_CB(cb->skb).pid,					       cb->nlh->nlmsg_seq,					       RTM_NEWADDR) <= 0)				goto done;		}	}done:	read_unlock(&dev_base_lock);	cb->args[0] = idx;	cb->args[1] = dn_idx;	return skb->len;}static int dn_dev_get_first(struct net_device *dev, dn_address *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(dn_address *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 == &loopback_dev)			return rv;	}	dev = &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;        unsigned short int *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 = (unsigned short *)skb_push(skb,2);        *pktlen = dn_htons(skb->len - 2);	skb->nh.raw = skb->data;	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;	unsigned short *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;	*((unsigned short *)ptr) = dn_htons(mtu2blksize(dev));	ptr += 2;	*ptr++ = dn_db->parms.priority; /* Priority */ 	*ptr++ = 0; /* Area: Reserved */	*((unsigned short *)ptr) = dn_htons((unsigned short)dn_db->parms.t3);	ptr += 2;	*ptr++ = 0; /* MPD: Reserved */	i1 = ptr++;	memset(ptr, 0, 7); /* Name: Reserved */	ptr += 7;	i2 = ptr++;	n = dn_neigh_elist(dev, ptr, n);	*i2 = 7 * n;	*i1 = 8 + *i2;	skb_trim(skb, (27 + *i2));	pktlen = (unsigned short *)skb_push(skb, 2);	*pktlen = dn_htons(skb->len - 2);	skb->nh.raw = skb->data;	if (dn_am_i_a_router(dn, dn_db, ifa)) {		struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);		if (skb2) {			dn_rt_finish_output(skb2, dn_rt_all_end_mcast, src);		}	}	dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);}static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa){	struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;	if (dn_db->parms.forwarding == 0)		dn_send_endnode_hello(dev, ifa);	else		dn_send_router_hello(dev, ifa);}static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa){	int tdlen = 16;	int size = dev->hard_header_len + 2 + 4 + tdlen;	struct sk_buff *skb = dn_alloc_skb(NULL, size, GFP_ATOMIC);	int i;	unsigned char *ptr;	char src[ETH_ALEN];	if (skb == NULL)		return ;	skb->dev = dev;	skb_push(skb, dev->hard_header_len);	ptr = skb_put(skb, 2 + 4 + tdlen);	*ptr++ = DN_RT_PKT_HELO;	*((dn_address *)ptr) = ifa->ifa_local;	ptr += 2;	*ptr++ = tdlen;	for(i = 0; i < tdlen; i++)		*ptr++ = 0252;	dn_dn2eth(src, ifa->ifa_local);	dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);}static int dn_eth_up(struct net_device *dev){	struct dn_dev *dn_db = dev->dn_ptr;

⌨️ 快捷键说明

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