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

📄 route.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
字号:
/* * INET		An implementation of the TCP/IP protocol suite for the LINUX *		operating system.  INET is implemented using the  BSD Socket *		interface as the means of communication with the user level. * *		ROUTE - implementation of the IP router. * * Version:	@(#)route.c	1.0.14	05/31/93 * * Authors:	Ross Biro, <bir7@leland.Stanford.Edu> *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * * Fixes: *		Alan Cox	:	Verify area fixes. *		Alan Cox	:	cli() protects routing changes *		Rui Oliveira	:	ICMP routing table updates *		(rco@di.uminho.pt)	Routing table insertion and update *		Linus Torvalds	:	Rewrote bits to be sensible * *		This program is free software; you can redistribute it and/or *		modify it under the terms of the GNU General Public License *		as published by the Free Software Foundation; either version *		2 of the License, or (at your option) any later version. */#include <asm/segment.h>#include <asm/system.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/errno.h>#include <linux/in.h>#include "inet.h"#include "dev.h"#include "ip.h"#include "protocol.h"#include "route.h"#include "tcp.h"#include "skbuff.h"#include "sock.h"#include "arp.h"#include "icmp.h"static struct rtable *rt_base = NULL;static struct rtable *rt_loopback = NULL;/* Dump the contents of a routing table entry. */static voidrt_print(struct rtable *rt){  if (rt == NULL || inet_debug != DBG_RT) return;  printk("RT: %06lx NXT=%06lx FLAGS=0x%02x\n",		(long) rt, (long) rt->rt_next, rt->rt_flags);  printk("    TARGET=%s ", in_ntoa(rt->rt_dst));  printk("GW=%s ", in_ntoa(rt->rt_gateway));  printk("    DEV=%s USE=%ld REF=%d\n",	(rt->rt_dev == NULL) ? "NONE" : rt->rt_dev->name,	rt->rt_use, rt->rt_refcnt);}/* * Remove a routing table entry. */static void rt_del(unsigned long dst){	struct rtable *r, **rp;	unsigned long flags;	DPRINTF((DBG_RT, "RT: flushing for dst %s\n", in_ntoa(dst)));	rp = &rt_base;	save_flags(flags);	cli();	while((r = *rp) != NULL) {		if (r->rt_dst != dst) {			rp = &r->rt_next;			continue;		}		*rp = r->rt_next;		if (rt_loopback == r)			rt_loopback = NULL;		kfree_s(r, sizeof(struct rtable));	} 	restore_flags(flags);}/* * Remove all routing table entries for a device. */void rt_flush(struct device *dev){	struct rtable *r;	struct rtable **rp;	unsigned long flags;	DPRINTF((DBG_RT, "RT: flushing for dev 0x%08lx (%s)\n", (long)dev, dev->name));	rp = &rt_base;	cli();	save_flags(flags);	while ((r = *rp) != NULL) {		if (r->rt_dev != dev) {			rp = &r->rt_next;			continue;		}		*rp = r->rt_next;		if (rt_loopback == r)			rt_loopback = NULL;		kfree_s(r, sizeof(struct rtable));	} 	restore_flags(flags);}/* * Used by 'rt_add()' when we can't get the netmask any other way.. * * If the lower byte or two are zero, we guess the mask based on the * number of zero 8-bit net numbers, otherwise we use the "default" * masks judging by the destination address and our device netmask. */static inline unsigned long default_mask(unsigned long dst){	dst = ntohl(dst);	if (IN_CLASSA(dst))		return htonl(IN_CLASSA_NET);	if (IN_CLASSB(dst))		return htonl(IN_CLASSB_NET);	return htonl(IN_CLASSC_NET);}static unsigned long guess_mask(unsigned long dst, struct device * dev){	unsigned long mask;	if (!dst)		return 0;	mask = default_mask(dst);	if ((dst ^ dev->pa_addr) & mask)		return mask;	return dev->pa_mask;}static inline struct device * get_gw_dev(unsigned long gw){	struct rtable * rt;	for (rt = rt_base ; ; rt = rt->rt_next) {		if (!rt)			return NULL;		if ((gw ^ rt->rt_dst) & rt->rt_mask)			continue;		/* gateways behind gateways are a no-no */		if (rt->rt_flags & RTF_GATEWAY)			return NULL;		return rt->rt_dev;	}}/* * rewrote rt_add(), as the old one was weird. Linus */void rt_add(short flags, unsigned long dst, unsigned long mask,	unsigned long gw, struct device *dev){	struct rtable *r, *rt;	struct rtable **rp;	unsigned long cpuflags;	if (flags & RTF_HOST) {		mask = 0xffffffff;	} else if (!mask) {		if (!((dst ^ dev->pa_addr) & dev->pa_mask)) {			mask = dev->pa_mask;			flags &= ~RTF_GATEWAY;			if (flags & RTF_DYNAMIC) {				/*printk("Dynamic route to my own net rejected\n");*/				return;			}		} else			mask = guess_mask(dst, dev);		dst &= mask;	}	if (gw == dev->pa_addr)		flags &= ~RTF_GATEWAY;	if (flags & RTF_GATEWAY) {		/* don't try to add a gateway we can't reach.. */		if (dev != get_gw_dev(gw))			return;		flags |= RTF_GATEWAY;	} else		gw = 0;	/* Allocate an entry. */	rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC);	if (rt == NULL) {		DPRINTF((DBG_RT, "RT: no memory for new route!\n"));		return;	}	memset(rt, 0, sizeof(struct rtable));	rt->rt_flags = flags | RTF_UP;	rt->rt_dst = dst;	rt->rt_dev = dev;	rt->rt_gateway = gw;	rt->rt_mask = mask;	rt->rt_mtu = dev->mtu;	rt_print(rt);	/*	 * What we have to do is loop though this until we have	 * found the first address which has a higher generality than	 * the one in rt.  Then we can put rt in right before it.	 */	save_flags(cpuflags);	cli();	/* remove old route if we are getting a duplicate. */	rp = &rt_base;	while ((r = *rp) != NULL) {		if (r->rt_dst != dst) {			rp = &r->rt_next;			continue;		}		*rp = r->rt_next;		if (rt_loopback == r)			rt_loopback = NULL;		kfree_s(r, sizeof(struct rtable));	}	/* add the new route */	rp = &rt_base;	while ((r = *rp) != NULL) {		if ((r->rt_mask & mask) != mask)			break;		rp = &r->rt_next;	}	rt->rt_next = r;	*rp = rt;	if (rt->rt_dev->flags & IFF_LOOPBACK)		rt_loopback = rt;	restore_flags(cpuflags);	return;}static inline int bad_mask(unsigned long mask, unsigned long addr){	if (addr & (mask = ~mask))		return 1;	mask = ntohl(mask);	if (mask & (mask+1))		return 1;	return 0;}static int rt_new(struct rtentry *r){	int err;	char * devname;	struct device * dev = NULL;	unsigned long flags, daddr, mask, gw;	if ((devname = r->rt_dev) != NULL) {		err = getname(devname, &devname);		if (err)			return err;		dev = dev_get(devname);		putname(devname);		if (!dev)			return -EINVAL;	}	if (r->rt_dst.sa_family != AF_INET)		return -EAFNOSUPPORT;	flags = r->rt_flags;	daddr = ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr;	mask = ((struct sockaddr_in *) &r->rt_genmask)->sin_addr.s_addr;	gw = ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr;/* BSD emulation: Permits route add someroute gw one-of-my-addresses   to indicate which iface. Not as clean as the nice Linux dev technique   but people keep using it... */	if (!dev && (flags & RTF_GATEWAY)) {		struct device *dev2;		for (dev2 = dev_base ; dev2 != NULL ; dev2 = dev2->next) {			if ((dev2->flags & IFF_UP) && dev2->pa_addr == gw) {				flags &= ~RTF_GATEWAY;				dev = dev2;				break;			}		}	}	if (bad_mask(mask, daddr))		mask = 0;	if (flags & RTF_HOST)		mask = 0xffffffff;	else if (mask && r->rt_genmask.sa_family != AF_INET)		return -EAFNOSUPPORT;	if (flags & RTF_GATEWAY) {		if (r->rt_gateway.sa_family != AF_INET)			return -EAFNOSUPPORT;		if (!dev)			dev = get_gw_dev(gw);	} else if (!dev)		dev = dev_check(daddr);	if (dev == NULL)		return -ENETUNREACH;	rt_add(flags, daddr, mask, gw, dev);	return 0;}static int rt_kill(struct rtentry *r){	struct sockaddr_in *trg;	trg = (struct sockaddr_in *) &r->rt_dst;	rt_del(trg->sin_addr.s_addr);	return 0;}/* Called from the PROCfs module. */intrt_get_info(char *buffer){  struct rtable *r;  char *pos;  pos = buffer;  pos += sprintf(pos,		 "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\n");    /* This isn't quite right -- r->rt_dst is a struct! */  for (r = rt_base; r != NULL; r = r->rt_next) {        pos += sprintf(pos, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\n",		r->rt_dev->name, r->rt_dst, r->rt_gateway,		r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric,		r->rt_mask);  }  return(pos - buffer);}/* * This is hackish, but results in better code. Use "-S" to see why. */#define early_out ({ goto no_route; 1; })struct rtable * rt_route(unsigned long daddr, struct options *opt){	struct rtable *rt;	for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next) {		if (!((rt->rt_dst ^ daddr) & rt->rt_mask))			break;		/* broadcast addresses can be special cases.. */		if ((rt->rt_dev->flags & IFF_BROADCAST) &&		     rt->rt_dev->pa_brdaddr == daddr)			break;	}	if (daddr == rt->rt_dev->pa_addr) {		if ((rt = rt_loopback) == NULL)			goto no_route;	}	rt->rt_use++;	return rt;no_route:	return NULL;}static int get_old_rtent(struct old_rtentry * src, struct rtentry * rt){	int err;	struct old_rtentry tmp;	err=verify_area(VERIFY_READ, src, sizeof(*src));	if (err)		return err;	memcpy_fromfs(&tmp, src, sizeof(*src));	memset(rt, 0, sizeof(*rt));	rt->rt_dst = tmp.rt_dst;	rt->rt_gateway = tmp.rt_gateway;	rt->rt_genmask.sa_family = AF_INET;	((struct sockaddr_in *) &rt->rt_genmask)->sin_addr.s_addr = tmp.rt_genmask;	rt->rt_flags = tmp.rt_flags;	rt->rt_dev = tmp.rt_dev;	return 0;}int rt_ioctl(unsigned int cmd, void *arg){	int err;	struct rtentry rt;	switch(cmd) {	case DDIOCSDBG:		return dbg_ioctl(arg, DBG_RT);	case SIOCADDRTOLD:	case SIOCDELRTOLD:		if (!suser())			return -EPERM;		err = get_old_rtent((struct old_rtentry *) arg, &rt);		if (err)			return err;		return (cmd == SIOCDELRTOLD) ? rt_kill(&rt) : rt_new(&rt);	case SIOCADDRT:	case SIOCDELRT:		if (!suser())			return -EPERM;		err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry));		if (err)			return err;		memcpy_fromfs(&rt, arg, sizeof(struct rtentry));		return (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt);	}	return -EINVAL;}

⌨️ 快捷键说明

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