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

📄 sit.c

📁 嵌入式系统设计与实验教材二源码linux内核移植与编译
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	IPv6 over IPv4 tunnel device - Simple Internet Transition (SIT) *	Linux INET6 implementation * *	Authors: *	Pedro Roque		<roque@di.fc.ul.pt>	 *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru> * *	$Id: sit.c,v 1.53 2001/09/25 05:09:53 davem Exp $ * *	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. * *	Changes: * Roger Venning <r.venning@telstra.com>:	6to4 support * Nate Thompson <nate@thebog.net>:		6to4 support */#define __NO_VERSION__#include <linux/config.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/sched.h>#include <linux/net.h>#include <linux/in6.h>#include <linux/netdevice.h>#include <linux/if_arp.h>#include <linux/icmp.h>#include <asm/uaccess.h>#include <linux/init.h>#include <linux/netfilter_ipv4.h>#include <net/sock.h>#include <net/snmp.h>#include <net/ipv6.h>#include <net/protocol.h>#include <net/transp_v6.h>#include <net/ip6_fib.h>#include <net/ip6_route.h>#include <net/ndisc.h>#include <net/addrconf.h>#include <net/ip.h>#include <net/udp.h>#include <net/icmp.h>#include <net/ipip.h>#include <net/inet_ecn.h>/*   This version of net/ipv6/sit.c is cloned of net/ipv4/ip_gre.c   For comments look at net/ipv4/ip_gre.c --ANK */#define HASH_SIZE  16#define HASH(addr) ((addr^(addr>>4))&0xF)static int ipip6_fb_tunnel_init(struct net_device *dev);static int ipip6_tunnel_init(struct net_device *dev);static struct net_device ipip6_fb_tunnel_dev = {	"sit0", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, ipip6_fb_tunnel_init,};static struct ip_tunnel ipip6_fb_tunnel = {	NULL, &ipip6_fb_tunnel_dev, {0, }, 0, 0, 0, 0, 0, 0, 0, {"sit0", }};static struct ip_tunnel *tunnels_r_l[HASH_SIZE];static struct ip_tunnel *tunnels_r[HASH_SIZE];static struct ip_tunnel *tunnels_l[HASH_SIZE];static struct ip_tunnel *tunnels_wc[1];static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunnels_r_l };static rwlock_t ipip6_lock = RW_LOCK_UNLOCKED;static struct ip_tunnel * ipip6_tunnel_lookup(u32 remote, u32 local){	unsigned h0 = HASH(remote);	unsigned h1 = HASH(local);	struct ip_tunnel *t;	for (t = tunnels_r_l[h0^h1]; t; t = t->next) {		if (local == t->parms.iph.saddr &&		    remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))			return t;	}	for (t = tunnels_r[h0]; t; t = t->next) {		if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))			return t;	}	for (t = tunnels_l[h1]; t; t = t->next) {		if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP))			return t;	}	if ((t = tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP))		return t;	return NULL;}static struct ip_tunnel ** ipip6_bucket(struct ip_tunnel *t){	u32 remote = t->parms.iph.daddr;	u32 local = t->parms.iph.saddr;	unsigned h = 0;	int prio = 0;	if (remote) {		prio |= 2;		h ^= HASH(remote);	}	if (local) {		prio |= 1;		h ^= HASH(local);	}	return &tunnels[prio][h];}static void ipip6_tunnel_unlink(struct ip_tunnel *t){	struct ip_tunnel **tp;	for (tp = ipip6_bucket(t); *tp; tp = &(*tp)->next) {		if (t == *tp) {			write_lock_bh(&ipip6_lock);			*tp = t->next;			write_unlock_bh(&ipip6_lock);			break;		}	}}static void ipip6_tunnel_link(struct ip_tunnel *t){	struct ip_tunnel **tp = ipip6_bucket(t);	write_lock_bh(&ipip6_lock);	t->next = *tp;	write_unlock_bh(&ipip6_lock);	*tp = t;}struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int create){	u32 remote = parms->iph.daddr;	u32 local = parms->iph.saddr;	struct ip_tunnel *t, **tp, *nt;	struct net_device *dev;	unsigned h = 0;	int prio = 0;	if (remote) {		prio |= 2;		h ^= HASH(remote);	}	if (local) {		prio |= 1;		h ^= HASH(local);	}	for (tp = &tunnels[prio][h]; (t = *tp) != NULL; tp = &t->next) {		if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr)			return t;	}	if (!create)		return NULL;	MOD_INC_USE_COUNT;	dev = kmalloc(sizeof(*dev) + sizeof(*t), GFP_KERNEL);	if (dev == NULL) {		MOD_DEC_USE_COUNT;		return NULL;	}	memset(dev, 0, sizeof(*dev) + sizeof(*t));	dev->priv = (void*)(dev+1);	nt = (struct ip_tunnel*)dev->priv;	nt->dev = dev;	dev->init = ipip6_tunnel_init;	dev->features |= NETIF_F_DYNALLOC;	memcpy(&nt->parms, parms, sizeof(*parms));	nt->parms.name[IFNAMSIZ-1] = '\0';	strcpy(dev->name, nt->parms.name);	if (dev->name[0] == 0) {		int i;		for (i=1; i<100; i++) {			sprintf(dev->name, "sit%d", i);			if (__dev_get_by_name(dev->name) == NULL)				break;		}		if (i==100)			goto failed;		memcpy(nt->parms.name, dev->name, IFNAMSIZ);	}	if (register_netdevice(dev) < 0)		goto failed;	dev_hold(dev);	ipip6_tunnel_link(nt);	/* Do not decrement MOD_USE_COUNT here. */	return nt;failed:	kfree(dev);	MOD_DEC_USE_COUNT;	return NULL;}static void ipip6_tunnel_destructor(struct net_device *dev){	if (dev != &ipip6_fb_tunnel_dev) {		MOD_DEC_USE_COUNT;	}}static void ipip6_tunnel_uninit(struct net_device *dev){	if (dev == &ipip6_fb_tunnel_dev) {		write_lock_bh(&ipip6_lock);		tunnels_wc[0] = NULL;		write_unlock_bh(&ipip6_lock);		dev_put(dev);	} else {		ipip6_tunnel_unlink((struct ip_tunnel*)dev->priv);		dev_put(dev);	}}void ipip6_err(struct sk_buff *skb, u32 info){#ifndef I_WISH_WORLD_WERE_PERFECT/* It is not :-( All the routers (except for Linux) return only   8 bytes of packet payload. It means, that precise relaying of   ICMP in the real Internet is absolutely infeasible. */	struct iphdr *iph = (struct iphdr*)skb->data;	int type = skb->h.icmph->type;	int code = skb->h.icmph->code;	struct ip_tunnel *t;	switch (type) {	default:	case ICMP_PARAMETERPROB:		return;	case ICMP_DEST_UNREACH:		switch (code) {		case ICMP_SR_FAILED:		case ICMP_PORT_UNREACH:			/* Impossible event. */			return;		case ICMP_FRAG_NEEDED:			/* Soft state for pmtu is maintained by IP core. */			return;		default:			/* All others are translated to HOST_UNREACH.			   rfc2003 contains "deep thoughts" about NET_UNREACH,			   I believe they are just ether pollution. --ANK			 */			break;		}		break;	case ICMP_TIME_EXCEEDED:		if (code != ICMP_EXC_TTL)			return;		break;	}	read_lock(&ipip6_lock);	t = ipip6_tunnel_lookup(iph->daddr, iph->saddr);	if (t == NULL || t->parms.iph.daddr == 0)		goto out;	if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)		goto out;	if (jiffies - t->err_time < IPTUNNEL_ERR_TIMEO)		t->err_count++;	else		t->err_count = 1;	t->err_time = jiffies;out:	read_unlock(&ipip6_lock);	return;#else	struct iphdr *iph = (struct iphdr*)dp;	int hlen = iph->ihl<<2;	struct ipv6hdr *iph6;	int type = skb->h.icmph->type;	int code = skb->h.icmph->code;	int rel_type = 0;	int rel_code = 0;	int rel_info = 0;	struct sk_buff *skb2;	struct rt6_info *rt6i;	if (len < hlen + sizeof(struct ipv6hdr))		return;	iph6 = (struct ipv6hdr*)(dp + hlen);	switch (type) {	default:		return;	case ICMP_PARAMETERPROB:		if (skb->h.icmph->un.gateway < hlen)			return;		/* So... This guy found something strange INSIDE encapsulated		   packet. Well, he is fool, but what can we do ?		 */		rel_type = ICMPV6_PARAMPROB;		rel_info = skb->h.icmph->un.gateway - hlen;		break;	case ICMP_DEST_UNREACH:		switch (code) {		case ICMP_SR_FAILED:		case ICMP_PORT_UNREACH:			/* Impossible event. */			return;		case ICMP_FRAG_NEEDED:			/* Too complicated case ... */			return;		default:			/* All others are translated to HOST_UNREACH.			   rfc2003 contains "deep thoughts" about NET_UNREACH,			   I believe, it is just ether pollution. --ANK			 */			rel_type = ICMPV6_DEST_UNREACH;			rel_code = ICMPV6_ADDR_UNREACH;			break;		}		break;	case ICMP_TIME_EXCEEDED:		if (code != ICMP_EXC_TTL)			return;		rel_type = ICMPV6_TIME_EXCEED;		rel_code = ICMPV6_EXC_HOPLIMIT;		break;	}	/* Prepare fake skb to feed it to icmpv6_send */	skb2 = skb_clone(skb, GFP_ATOMIC);	if (skb2 == NULL)		return;	dst_release(skb2->dst);	skb2->dst = NULL;	skb_pull(skb2, skb->data - (u8*)iph6);	skb2->nh.raw = skb2->data;	/* Try to guess incoming interface */	rt6i = rt6_lookup(&iph6->saddr, NULL, NULL, 0);	if (rt6i && rt6i->rt6i_dev) {		skb2->dev = rt6i->rt6i_dev;		rt6i = rt6_lookup(&iph6->daddr, &iph6->saddr, NULL, 0);		if (rt6i && rt6i->rt6i_dev && rt6i->rt6i_dev->type == ARPHRD_SIT) {			struct ip_tunnel * t = (struct ip_tunnel*)rt6i->rt6i_dev->priv;			if (rel_type == ICMPV6_TIME_EXCEED && t->parms.iph.ttl) {				rel_type = ICMPV6_DEST_UNREACH;				rel_code = ICMPV6_ADDR_UNREACH;			}			icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev);		}	}	kfree_skb(skb2);	return;#endif}static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb){	if (INET_ECN_is_ce(iph->tos) &&	    INET_ECN_is_not_ce(ip6_get_dsfield(skb->nh.ipv6h)))		IP6_ECN_set_ce(skb->nh.ipv6h);}int ipip6_rcv(struct sk_buff *skb){	struct iphdr *iph;	struct ip_tunnel *tunnel;	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))		goto out;	iph = skb->nh.iph;	read_lock(&ipip6_lock);	if ((tunnel = ipip6_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) {		skb->mac.raw = skb->nh.raw;		skb->nh.raw = skb->data;		memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));		skb->protocol = __constant_htons(ETH_P_IPV6);		skb->pkt_type = PACKET_HOST;		tunnel->stat.rx_packets++;		tunnel->stat.rx_bytes += skb->len;		skb->dev = tunnel->dev;		dst_release(skb->dst);		skb->dst = NULL;#ifdef CONFIG_NETFILTER		nf_conntrack_put(skb->nfct);		skb->nfct = NULL;#ifdef CONFIG_NETFILTER_DEBUG		skb->nf_debug = 0;#endif#endif		ipip6_ecn_decapsulate(iph, skb);		netif_rx(skb);		read_unlock(&ipip6_lock);		return 0;	}	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);	kfree_skb(skb);	read_unlock(&ipip6_lock);out:	return 0;}/* Need this wrapper because NF_HOOK takes the function address */static inline int do_ip_send(struct sk_buff *skb){	return ip_send(skb);}

⌨️ 快捷键说明

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