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

📄 ddp.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Find a match for a specific network:node pair */static struct atalk_iface *atalk_find_interface(int net, int node){	struct atalk_iface *iface;	spin_lock_bh(&atalk_iface_lock);	for (iface = atalk_iface_list; iface != NULL; iface = iface->next) {		if ((node == ATADDR_BCAST ||		     node == ATADDR_ANYNODE ||		     iface->address.s_node == node) &&		    iface->address.s_net == net &&		    !(iface->status & ATIF_PROBE))			break;		/* XXXX.0 -- net.0 returns the iface associated with net */		if ((node == ATADDR_ANYNODE) && (net != ATADDR_ANYNET) &&		    (ntohs(iface->nets.nr_firstnet) <= ntohs(net)) &&		    (ntohs(net) <= ntohs(iface->nets.nr_lastnet)))		        break;	}	spin_unlock_bh(&atalk_iface_lock);	return iface;}/* * Find a route for an AppleTalk packet. This ought to get cached in * the socket (later on...). We know about host routes and the fact * that a route must be direct to broadcast. */static struct atalk_route *atrtr_find(struct at_addr *target){	/*	 * we must search through all routes unless we find a 	 * host route, because some host routes might overlap	 * network routes	 */	struct atalk_route *r;	struct atalk_route *net_route = NULL;		read_lock_bh(&atalk_router_lock);	for (r = atalk_router_list; r != NULL; r = r->next) {		if (!(r->flags & RTF_UP))			continue;		if (r->target.s_net == target->s_net) {			if (r->flags & RTF_HOST) {				/*				 * if this host route is for the target,				 * the we're done				 */				if (r->target.s_node == target->s_node)					goto out;			} else {				/*				 * this route will work if there isn't a				 * direct host route, so cache it				 */				net_route = r;			}		}	}		/* 	 * if we found a network route but not a direct host	 * route, then return it	 */	if (net_route != NULL) {		r = net_route;	} else if (atrtr_default.dev) {		r = &atrtr_default;	} else {		/*		 * No route can be found.		 */		r = NULL;	}out:	read_unlock_bh(&atalk_router_lock);	return r;}/* * Given an AppleTalk network, find the device to use. This can be * a simple lookup. */struct net_device *atrtr_get_dev(struct at_addr *sa){	struct atalk_route *atr = atrtr_find(sa);	if (atr == NULL)		return NULL;	else		return atr->dev;}/* * 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;	/*	 * Fixme: Raise/Lower a routing change semaphore for these	 * operations.	 */	/*	 * Validate the request	 */	if (ta->sat_family != AF_APPLETALK)		return -EINVAL;	if (devhint == NULL && ga->sat_family != AF_APPLETALK)		return -EINVAL;	/*	 * Now walk the routing table and make our decisions.	 */	write_lock_bh(&atalk_router_lock);	for (rt = atalk_router_list; rt != NULL; 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 == NULL) {		riface = NULL;		spin_lock_bh(&atalk_iface_lock);		for (iface = atalk_iface_list; iface; iface = iface->next) {			if (riface == NULL &&			    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;		}				spin_unlock_bh(&atalk_iface_lock);		retval = -ENETUNREACH;		if (riface == NULL)			goto out;		devhint = riface->dev;	}	if (rt == NULL) {		rt = (struct atalk_route *)			kmalloc(sizeof(struct atalk_route), GFP_ATOMIC);		retval = -ENOBUFS;		if (rt == NULL)			goto out;		rt->next = atalk_router_list;		atalk_router_list = rt;	}	/*	 * Fill in the routing entry.	 */	rt->target  = ta->sat_addr;	rt->dev     = devhint;	rt->flags   = r->rt_flags;	rt->gateway = ga->sat_addr;	retval = 0;out:	write_unlock_bh(&atalk_router_lock);	return retval;}/* * Delete a route. Find it and discard it. */static int atrtr_delete(struct at_addr * addr){	struct atalk_route **r = &atalk_router_list;	struct atalk_route *tmp;	int retval = 0;	write_lock_bh(&atalk_router_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;			kfree(tmp);			goto out;		}		r = &tmp->next;	}	retval = -ENOENT;out:	write_unlock_bh(&atalk_router_lock);	return retval;}/* * Called when a device is downed. Just throw away any routes * via it. */void atrtr_device_down(struct net_device *dev){	struct atalk_route **r = &atalk_router_list;	struct atalk_route *tmp;	write_lock_bh(&atalk_router_lock);	while ((tmp = *r) != NULL) {		if (tmp->dev == dev) {			*r = tmp->next;			kfree(tmp);		} else {			r = &tmp->next;		}	}	write_unlock_bh(&atalk_router_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){	if (event == NETDEV_DOWN) {		/* Discard any use of this */	        atalk_dev_down((struct net_device *) ptr);	}	return NOTIFY_DONE;}/* * ioctl calls. Shouldn't even need touching. *//* * Device configuration ioctl calls. */int atif_ioctl(int cmd, void *arg){	struct ifreq atreq;	static char aarp_mcast[6] = {0x09, 0x00, 0x00, 0xFF, 0xFF, 0xFF};	struct 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;	if ((dev = __dev_get_by_name(atreq.ifr_name)) == NULL)		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 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 == NULL)					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 == NULL)				return -EADDRNOTAVAIL;			((struct sockaddr_at *)(&atreq.ifr_addr))->sat_family =				AF_APPLETALK;			((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr =				atif->address;			break;		case SIOCGIFBRDADDR:			if (atif == NULL)				return -EADDRNOTAVAIL;			((struct sockaddr_at *)(&atreq.ifr_addr))->sat_family =				AF_APPLETALK;			((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_net =				atif->address.s_net;			((struct sockaddr_at *)(&atreq.ifr_addr))->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 == NULL)                                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 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 == NULL)                                return -EADDRNOTAVAIL;                        /*                         * give to aarp module to remove proxy entry                         */                        aarp_proxy_remove(atif->dev, &(sa->sat_addr));                        return 0;	};	if (copy_to_user(arg, &atreq, sizeof(atreq)))		return -EFAULT;	return 0;}/* * Routing ioctl() calls */static int atrtr_ioctl(unsigned int cmd, void *arg){	struct rtentry rt;	struct net_device *dev = NULL;	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:			/* FIX ME: the name of the device is still in user space, isn't it? */			if (rt.rt_dev != NULL) {				if ((dev = __dev_get_by_name(rt.rt_dev)) == NULL)					return -ENODEV;			}						return atrtr_create(&rt, dev);		default:			return -EINVAL;	};}/* Called from proc fs - just make it print the ifaces neatly */static int atalk_if_get_info(char *buffer, char **start, off_t offset, int length){	struct atalk_iface *iface;

⌨️ 快捷键说明

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