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

📄 exthdrs.c

📁 嵌入式系统设计与实验教材二源码linux内核移植与编译
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	Extension Header handling for IPv6 *	Linux INET6 implementation * *	Authors: *	Pedro Roque		<roque@di.fc.ul.pt> *	Andi Kleen		<ak@muc.de> *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru> * *	$Id: exthdrs.c,v 1.13 2001/06/19 15:58:56 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: *	yoshfuji		: ensure not to overrun while parsing  *				  tlv options. */#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/netdevice.h>#include <linux/in6.h>#include <linux/icmpv6.h>#include <net/sock.h>#include <net/snmp.h>#include <net/ipv6.h>#include <net/protocol.h>#include <net/transp_v6.h>#include <net/rawv6.h>#include <net/ndisc.h>#include <net/ip6_route.h>#include <net/addrconf.h>#include <asm/uaccess.h>/* *	Parsing inbound headers. * *	Parsing function "func" returns offset wrt skb->nh of the place, *	where next nexthdr value is stored or NULL, if parsing *	failed. It should also update skb->h tp point at the next header. */struct hdrtype_proc{	int	type;	int	(*func) (struct sk_buff **, int offset);};/* *	Parsing tlv encoded headers. * *	Parsing function "func" returns 1, if parsing succeed *	and 0, if it failed. *	It MUST NOT touch skb->h. */struct tlvtype_proc{	int	type;	int	(*func) (struct sk_buff *, int offset);};/*********************  Generic functions *********************//* An unknown option is detected, decide what to do */int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff){	switch ((skb->nh.raw[optoff] & 0xC0) >> 6) {	case 0: /* ignore */		return 1;	case 1: /* drop packet */		break;	case 3: /* Send ICMP if not a multicast address and drop packet */		/* Actually, it is redundant check. icmp_send		   will recheck in any case.		 */		if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))			break;	case 2: /* send ICMP PARM PROB regardless and drop packet */		icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);		return 0;	};	kfree_skb(skb);	return 0;}/* Parse tlv encoded option header (hop-by-hop or destination) */static int ip6_parse_tlv(struct tlvtype_proc *procs, struct sk_buff *skb){	struct tlvtype_proc *curr;	int off = skb->h.raw - skb->nh.raw;	int len = ((skb->h.raw[1]+1)<<3);	if ((skb->h.raw + len) - skb->data > skb_headlen(skb))		goto bad;	off += 2;	len -= 2;	while (len > 0) {		int optlen = skb->nh.raw[off+1]+2;		switch (skb->nh.raw[off]) {		case IPV6_TLV_PAD0:			optlen = 1;			break;		case IPV6_TLV_PADN:			break;		default: /* Other TLV code so scan list */			if (optlen > len)				goto bad;			for (curr=procs; curr->type >= 0; curr++) {				if (curr->type == skb->nh.raw[off]) {					/* type specific length/alignment 					   checks will be perfomed in the 					   func(). */					if (curr->func(skb, off) == 0)						return 0;					break;				}			}			if (curr->type < 0) {				if (ip6_tlvopt_unknown(skb, off) == 0)					return 0;			}			break;		}		off += optlen;		len -= optlen;	}	if (len == 0)		return 1;bad:	kfree_skb(skb);	return 0;}/*****************************  Destination options header. *****************************/struct tlvtype_proc tlvprocdestopt_lst[] = {	/* No destination options are defined now */	{-1,			NULL}};static int ipv6_dest_opt(struct sk_buff **skb_ptr, int nhoff){	struct sk_buff *skb=*skb_ptr;	struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||	    !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {		kfree_skb(skb);		return -1;	}	opt->dst1 = skb->h.raw - skb->nh.raw;	if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) {		skb->h.raw += ((skb->h.raw[1]+1)<<3);		return opt->dst1;	}	return -1;}/********************************  NONE header. No data in packet. ********************************/static int ipv6_nodata(struct sk_buff **skb_ptr, int nhoff){	kfree_skb(*skb_ptr);	return -1;}/********************************  Routing header. ********************************/static int ipv6_routing_header(struct sk_buff **skb_ptr, int nhoff){	struct sk_buff *skb = *skb_ptr;	struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;	struct in6_addr *addr;	struct in6_addr daddr;	int addr_type;	int n, i;	struct ipv6_rt_hdr *hdr;	struct rt0_hdr *rthdr;	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||	    !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {		IP6_INC_STATS_BH(Ip6InHdrErrors);		kfree_skb(skb);		return -1;	}	hdr = (struct ipv6_rt_hdr *) skb->h.raw;	if ((ipv6_addr_type(&skb->nh.ipv6h->daddr)&IPV6_ADDR_MULTICAST) ||	    skb->pkt_type != PACKET_HOST) {		kfree_skb(skb);		return -1;	}looped_back:	if (hdr->segments_left == 0) {		opt->srcrt = skb->h.raw - skb->nh.raw;		skb->h.raw += (hdr->hdrlen + 1) << 3;		opt->dst0 = opt->dst1;		opt->dst1 = 0;		return (&hdr->nexthdr) - skb->nh.raw;	}	if (hdr->type != IPV6_SRCRT_TYPE_0 || (hdr->hdrlen & 0x01)) {		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, hdr->type != IPV6_SRCRT_TYPE_0 ? 2 : 1);		return -1;	}	/*	 *	This is the routing header forwarding algorithm from	 *	RFC 1883, page 17.	 */	n = hdr->hdrlen >> 1;	if (hdr->segments_left > n) {		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw);		return -1;	}	/* We are about to mangle packet header. Be careful!	   Do not damage packets queued somewhere.	 */	if (skb_cloned(skb)) {		struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);		kfree_skb(skb);		if (skb2 == NULL)			return -1;		*skb_ptr = skb = skb2;		opt = (struct inet6_skb_parm *)skb2->cb;		hdr = (struct ipv6_rt_hdr *) skb2->h.raw;	}	if (skb->ip_summed == CHECKSUM_HW)		skb->ip_summed = CHECKSUM_NONE;	i = n - --hdr->segments_left;	rthdr = (struct rt0_hdr *) hdr;	addr = rthdr->addr;	addr += i - 1;	addr_type = ipv6_addr_type(addr);	if (addr_type&IPV6_ADDR_MULTICAST) {		kfree_skb(skb);		return -1;	}	ipv6_addr_copy(&daddr, addr);	ipv6_addr_copy(addr, &skb->nh.ipv6h->daddr);	ipv6_addr_copy(&skb->nh.ipv6h->daddr, &daddr);	dst_release(xchg(&skb->dst, NULL));	ip6_route_input(skb);	if (skb->dst->error) {		skb->dst->input(skb);		return -1;	}	if (skb->dst->dev->flags&IFF_LOOPBACK) {		if (skb->nh.ipv6h->hop_limit <= 1) {			icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,				    0, skb->dev);			kfree_skb(skb);			return -1;		}		skb->nh.ipv6h->hop_limit--;		goto looped_back;	}	skb->dst->input(skb);	return -1;}/*   This function inverts received rthdr.   NOTE: specs allow to make it automatically only if   packet authenticated.   I will not discuss it here (though, I am really pissed off at   this stupid requirement making rthdr idea useless)   Actually, it creates severe problems  for us.   Embrionic requests has no associated sockets,   so that user have no control over it and   cannot not only to set reply options, but   even to know, that someone wants to connect   without success. :-(   For now we need to test the engine, so that I created   temporary (or permanent) backdoor.   If listening socket set IPV6_RTHDR to 2, then we invert header.                                                   --ANK (980729) */struct ipv6_txoptions *ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr){	/* Received rthdr:	   [ H1 -> H2 -> ... H_prev ]  daddr=ME	   Inverted result:	   [ H_prev -> ... -> H1 ] daddr =sender	   Note, that IP output engine will rewrire this rthdr	   by rotating it left by one addr.	 */	int n, i;	struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;	struct rt0_hdr *irthdr;	struct ipv6_txoptions *opt;	int hdrlen = ipv6_optlen(hdr);	if (hdr->segments_left ||	    hdr->type != IPV6_SRCRT_TYPE_0 ||	    hdr->hdrlen & 0x01)		return NULL;	n = hdr->hdrlen >> 1;	opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);	if (opt == NULL)		return NULL;	memset(opt, 0, sizeof(*opt));	opt->tot_len = sizeof(*opt) + hdrlen;	opt->srcrt = (void*)(opt+1);	opt->opt_nflen = hdrlen;	memcpy(opt->srcrt, hdr, sizeof(*hdr));	irthdr = (struct rt0_hdr*)opt->srcrt;	/* Obsolete field, MBZ, when originated by us */	irthdr->bitmap = 0;	opt->srcrt->segments_left = n;	for (i=0; i<n; i++)		memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);	return opt;}/********************************  AUTH header. ********************************//*   rfc1826 said, that if a host does not implement AUTH header   it MAY ignore it. We use this hole 8)   Actually, now we can implement OSPFv6 without kernel IPsec.   Authentication for poors may be done in user space with the same success.   Yes, it means, that we allow application to send/receive   raw authentication header. Apparently, we suppose, that it knows   what it does and calculates authentication data correctly.   Certainly, it is possible only for udp and raw sockets, but not for tcp.   AUTH header has 4byte granular length, which kills all the idea   behind AUTOMATIC 64bit alignment of IPv6. Now we will lose   cpu ticks, checking that sender did not something stupid   and opt->hdrlen is even. Shit!		--ANK (980730) */static int ipv6_auth_hdr(struct sk_buff **skb_ptr, int nhoff){	struct sk_buff *skb=*skb_ptr;	struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;	int len;	if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8))		goto fail;

⌨️ 快捷键说明

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