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

📄 ipv6.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)		goto drop;	req = inet6_reqsk_alloc(&dccp6_request_sock_ops);	if (req == NULL)		goto drop;	if (dccp_parse_options(sk, skb))		goto drop_and_free;	dccp_reqsk_init(req, skb);	if (security_inet_conn_request(sk, skb, req))		goto drop_and_free;	ireq6 = inet6_rsk(req);	ipv6_addr_copy(&ireq6->rmt_addr, &ipv6_hdr(skb)->saddr);	ipv6_addr_copy(&ireq6->loc_addr, &ipv6_hdr(skb)->daddr);	ireq6->pktopts	= NULL;	if (ipv6_opt_accepted(sk, skb) ||	    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||	    np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {		atomic_inc(&skb->users);		ireq6->pktopts = skb;	}	ireq6->iif = sk->sk_bound_dev_if;	/* So that link locals have meaning */	if (!sk->sk_bound_dev_if &&	    ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL)		ireq6->iif = inet6_iif(skb);	/*	 * Step 3: Process LISTEN state	 *	 *   Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie	 *	 *   In fact we defer setting S.GSR, S.SWL, S.SWH to	 *   dccp_create_openreq_child.	 */	dreq = dccp_rsk(req);	dreq->dreq_isr	   = dcb->dccpd_seq;	dreq->dreq_iss	   = dccp_v6_init_sequence(skb);	dreq->dreq_service = service;	if (dccp_v6_send_response(sk, req, NULL))		goto drop_and_free;	inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);	return 0;drop_and_free:	reqsk_free(req);drop:	DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);	return -1;}static struct sock *dccp_v6_request_recv_sock(struct sock *sk,					      struct sk_buff *skb,					      struct request_sock *req,					      struct dst_entry *dst){	struct inet6_request_sock *ireq6 = inet6_rsk(req);	struct ipv6_pinfo *newnp, *np = inet6_sk(sk);	struct inet_sock *newinet;	struct dccp_sock *newdp;	struct dccp6_sock *newdp6;	struct sock *newsk;	struct ipv6_txoptions *opt;	if (skb->protocol == htons(ETH_P_IP)) {		/*		 *	v6 mapped		 */		newsk = dccp_v4_request_recv_sock(sk, skb, req, dst);		if (newsk == NULL)			return NULL;		newdp6 = (struct dccp6_sock *)newsk;		newdp = dccp_sk(newsk);		newinet = inet_sk(newsk);		newinet->pinet6 = &newdp6->inet6;		newnp = inet6_sk(newsk);		memcpy(newnp, np, sizeof(struct ipv6_pinfo));		ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),			      newinet->daddr);		ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),			      newinet->saddr);		ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);		inet_csk(newsk)->icsk_af_ops = &dccp_ipv6_mapped;		newsk->sk_backlog_rcv = dccp_v4_do_rcv;		newnp->pktoptions  = NULL;		newnp->opt	   = NULL;		newnp->mcast_oif   = inet6_iif(skb);		newnp->mcast_hops  = ipv6_hdr(skb)->hop_limit;		/*		 * No need to charge this sock to the relevant IPv6 refcnt debug socks count		 * here, dccp_create_openreq_child now does this for us, see the comment in		 * that function for the gory details. -acme		 */		/* It is tricky place. Until this moment IPv4 tcp		   worked with IPv6 icsk.icsk_af_ops.		   Sync it now.		 */		dccp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie);		return newsk;	}	opt = np->opt;	if (sk_acceptq_is_full(sk))		goto out_overflow;	if (dst == NULL) {		struct in6_addr *final_p = NULL, final;		struct flowi fl;		memset(&fl, 0, sizeof(fl));		fl.proto = IPPROTO_DCCP;		ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);		if (opt != NULL && opt->srcrt != NULL) {			const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;			ipv6_addr_copy(&final, &fl.fl6_dst);			ipv6_addr_copy(&fl.fl6_dst, rt0->addr);			final_p = &final;		}		ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);		fl.oif = sk->sk_bound_dev_if;		fl.fl_ip_dport = inet_rsk(req)->rmt_port;		fl.fl_ip_sport = inet_sk(sk)->sport;		security_sk_classify_flow(sk, &fl);		if (ip6_dst_lookup(sk, &dst, &fl))			goto out;		if (final_p)			ipv6_addr_copy(&fl.fl6_dst, final_p);		if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)			goto out;	}	newsk = dccp_create_openreq_child(sk, req, skb);	if (newsk == NULL)		goto out;	/*	 * No need to charge this sock to the relevant IPv6 refcnt debug socks	 * count here, dccp_create_openreq_child now does this for us, see the	 * comment in that function for the gory details. -acme	 */	__ip6_dst_store(newsk, dst, NULL, NULL);	newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |						      NETIF_F_TSO);	newdp6 = (struct dccp6_sock *)newsk;	newinet = inet_sk(newsk);	newinet->pinet6 = &newdp6->inet6;	newdp = dccp_sk(newsk);	newnp = inet6_sk(newsk);	memcpy(newnp, np, sizeof(struct ipv6_pinfo));	ipv6_addr_copy(&newnp->daddr, &ireq6->rmt_addr);	ipv6_addr_copy(&newnp->saddr, &ireq6->loc_addr);	ipv6_addr_copy(&newnp->rcv_saddr, &ireq6->loc_addr);	newsk->sk_bound_dev_if = ireq6->iif;	/* Now IPv6 options...	   First: no IPv4 options.	 */	newinet->opt = NULL;	/* Clone RX bits */	newnp->rxopt.all = np->rxopt.all;	/* Clone pktoptions received with SYN */	newnp->pktoptions = NULL;	if (ireq6->pktopts != NULL) {		newnp->pktoptions = skb_clone(ireq6->pktopts, GFP_ATOMIC);		kfree_skb(ireq6->pktopts);		ireq6->pktopts = NULL;		if (newnp->pktoptions)			skb_set_owner_r(newnp->pktoptions, newsk);	}	newnp->opt	  = NULL;	newnp->mcast_oif  = inet6_iif(skb);	newnp->mcast_hops = ipv6_hdr(skb)->hop_limit;	/*	 * Clone native IPv6 options from listening socket (if any)	 *	 * Yes, keeping reference count would be much more clever, but we make	 * one more one thing there: reattach optmem to newsk.	 */	if (opt != NULL) {		newnp->opt = ipv6_dup_options(newsk, opt);		if (opt != np->opt)			sock_kfree_s(sk, opt, opt->tot_len);	}	inet_csk(newsk)->icsk_ext_hdr_len = 0;	if (newnp->opt != NULL)		inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +						     newnp->opt->opt_flen);	dccp_sync_mss(newsk, dst_mtu(dst));	newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;	__inet6_hash(&dccp_hashinfo, newsk);	inet_inherit_port(&dccp_hashinfo, sk, newsk);	return newsk;out_overflow:	NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS);out:	NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS);	if (opt != NULL && opt != np->opt)		sock_kfree_s(sk, opt, opt->tot_len);	dst_release(dst);	return NULL;}/* The socket must have it's spinlock held when we get * here. * * We have a potential double-lock case here, so even when * doing backlog processing we use the BH locking scheme. * This is because we cannot sleep with the original spinlock * held. */static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb){	struct ipv6_pinfo *np = inet6_sk(sk);	struct sk_buff *opt_skb = NULL;	/* Imagine: socket is IPv6. IPv4 packet arrives,	   goes to IPv4 receive handler and backlogged.	   From backlog it always goes here. Kerboom...	   Fortunately, dccp_rcv_established and rcv_established	   handle them correctly, but it is not case with	   dccp_v6_hnd_req and dccp_v6_ctl_send_reset().   --ANK	 */	if (skb->protocol == htons(ETH_P_IP))		return dccp_v4_do_rcv(sk, skb);	if (sk_filter(sk, skb))		goto discard;	/*	 * socket locking is here for SMP purposes as backlog rcv is currently	 * called with bh processing disabled.	 */	/* Do Stevens' IPV6_PKTOPTIONS.	   Yes, guys, it is the only place in our code, where we	   may make it not affecting IPv4.	   The rest of code is protocol independent,	   and I do not like idea to uglify IPv4.	   Actually, all the idea behind IPV6_PKTOPTIONS	   looks not very well thought. For now we latch	   options, received in the last packet, enqueued	   by tcp. Feel free to propose better solution.					       --ANK (980728)	 */	if (np->rxopt.all)	/*	 * FIXME: Add handling of IPV6_PKTOPTIONS skb. See the comments below	 *        (wrt ipv6_pktopions) and net/ipv6/tcp_ipv6.c for an example.	 */		opt_skb = skb_clone(skb, GFP_ATOMIC);	if (sk->sk_state == DCCP_OPEN) { /* Fast path */		if (dccp_rcv_established(sk, skb, dccp_hdr(skb), skb->len))			goto reset;		if (opt_skb) {			/* XXX This is where we would goto ipv6_pktoptions. */			__kfree_skb(opt_skb);		}		return 0;	}	/*	 *  Step 3: Process LISTEN state	 *     If S.state == LISTEN,	 *	 If P.type == Request or P contains a valid Init Cookie option,	 *	      (* Must scan the packet's options to check for Init	 *		 Cookies.  Only Init Cookies are processed here,	 *		 however; other options are processed in Step 8.  This	 *		 scan need only be performed if the endpoint uses Init	 *		 Cookies *)	 *	      (* Generate a new socket and switch to that socket *)	 *	      Set S := new socket for this port pair	 *	      S.state = RESPOND	 *	      Choose S.ISS (initial seqno) or set from Init Cookies	 *	      Initialize S.GAR := S.ISS	 *	      Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies	 *	      Continue with S.state == RESPOND	 *	      (* A Response packet will be generated in Step 11 *)	 *	 Otherwise,	 *	      Generate Reset(No Connection) unless P.type == Reset	 *	      Drop packet and return	 *	 * NOTE: the check for the packet types is done in	 *	 dccp_rcv_state_process	 */	if (sk->sk_state == DCCP_LISTEN) {		struct sock *nsk = dccp_v6_hnd_req(sk, skb);		if (nsk == NULL)			goto discard;		/*		 * Queue it on the new socket if the new socket is active,		 * otherwise we just shortcircuit this and continue with		 * the new socket..		 */		if (nsk != sk) {			if (dccp_child_process(sk, nsk, skb))				goto reset;			if (opt_skb != NULL)				__kfree_skb(opt_skb);			return 0;		}	}	if (dccp_rcv_state_process(sk, skb, dccp_hdr(skb), skb->len))		goto reset;	if (opt_skb) {		/* XXX This is where we would goto ipv6_pktoptions. */		__kfree_skb(opt_skb);	}	return 0;reset:	dccp_v6_ctl_send_reset(sk, skb);discard:	if (opt_skb != NULL)		__kfree_skb(opt_skb);	kfree_skb(skb);	return 0;}static int dccp_v6_rcv(struct sk_buff *skb){	const struct dccp_hdr *dh;	struct sock *sk;	int min_cov;	/* Step 1: Check header basics */	if (dccp_invalid_packet(skb))		goto discard_it;	/* Step 1: If header checksum is incorrect, drop packet and return. */	if (dccp_v6_csum_finish(skb, &ipv6_hdr(skb)->saddr,				     &ipv6_hdr(skb)->daddr)) {		DCCP_WARN("dropped packet with invalid checksum\n");		goto discard_it;	}	dh = dccp_hdr(skb);	DCCP_SKB_CB(skb)->dccpd_seq  = dccp_hdr_seq(dh);	DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;	if (dccp_packet_without_ack(skb))		DCCP_SKB_CB(skb)->dccpd_ack_seq = DCCP_PKT_WITHOUT_ACK_SEQ;	else		DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);	/* Step 2:	 *	Look up flow ID in table and get corresponding socket */	sk = __inet6_lookup(&dccp_hashinfo, &ipv6_hdr(skb)->saddr,			    dh->dccph_sport,			    &ipv6_hdr(skb)->daddr, ntohs(dh->dccph_dport),			    inet6_iif(skb));	/*	 * Step 2:	 *	If no socket ...	 */	if (sk == NULL) {		dccp_pr_debug("failed to look up flow ID in table and "			      "get corresponding socket\n");		goto no_dccp_socket;	}	/*	 * Step 2:	 *	... or S.state == TIMEWAIT,	 *		Generate Reset(No Connection) unless P.type == Reset	 *		Drop packet and return	 */	if (sk->sk_state == DCCP_TIME_WAIT) {

⌨️ 快捷键说明

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