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

📄 exthdrs.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	 */	n = hdr->hdrlen >> 1;	if (hdr->segments_left > n) {		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),				 IPSTATS_MIB_INHDRERRORS);		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,				  ((&hdr->segments_left) -				   skb_network_header(skb)));		return -1;	}	/* We are about to mangle packet header. Be careful!	   Do not damage packets queued somewhere.	 */	if (skb_cloned(skb)) {		/* the copy is a forwarded packet */		if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {			IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),					 IPSTATS_MIB_OUTDISCARDS);			kfree_skb(skb);			return -1;		}		hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);	}	if (skb->ip_summed == CHECKSUM_COMPLETE)		skb->ip_summed = CHECKSUM_NONE;	i = n - --hdr->segments_left;	rthdr = (struct rt0_hdr *) hdr;	addr = rthdr->addr;	addr += i - 1;	switch (hdr->type) {#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)	case IPV6_SRCRT_TYPE_2:		if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,				     (xfrm_address_t *)&ipv6_hdr(skb)->saddr,				     IPPROTO_ROUTING) < 0) {			IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),					 IPSTATS_MIB_INADDRERRORS);			kfree_skb(skb);			return -1;		}		if (!ipv6_chk_home_addr(addr)) {			IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),					 IPSTATS_MIB_INADDRERRORS);			kfree_skb(skb);			return -1;		}		break;#endif	default:		break;	}	if (ipv6_addr_is_multicast(addr)) {		IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),				 IPSTATS_MIB_INADDRERRORS);		kfree_skb(skb);		return -1;	}	ipv6_addr_copy(&daddr, addr);	ipv6_addr_copy(addr, &ipv6_hdr(skb)->daddr);	ipv6_addr_copy(&ipv6_hdr(skb)->daddr, &daddr);	dst_release(xchg(&skb->dst, NULL));	ip6_route_input(skb);	if (skb->dst->error) {		skb_push(skb, skb->data - skb_network_header(skb));		dst_input(skb);		return -1;	}	if (skb->dst->dev->flags&IFF_LOOPBACK) {		if (ipv6_hdr(skb)->hop_limit <= 1) {			IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),					 IPSTATS_MIB_INHDRERRORS);			icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,				    0, skb->dev);			kfree_skb(skb);			return -1;		}		ipv6_hdr(skb)->hop_limit--;		goto looped_back;	}	skb_push(skb, skb->data - skb_network_header(skb));	dst_input(skb);	return -1;unknown_rh:	IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);	icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,			  (&hdr->type) - skb_network_header(skb));	return -1;}static struct inet6_protocol rthdr_protocol = {	.handler	=	ipv6_rthdr_rcv,	.flags		=	INET6_PROTO_NOPOLICY | INET6_PROTO_GSO_EXTHDR,};void __init ipv6_rthdr_init(void){	if (inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING) < 0)		printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n");};/**********************************  Hop-by-hop options. **********************************//* * Note: we cannot rely on skb->dst before we assign it in ip6_route_input(). */static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb){	return skb->dst ? ip6_dst_idev(skb->dst) : __in6_dev_get(skb->dev);}/* Router Alert as of RFC 2711 */static int ipv6_hop_ra(struct sk_buff *skb, int optoff){	const unsigned char *nh = skb_network_header(skb);	if (nh[optoff + 1] == 2) {		IP6CB(skb)->ra = optoff;		return 1;	}	LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_ra: wrong RA length %d\n",		       nh[optoff + 1]);	kfree_skb(skb);	return 0;}/* Jumbo payload */static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff){	const unsigned char *nh = skb_network_header(skb);	u32 pkt_len;	if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {		LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",			       nh[optoff+1]);		IP6_INC_STATS_BH(ipv6_skb_idev(skb),				 IPSTATS_MIB_INHDRERRORS);		goto drop;	}	pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));	if (pkt_len <= IPV6_MAXPLEN) {		IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS);		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);		return 0;	}	if (ipv6_hdr(skb)->payload_len) {		IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS);		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);		return 0;	}	if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {		IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INTRUNCATEDPKTS);		goto drop;	}	if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))		goto drop;	return 1;drop:	kfree_skb(skb);	return 0;}static struct tlvtype_proc tlvprochopopt_lst[] = {	{		.type	= IPV6_TLV_ROUTERALERT,		.func	= ipv6_hop_ra,	},	{		.type	= IPV6_TLV_JUMBO,		.func	= ipv6_hop_jumbo,	},	{ -1, }};int ipv6_parse_hopopts(struct sk_buff *skb){	struct inet6_skb_parm *opt = IP6CB(skb);	/*	 * skb_network_header(skb) is equal to skb->data, and	 * skb_network_header_len(skb) is always equal to	 * sizeof(struct ipv6hdr) by definition of	 * hop-by-hop options.	 */	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) ||	    !pskb_may_pull(skb, (sizeof(struct ipv6hdr) +				 ((skb_transport_header(skb)[1] + 1) << 3)))) {		kfree_skb(skb);		return -1;	}	opt->hop = sizeof(struct ipv6hdr);	if (ip6_parse_tlv(tlvprochopopt_lst, skb)) {		skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;		opt = IP6CB(skb);		opt->nhoff = sizeof(struct ipv6hdr);		return 1;	}	return -1;}/* *	Creating outbound headers. * *	"build" functions work when skb is filled from head to tail (datagram) *	"push"	functions work when headers are added from tail to head (tcp) * *	In both cases we assume, that caller reserved enough room *	for headers. */static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,			    struct ipv6_rt_hdr *opt,			    struct in6_addr **addr_p){	struct rt0_hdr *phdr, *ihdr;	int hops;	ihdr = (struct rt0_hdr *) opt;	phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3);	memcpy(phdr, ihdr, sizeof(struct rt0_hdr));	hops = ihdr->rt_hdr.hdrlen >> 1;	if (hops > 1)		memcpy(phdr->addr, ihdr->addr + 1,		       (hops - 1) * sizeof(struct in6_addr));	ipv6_addr_copy(phdr->addr + (hops - 1), *addr_p);	*addr_p = ihdr->addr;	phdr->rt_hdr.nexthdr = *proto;	*proto = NEXTHDR_ROUTING;}static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt){	struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt));	memcpy(h, opt, ipv6_optlen(opt));	h->nexthdr = *proto;	*proto = type;}void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,			  u8 *proto,			  struct in6_addr **daddr){	if (opt->srcrt) {		ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);		/*		 * IPV6_RTHDRDSTOPTS is ignored		 * unless IPV6_RTHDR is set (RFC3542).		 */		if (opt->dst0opt)			ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);	}	if (opt->hopopt)		ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);}EXPORT_SYMBOL(ipv6_push_nfrag_opts);void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto){	if (opt->dst1opt)		ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);}struct ipv6_txoptions *ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt){	struct ipv6_txoptions *opt2;	opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);	if (opt2) {		long dif = (char*)opt2 - (char*)opt;		memcpy(opt2, opt, opt->tot_len);		if (opt2->hopopt)			*((char**)&opt2->hopopt) += dif;		if (opt2->dst0opt)			*((char**)&opt2->dst0opt) += dif;		if (opt2->dst1opt)			*((char**)&opt2->dst1opt) += dif;		if (opt2->srcrt)			*((char**)&opt2->srcrt) += dif;	}	return opt2;}EXPORT_SYMBOL_GPL(ipv6_dup_options);static int ipv6_renew_option(void *ohdr,			     struct ipv6_opt_hdr __user *newopt, int newoptlen,			     int inherit,			     struct ipv6_opt_hdr **hdr,			     char **p){	if (inherit) {		if (ohdr) {			memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr));			*hdr = (struct ipv6_opt_hdr *)*p;			*p += CMSG_ALIGN(ipv6_optlen(*(struct ipv6_opt_hdr **)hdr));		}	} else {		if (newopt) {			if (copy_from_user(*p, newopt, newoptlen))				return -EFAULT;			*hdr = (struct ipv6_opt_hdr *)*p;			if (ipv6_optlen(*(struct ipv6_opt_hdr **)hdr) > newoptlen)				return -EINVAL;			*p += CMSG_ALIGN(newoptlen);		}	}	return 0;}struct ipv6_txoptions *ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,		   int newtype,		   struct ipv6_opt_hdr __user *newopt, int newoptlen){	int tot_len = 0;	char *p;	struct ipv6_txoptions *opt2;	int err;	if (opt) {		if (newtype != IPV6_HOPOPTS && opt->hopopt)			tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));		if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)			tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));		if (newtype != IPV6_RTHDR && opt->srcrt)			tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));		if (newtype != IPV6_DSTOPTS && opt->dst1opt)			tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));	}	if (newopt && newoptlen)		tot_len += CMSG_ALIGN(newoptlen);	if (!tot_len)		return NULL;	tot_len += sizeof(*opt2);	opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);	if (!opt2)		return ERR_PTR(-ENOBUFS);	memset(opt2, 0, tot_len);	opt2->tot_len = tot_len;	p = (char *)(opt2 + 1);	err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen,				newtype != IPV6_HOPOPTS,				&opt2->hopopt, &p);	if (err)		goto out;	err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen,				newtype != IPV6_RTHDRDSTOPTS,				&opt2->dst0opt, &p);	if (err)		goto out;	err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen,				newtype != IPV6_RTHDR,				(struct ipv6_opt_hdr **)&opt2->srcrt, &p);	if (err)		goto out;	err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen,				newtype != IPV6_DSTOPTS,				&opt2->dst1opt, &p);	if (err)		goto out;	opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +			  (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +			  (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);	opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);	return opt2;out:	sock_kfree_s(sk, opt2, opt2->tot_len);	return ERR_PTR(err);}struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,					  struct ipv6_txoptions *opt){	/*	 * ignore the dest before srcrt unless srcrt is being included.	 * --yoshfuji	 */	if (opt && opt->dst0opt && !opt->srcrt) {		if (opt_space != opt) {			memcpy(opt_space, opt, sizeof(*opt_space));			opt = opt_space;		}		opt->opt_nflen -= ipv6_optlen(opt->dst0opt);		opt->dst0opt = NULL;	}	return opt;}

⌨️ 快捷键说明

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