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

📄 ip6_output.c

📁 ipv6地址转换器
💻 C
📖 第 1 页 / 共 2 页
字号:
						frag_off -= frag_len;			data_off -= frag_len;			fhdr2 = (struct frag_hdr *) (skb->data + fhdr_dist);			/* more flag on */			fhdr2->frag_off = htons(frag_off | 1);			/* Write fragmentable exthdrs to the first chunk */			if (nfrags == 0 && opt && opt->opt_flen) {				ipv6_build_frag_opts(skb, &fhdr2->nexthdr, opt);				frag_len -= opt->opt_flen;				data_off = 0;			}			err = getfrag(data, &hdr->saddr,skb_put(skb, frag_len),				      data_off, frag_len);			if (err) {				kfree_skb(skb);				break;			}			ipv6_statistics.Ip6FragCreates++;			ipv6_statistics.Ip6OutRequests++;			dst->output(skb);		}	}	if (err) {		ipv6_statistics.Ip6FragFails++;		kfree_skb(last_skb);		return -EFAULT;	}	hdr->payload_len = htons(unfrag_len + last_len - sizeof(struct ipv6hdr));	/*	 *	update last_skb to reflect the getfrag we did	 *	on start.	 */	skb_put(last_skb, last_len);	ipv6_statistics.Ip6FragCreates++;	ipv6_statistics.Ip6FragOKs++;	ipv6_statistics.Ip6OutRequests++;	dst->output(last_skb);	return 0;}int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data,		   struct flowi *fl, unsigned length,		   struct ipv6_txoptions *opt, int hlimit, int flags){	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;	struct in6_addr *final_dst = NULL;	struct dst_entry *dst;	int err = 0;	unsigned int pktlength, jumbolen, mtu;	struct in6_addr saddr;	if (opt && opt->srcrt) {		struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;		final_dst = fl->fl6_dst;		fl->fl6_dst = rt0->addr;	}	if (!fl->oif && ipv6_addr_is_multicast(fl->nl_u.ip6_u.daddr))		fl->oif = np->mcast_oif;	dst = NULL;	if (sk->dst_cache) {		dst = dst_check(&sk->dst_cache, np->dst_cookie);		if (dst) {			struct rt6_info *rt = (struct rt6_info*)dst_clone(dst);			/* Yes, checking route validity in not connected			   case is not very simple. Take into account,			   that we do not support routing by source, TOS,			   and MSG_DONTROUTE 		--ANK (980726)			   1. If route was host route, check that			      cached destination is current.			      If it is network route, we still may			      check its validity using saved pointer			      to the last used address: daddr_cache.			      We do not want to save whole address now,			      (because main consumer of this service			       is tcp, which has not this problem),			      so that the last trick works only on connected			      sockets.			   2. oif also should be the same.			 */			if (((rt->rt6i_dst.plen != 128 ||			      ipv6_addr_cmp(fl->fl6_dst, &rt->rt6i_dst.addr))			     && (np->daddr_cache == NULL ||				 ipv6_addr_cmp(fl->fl6_dst, np->daddr_cache)))			    || (fl->oif && fl->oif != dst->dev->ifindex)) {				dst_release(dst);				dst = NULL;			}		}	}	if (dst == NULL)		dst = ip6_route_output(sk, fl);	if (dst->error) {		ipv6_statistics.Ip6OutNoRoutes++;		dst_release(dst);		return -ENETUNREACH;	}	if (fl->fl6_src == NULL) {		err = ipv6_get_saddr(dst, fl->fl6_dst, &saddr);		if (err) {#if IP6_DEBUG >= 2			printk(KERN_DEBUG "ip6_build_xmit: "			       "no availiable source address\n");#endif			goto out;		}		fl->fl6_src = &saddr;	}	pktlength = length;	if (hlimit < 0) {		if (ipv6_addr_is_multicast(fl->fl6_dst))			hlimit = np->mcast_hops;		else			hlimit = np->hop_limit;		if (hlimit < 0)			hlimit = ((struct rt6_info*)dst)->rt6i_hoplimit;	}	jumbolen = 0;	if (!sk->ip_hdrincl) {		pktlength += sizeof(struct ipv6hdr);		if (opt)			pktlength += opt->opt_flen + opt->opt_nflen;		if (pktlength > 0xFFFF + sizeof(struct ipv6hdr)) {			/* Jumbo datagram.			   It is assumed, that in the case of sk->ip_hdrincl			   jumbo option is supplied by user.			 */			pktlength += 8;			jumbolen = pktlength - sizeof(struct ipv6hdr);		}	}	mtu = dst->pmtu;	if (np->frag_size < mtu) {		if (np->frag_size)			mtu = np->frag_size;		else if (np->pmtudisc == IPV6_PMTUDISC_DONT)			mtu = IPV6_MIN_MTU;	}	/* Critical arithmetic overflow check.	   FIXME: may gcc optimize it out? --ANK (980726)	 */	if (pktlength < length) {		ipv6_local_error(sk, EMSGSIZE, fl, mtu);		err = -EMSGSIZE;		goto out;	}	if (pktlength <= mtu) {		struct sk_buff *skb;		struct ipv6hdr *hdr;		struct device *dev = dst->dev;		skb = sock_alloc_send_skb(sk, pktlength + 15 +					  dev->hard_header_len, 0,					  flags & MSG_DONTWAIT, &err);		if (skb == NULL) {			ipv6_statistics.Ip6OutDiscards++;			goto out;		}		skb->dst = dst_clone(dst);		skb_reserve(skb, (dev->hard_header_len + 15) & ~15);		hdr = (struct ipv6hdr *) skb->tail;		skb->nh.ipv6h = hdr;		if (!sk->ip_hdrincl) {			ip6_bld_1(sk, skb, fl, hlimit,				  jumbolen ? sizeof(struct ipv6hdr) : pktlength);			if (opt || jumbolen) {				u8 *prev_hdr = &hdr->nexthdr;				prev_hdr = ipv6_build_nfrag_opts(skb, prev_hdr, opt, final_dst, jumbolen);				if (opt && opt->opt_flen)					ipv6_build_frag_opts(skb, prev_hdr, opt);			}		}		skb_put(skb, length);		err = getfrag(data, &hdr->saddr,			      ((char *) hdr) + (pktlength - length),			      0, length);		if (!err) {			ipv6_statistics.Ip6OutRequests++;			dst->output(skb);		} else {			err = -EFAULT;			kfree_skb(skb);		}	} else {		if (sk->ip_hdrincl || jumbolen ||		    np->pmtudisc == IPV6_PMTUDISC_DO) {			ipv6_local_error(sk, EMSGSIZE, fl, mtu);			err = -EMSGSIZE;			goto out;		}		err = ip6_frag_xmit(sk, getfrag, data, dst, fl, opt, final_dst, hlimit,				    flags, length, mtu);	}	/*	 *	cleanup	 */out:	ip6_dst_store(sk, dst, fl->nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL);	return err;}int ip6_call_ra_chain(struct sk_buff *skb, int sel){	struct ip6_ra_chain *ra;	struct sock *last = NULL;	for (ra = ip6_ra_chain; ra; ra = ra->next) {		struct sock *sk = ra->sk;		if (sk && ra->sel == sel) {			if (last) {				struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);				if (skb2)					rawv6_rcv(last, skb2, skb2->len);			}			last = sk;		}	}	if (last) {		rawv6_rcv(last, skb, skb->len);		return 1;	}	return 0;}int ip6_forward(struct sk_buff *skb){	struct dst_entry *dst = skb->dst;	struct ipv6hdr *hdr = skb->nh.ipv6h;	struct inet6_skb_parm *opt =(struct inet6_skb_parm*)skb->cb;		if (ipv6_devconf.forwarding == 0 && opt->srcrt == 0)		goto drop;	/*	 *	We DO NOT make any processing on	 *	RA packets, pushing them to user level AS IS	 *	without ane WARRANTY that application will be able	 *	to interpret them. The reason is that we	 *	cannot make anything clever here.	 *	 *	We are not end-node, so that if packet contains	 *	AH/ESP, we cannot make anything.	 *	Defragmentation also would be mistake, RA packets	 *	cannot be fragmented, because there is no warranty	 *	that different fragments will go along one path. --ANK	 */	if (opt->ra) {		u8 *ptr = skb->nh.raw + opt->ra;		if (ip6_call_ra_chain(skb, (ptr[2]<<8) + ptr[3]))			return 0;	}	/*	 *	check and decrement ttl	 */	if (hdr->hop_limit <= 1) {		/* Force OUTPUT device used as source address */		skb->dev = dst->dev;		icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,			    0, skb->dev);		kfree_skb(skb);		return -ETIMEDOUT;	}	/* IPv6 specs say nothing about it, but it is clear that we cannot	   send redirects to source routed frames.	 */	if (skb->dev == dst->dev && dst->neighbour && opt->srcrt == 0) {		struct in6_addr *target = NULL;		struct rt6_info *rt;		struct neighbour *n = dst->neighbour;		/*		 *	incoming and outgoing devices are the same		 *	send a redirect.		 */		rt = (struct rt6_info *) dst;		if ((rt->rt6i_flags & RTF_GATEWAY))			target = (struct in6_addr*)&n->primary_key;		else			target = &hdr->daddr;		/* Limit redirects both by destination (here)		   and by source (inside ndisc_send_redirect)		 */		if (xrlim_allow(dst, 1*HZ))			ndisc_send_redirect(skb, n, target);	} else if (ipv6_addr_type(&hdr->saddr)&(IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK						|IPV6_ADDR_LINKLOCAL)) {		/* This check is security critical. */		goto drop;	}	if (skb->len > dst->pmtu) {		/* Again, force OUTPUT device used as source address */		skb->dev = dst->dev;		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev);		ipv6_statistics.Ip6InTooBigErrors++;		kfree_skb(skb);		return -EMSGSIZE;	}	if ((skb = skb_cow(skb, dst->dev->hard_header_len)) == NULL)		return 0;	hdr = skb->nh.ipv6h;	/* Mangling hops number delayed to point after skb COW */ 	hdr->hop_limit--;	ipv6_statistics.Ip6OutForwDatagrams++;	return dst->output(skb);drop:	ipv6_statistics.Ip6InAddrErrors++;	kfree_skb(skb);	return -EINVAL;}

⌨️ 快捷键说明

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