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

📄 ddp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	return atr ? atr->dev : NULL;}/* Set up a default router */static void atrtr_set_default(struct net_device *dev){	atrtr_default.dev	     = dev;	atrtr_default.flags	     = RTF_UP;	atrtr_default.gateway.s_net  = htons(0);	atrtr_default.gateway.s_node = 0;}/* * Add a router. Basically make sure it looks valid and stuff the * entry in the list. While it uses netranges we always set them to one * entry to work like netatalk. */static int atrtr_create(struct rtentry *r, struct net_device *devhint){	struct sockaddr_at *ta = (struct sockaddr_at *)&r->rt_dst;	struct sockaddr_at *ga = (struct sockaddr_at *)&r->rt_gateway;	struct atalk_route *rt;	struct atalk_iface *iface, *riface;	int retval = -EINVAL;	/*	 * Fixme: Raise/Lower a routing change semaphore for these	 * operations.	 */	/* Validate the request */	if (ta->sat_family != AF_APPLETALK ||	    (!devhint && ga->sat_family != AF_APPLETALK))		goto out;	/* Now walk the routing table and make our decisions */	write_lock_bh(&atalk_routes_lock);	for (rt = atalk_routes; rt; rt = rt->next) {		if (r->rt_flags != rt->flags)			continue;		if (ta->sat_addr.s_net == rt->target.s_net) {			if (!(rt->flags & RTF_HOST))				break;			if (ta->sat_addr.s_node == rt->target.s_node)				break;		}	}	if (!devhint) {		riface = NULL;		read_lock_bh(&atalk_interfaces_lock);		for (iface = atalk_interfaces; iface; iface = iface->next) {			if (!riface &&			    ntohs(ga->sat_addr.s_net) >=					ntohs(iface->nets.nr_firstnet) &&			    ntohs(ga->sat_addr.s_net) <=					ntohs(iface->nets.nr_lastnet))				riface = iface;			if (ga->sat_addr.s_net == iface->address.s_net &&			    ga->sat_addr.s_node == iface->address.s_node)				riface = iface;		}		read_unlock_bh(&atalk_interfaces_lock);		retval = -ENETUNREACH;		if (!riface)			goto out_unlock;		devhint = riface->dev;	}	if (!rt) {		rt = kzalloc(sizeof(*rt), GFP_ATOMIC);		retval = -ENOBUFS;		if (!rt)			goto out_unlock;		rt->next = atalk_routes;		atalk_routes = rt;	}	/* Fill in the routing entry */	rt->target  = ta->sat_addr;	dev_hold(devhint);	rt->dev     = devhint;	rt->flags   = r->rt_flags;	rt->gateway = ga->sat_addr;	retval = 0;out_unlock:	write_unlock_bh(&atalk_routes_lock);out:	return retval;}/* Delete a route. Find it and discard it */static int atrtr_delete(struct atalk_addr * addr){	struct atalk_route **r = &atalk_routes;	int retval = 0;	struct atalk_route *tmp;	write_lock_bh(&atalk_routes_lock);	while ((tmp = *r) != NULL) {		if (tmp->target.s_net == addr->s_net &&		    (!(tmp->flags&RTF_GATEWAY) ||		     tmp->target.s_node == addr->s_node)) {			*r = tmp->next;			dev_put(tmp->dev);			kfree(tmp);			goto out;		}		r = &tmp->next;	}	retval = -ENOENT;out:	write_unlock_bh(&atalk_routes_lock);	return retval;}/* * Called when a device is downed. Just throw away any routes * via it. */static void atrtr_device_down(struct net_device *dev){	struct atalk_route **r = &atalk_routes;	struct atalk_route *tmp;	write_lock_bh(&atalk_routes_lock);	while ((tmp = *r) != NULL) {		if (tmp->dev == dev) {			*r = tmp->next;			dev_put(dev);			kfree(tmp);		} else			r = &tmp->next;	}	write_unlock_bh(&atalk_routes_lock);	if (atrtr_default.dev == dev)		atrtr_set_default(NULL);}/* Actually down the interface */static inline void atalk_dev_down(struct net_device *dev){	atrtr_device_down(dev);	/* Remove all routes for the device */	aarp_device_down(dev);	/* Remove AARP entries for the device */	atif_drop_device(dev);	/* Remove the device */}/* * A device event has occurred. Watch for devices going down and * delete our use of them (iface and route). */static int ddp_device_event(struct notifier_block *this, unsigned long event,			    void *ptr){	struct net_device *dev = ptr;	if (dev->nd_net != &init_net)		return NOTIFY_DONE;	if (event == NETDEV_DOWN)		/* Discard any use of this */		atalk_dev_down(dev);	return NOTIFY_DONE;}/* ioctl calls. Shouldn't even need touching *//* Device configuration ioctl calls */static int atif_ioctl(int cmd, void __user *arg){	static char aarp_mcast[6] = { 0x09, 0x00, 0x00, 0xFF, 0xFF, 0xFF };	struct ifreq atreq;	struct atalk_netrange *nr;	struct sockaddr_at *sa;	struct net_device *dev;	struct atalk_iface *atif;	int ct;	int limit;	struct rtentry rtdef;	int add_route;	if (copy_from_user(&atreq, arg, sizeof(atreq)))		return -EFAULT;	dev = __dev_get_by_name(&init_net, atreq.ifr_name);	if (!dev)		return -ENODEV;	sa = (struct sockaddr_at *)&atreq.ifr_addr;	atif = atalk_find_dev(dev);	switch (cmd) {		case SIOCSIFADDR:			if (!capable(CAP_NET_ADMIN))				return -EPERM;			if (sa->sat_family != AF_APPLETALK)				return -EINVAL;			if (dev->type != ARPHRD_ETHER &&			    dev->type != ARPHRD_LOOPBACK &&			    dev->type != ARPHRD_LOCALTLK &&			    dev->type != ARPHRD_PPP)				return -EPROTONOSUPPORT;			nr = (struct atalk_netrange *)&sa->sat_zero[0];			add_route = 1;			/*			 * if this is a point-to-point iface, and we already			 * have an iface for this AppleTalk address, then we			 * should not add a route			 */			if ((dev->flags & IFF_POINTOPOINT) &&			    atalk_find_interface(sa->sat_addr.s_net,						 sa->sat_addr.s_node)) {				printk(KERN_DEBUG "AppleTalk: point-to-point "						  "interface added with "						  "existing address\n");				add_route = 0;			}			/*			 * Phase 1 is fine on LocalTalk but we don't do			 * EtherTalk phase 1. Anyone wanting to add it go ahead.			 */			if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)				return -EPROTONOSUPPORT;			if (sa->sat_addr.s_node == ATADDR_BCAST ||			    sa->sat_addr.s_node == 254)				return -EINVAL;			if (atif) {				/* Already setting address */				if (atif->status & ATIF_PROBE)					return -EBUSY;				atif->address.s_net  = sa->sat_addr.s_net;				atif->address.s_node = sa->sat_addr.s_node;				atrtr_device_down(dev);	/* Flush old routes */			} else {				atif = atif_add_device(dev, &sa->sat_addr);				if (!atif)					return -ENOMEM;			}			atif->nets = *nr;			/*			 * Check if the chosen address is used. If so we			 * error and atalkd will try another.			 */			if (!(dev->flags & IFF_LOOPBACK) &&			    !(dev->flags & IFF_POINTOPOINT) &&			    atif_probe_device(atif) < 0) {				atif_drop_device(dev);				return -EADDRINUSE;			}			/* Hey it worked - add the direct routes */			sa = (struct sockaddr_at *)&rtdef.rt_gateway;			sa->sat_family = AF_APPLETALK;			sa->sat_addr.s_net  = atif->address.s_net;			sa->sat_addr.s_node = atif->address.s_node;			sa = (struct sockaddr_at *)&rtdef.rt_dst;			rtdef.rt_flags = RTF_UP;			sa->sat_family = AF_APPLETALK;			sa->sat_addr.s_node = ATADDR_ANYNODE;			if (dev->flags & IFF_LOOPBACK ||			    dev->flags & IFF_POINTOPOINT)				rtdef.rt_flags |= RTF_HOST;			/* Routerless initial state */			if (nr->nr_firstnet == htons(0) &&			    nr->nr_lastnet == htons(0xFFFE)) {				sa->sat_addr.s_net = atif->address.s_net;				atrtr_create(&rtdef, dev);				atrtr_set_default(dev);			} else {				limit = ntohs(nr->nr_lastnet);				if (limit - ntohs(nr->nr_firstnet) > 4096) {					printk(KERN_WARNING "Too many routes/"							    "iface.\n");					return -EINVAL;				}				if (add_route)					for (ct = ntohs(nr->nr_firstnet);					     ct <= limit; ct++) {						sa->sat_addr.s_net = htons(ct);						atrtr_create(&rtdef, dev);					}			}			dev_mc_add(dev, aarp_mcast, 6, 1);			return 0;		case SIOCGIFADDR:			if (!atif)				return -EADDRNOTAVAIL;			sa->sat_family = AF_APPLETALK;			sa->sat_addr = atif->address;			break;		case SIOCGIFBRDADDR:			if (!atif)				return -EADDRNOTAVAIL;			sa->sat_family = AF_APPLETALK;			sa->sat_addr.s_net = atif->address.s_net;			sa->sat_addr.s_node = ATADDR_BCAST;			break;		case SIOCATALKDIFADDR:		case SIOCDIFADDR:			if (!capable(CAP_NET_ADMIN))				return -EPERM;			if (sa->sat_family != AF_APPLETALK)				return -EINVAL;			atalk_dev_down(dev);			break;		case SIOCSARP:			if (!capable(CAP_NET_ADMIN))				return -EPERM;			if (sa->sat_family != AF_APPLETALK)				return -EINVAL;			if (!atif)				return -EADDRNOTAVAIL;			/*			 * for now, we only support proxy AARP on ELAP;			 * we should be able to do it for LocalTalk, too.			 */			if (dev->type != ARPHRD_ETHER)				return -EPROTONOSUPPORT;			/*			 * atif points to the current interface on this network;			 * we aren't concerned about its current status (at			 * least for now), but it has all the settings about			 * the network we're going to probe. Consequently, it			 * must exist.			 */			if (!atif)				return -EADDRNOTAVAIL;			nr = (struct atalk_netrange *)&(atif->nets);			/*			 * Phase 1 is fine on Localtalk but we don't do			 * Ethertalk phase 1. Anyone wanting to add it go ahead.			 */			if (dev->type == ARPHRD_ETHER && nr->nr_phase != 2)				return -EPROTONOSUPPORT;			if (sa->sat_addr.s_node == ATADDR_BCAST ||			    sa->sat_addr.s_node == 254)				return -EINVAL;			/*			 * Check if the chosen address is used. If so we			 * error and ATCP will try another.			 */			if (atif_proxy_probe_device(atif, &(sa->sat_addr)) < 0)				return -EADDRINUSE;			/*			 * We now have an address on the local network, and			 * the AARP code will defend it for us until we take it			 * down. We don't set up any routes right now, because			 * ATCP will install them manually via SIOCADDRT.			 */			break;		case SIOCDARP:			if (!capable(CAP_NET_ADMIN))				return -EPERM;			if (sa->sat_family != AF_APPLETALK)				return -EINVAL;			if (!atif)				return -EADDRNOTAVAIL;			/* give to aarp module to remove proxy entry */			aarp_proxy_remove(atif->dev, &(sa->sat_addr));			return 0;	}	return copy_to_user(arg, &atreq, sizeof(atreq)) ? -EFAULT : 0;}/* Routing ioctl() calls */static int atrtr_ioctl(unsigned int cmd, void __user *arg){	struct rtentry rt;	if (copy_from_user(&rt, arg, sizeof(rt)))		return -EFAULT;	switch (cmd) {		case SIOCDELRT:			if (rt.rt_dst.sa_family != AF_APPLETALK)				return -EINVAL;			return atrtr_delete(&((struct sockaddr_at *)						&rt.rt_dst)->sat_addr);		case SIOCADDRT: {			struct net_device *dev = NULL;			if (rt.rt_dev) {				char name[IFNAMSIZ];				if (copy_from_user(name, rt.rt_dev, IFNAMSIZ-1))					return -EFAULT;				name[IFNAMSIZ-1] = '\0';				dev = __dev_get_by_name(&init_net, name);				if (!dev)					return -ENODEV;			}			return atrtr_create(&rt, dev);		}	}	return -EINVAL;}/**************************************************************************\*                                                                          ** Handling for system calls applied via the various interfaces to an       ** AppleTalk socket object.                                                 **                                                                          *\**************************************************************************//* * Checksum: This is 'optional'. It's quite likely also a good * candidate for assembler hackery 8) */static unsigned long atalk_sum_partial(const unsigned char *data,				       int len, unsigned long sum){	/* This ought to be unwrapped neatly. I'll trust gcc for now */	while (len--) {		sum += *data;		sum <<= 1;		if (sum & 0x10000) {			sum++;			sum &= 0xffff;		}		data++;	}	return sum;}/*  Checksum skb data --  similar to skb_checksum  */static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset,				   int len, unsigned long sum){	int start = skb_headlen(skb);	int i, copy;	/* checksum stuff in header space */	if ( (copy = start - offset) > 0) {		if (copy > len)			copy = len;		sum = atalk_sum_partial(skb->data + offset, copy, sum);		if ( (len -= copy) == 0)			return sum;		offset += copy;	}	/* checksum stuff in frags */	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {		int end;		BUG_TRAP(start <= offset + len);		end = start + skb_shinfo(skb)->frags[i].size;		if ((copy = end - offset) > 0) {			u8 *vaddr;			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];			if (copy > len)				copy = len;			vaddr = kmap_skb_frag(frag);

⌨️ 快捷键说明

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