diff options
Diffstat (limited to 'net/sctp/input.c')
| -rw-r--r-- | net/sctp/input.c | 343 | 
1 files changed, 164 insertions, 179 deletions
diff --git a/net/sctp/input.c b/net/sctp/input.c index ea2192444ce..f2e2cbd2d75 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -23,16 +23,12 @@   * See the GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING.  If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING.  If not, see + * <http://www.gnu.org/licenses/>.   *   * Please send any bug reports or fixes you make to the   * email address(es): - *    lksctp developers <lksctp-developers@lists.sourceforge.net> - * - * Or submit a bug report through the following website: - *    http://www.sf.net/projects/lksctp + *    lksctp developers <linux-sctp@vger.kernel.org>   *   * Written or modified by:   *    La Monte H.P. Yarroll <piggy@acm.org> @@ -43,9 +39,6 @@   *    Daisy Chang <daisyc@us.ibm.com>   *    Sridhar Samudrala <sri@us.ibm.com>   *    Ardelle Fan <ardelle.fan@intel.com> - * - * Any bugs reported given to us we will try to fix... any fixes shared will - * be incorporated into the next SCTP release.   */  #include <linux/types.h> @@ -66,12 +59,15 @@  /* Forward declarations for internal helpers. */  static int sctp_rcv_ootb(struct sk_buff *); -static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, -				      const union sctp_addr *laddr, +static struct sctp_association *__sctp_rcv_lookup(struct net *net, +				      struct sk_buff *skb,  				      const union sctp_addr *paddr, +				      const union sctp_addr *laddr,  				      struct sctp_transport **transportp); -static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr); +static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(struct net *net, +						const union sctp_addr *laddr);  static struct sctp_association *__sctp_lookup_association( +					struct net *net,  					const union sctp_addr *local,  					const union sctp_addr *peer,  					struct sctp_transport **pt); @@ -80,23 +76,15 @@ static int sctp_add_backlog(struct sock *sk, struct sk_buff *skb);  /* Calculate the SCTP checksum of an SCTP packet.  */ -static inline int sctp_rcv_checksum(struct sk_buff *skb) +static inline int sctp_rcv_checksum(struct net *net, struct sk_buff *skb)  {  	struct sctphdr *sh = sctp_hdr(skb);  	__le32 cmp = sh->checksum; -	struct sk_buff *list; -	__le32 val; -	__u32 tmp = sctp_start_cksum((__u8 *)sh, skb_headlen(skb)); - -	skb_walk_frags(skb, list) -		tmp = sctp_update_cksum((__u8 *)list->data, skb_headlen(list), -					tmp); - -	val = sctp_end_cksum(tmp); +	__le32 val = sctp_compute_cksum(skb, 0);  	if (val != cmp) {  		/* CRC failure, dump it. */ -		SCTP_INC_STATS_BH(SCTP_MIB_CHECKSUMERRORS); +		SCTP_INC_STATS_BH(net, SCTP_MIB_CHECKSUMERRORS);  		return -1;  	}  	return 0; @@ -105,7 +93,7 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb)  struct sctp_input_cb {  	union {  		struct inet_skb_parm	h4; -#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) +#if IS_ENABLED(CONFIG_IPV6)  		struct inet6_skb_parm	h6;  #endif  	} header; @@ -129,11 +117,12 @@ int sctp_rcv(struct sk_buff *skb)  	union sctp_addr dest;  	int family;  	struct sctp_af *af; +	struct net *net = dev_net(skb->dev); -	if (skb->pkt_type!=PACKET_HOST) +	if (skb->pkt_type != PACKET_HOST)  		goto discard_it; -	SCTP_INC_STATS_BH(SCTP_MIB_INSCTPPACKS); +	SCTP_INC_STATS_BH(net, SCTP_MIB_INSCTPPACKS);  	if (skb_linearize(skb))  		goto discard_it; @@ -145,7 +134,7 @@ int sctp_rcv(struct sk_buff *skb)  	if (skb->len < sizeof(struct sctphdr))  		goto discard_it;  	if (!sctp_checksum_disable && !skb_csum_unnecessary(skb) && -		  sctp_rcv_checksum(skb) < 0) +		  sctp_rcv_checksum(net, skb) < 0)  		goto discard_it;  	skb_pull(skb, sizeof(struct sctphdr)); @@ -178,10 +167,10 @@ int sctp_rcv(struct sk_buff *skb)  	    !af->addr_valid(&dest, NULL, skb))  		goto discard_it; -	asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport); +	asoc = __sctp_rcv_lookup(net, skb, &src, &dest, &transport);  	if (!asoc) -		ep = __sctp_rcv_lookup_endpoint(&dest); +		ep = __sctp_rcv_lookup_endpoint(net, &dest);  	/* Retrieve the common input handling substructure. */  	rcvr = asoc ? &asoc->base : &ep->base; @@ -191,8 +180,7 @@ int sctp_rcv(struct sk_buff *skb)  	 * If a frame arrives on an interface and the receiving socket is  	 * bound to another interface, via SO_BINDTODEVICE, treat it as OOTB  	 */ -	if (sk->sk_bound_dev_if && (sk->sk_bound_dev_if != af->skb_iif(skb))) -	{ +	if (sk->sk_bound_dev_if && (sk->sk_bound_dev_if != af->skb_iif(skb))) {  		if (asoc) {  			sctp_association_put(asoc);  			asoc = NULL; @@ -200,7 +188,7 @@ int sctp_rcv(struct sk_buff *skb)  			sctp_endpoint_put(ep);  			ep = NULL;  		} -		sk = sctp_get_ctl_sock(); +		sk = net->sctp.ctl_sock;  		ep = sctp_sk(sk)->ep;  		sctp_endpoint_hold(ep);  		rcvr = &ep->base; @@ -216,7 +204,7 @@ int sctp_rcv(struct sk_buff *skb)  	 */  	if (!asoc) {  		if (sctp_rcv_ootb(skb)) { -			SCTP_INC_STATS_BH(SCTP_MIB_OUTOFBLUES); +			SCTP_INC_STATS_BH(net, SCTP_MIB_OUTOFBLUES);  			goto discard_release;  		}  	} @@ -250,7 +238,7 @@ int sctp_rcv(struct sk_buff *skb)  	 * bottom halves on this lock, but a user may be in the lock too,  	 * so check if it is busy.  	 */ -	sctp_bh_lock_sock(sk); +	bh_lock_sock(sk);  	if (sk != rcvr->sk) {  		/* Our cached sk is different from the rcvr->sk.  This is @@ -260,25 +248,25 @@ int sctp_rcv(struct sk_buff *skb)  		 * be doing something with the new socket.  Switch our veiw  		 * of the current sk.  		 */ -		sctp_bh_unlock_sock(sk); +		bh_unlock_sock(sk);  		sk = rcvr->sk; -		sctp_bh_lock_sock(sk); +		bh_lock_sock(sk);  	}  	if (sock_owned_by_user(sk)) {  		if (sctp_add_backlog(sk, skb)) { -			sctp_bh_unlock_sock(sk); +			bh_unlock_sock(sk);  			sctp_chunk_free(chunk);  			skb = NULL; /* sctp_chunk_free already freed the skb */  			goto discard_release;  		} -		SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_BACKLOG); +		SCTP_INC_STATS_BH(net, SCTP_MIB_IN_PKT_BACKLOG);  	} else { -		SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_SOFTIRQ); +		SCTP_INC_STATS_BH(net, SCTP_MIB_IN_PKT_SOFTIRQ);  		sctp_inq_push(&chunk->rcvr->inqueue, chunk);  	} -	sctp_bh_unlock_sock(sk); +	bh_unlock_sock(sk);  	/* Release the asoc/ep ref we took in the lookup calls. */  	if (asoc) @@ -289,7 +277,7 @@ int sctp_rcv(struct sk_buff *skb)  	return 0;  discard_it: -	SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_DISCARDS); +	SCTP_INC_STATS_BH(net, SCTP_MIB_IN_PKT_DISCARDS);  	kfree_skb(skb);  	return 0; @@ -339,17 +327,17 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)  		 */  		sk = rcvr->sk; -		sctp_bh_lock_sock(sk); +		bh_lock_sock(sk);  		if (sock_owned_by_user(sk)) { -			if (sk_add_backlog(sk, skb)) +			if (sk_add_backlog(sk, skb, sk->sk_rcvbuf))  				sctp_chunk_free(chunk);  			else  				backloged = 1;  		} else  			sctp_inq_push(inqueue, chunk); -		sctp_bh_unlock_sock(sk); +		bh_unlock_sock(sk);  		/* If the chunk was backloged again, don't drop refs */  		if (backloged) @@ -376,7 +364,7 @@ static int sctp_add_backlog(struct sock *sk, struct sk_buff *skb)  	struct sctp_ep_common *rcvr = chunk->rcvr;  	int ret; -	ret = sk_add_backlog(sk, skb); +	ret = sk_add_backlog(sk, skb, sk->sk_rcvbuf);  	if (!ret) {  		/* Hold the assoc/ep while hanging on the backlog queue.  		 * This way, we know structures we need will not disappear @@ -408,10 +396,10 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,  	if (t->param_flags & SPP_PMTUD_ENABLE) {  		/* Update transports view of the MTU */ -		sctp_transport_update_pmtu(t, pmtu); +		sctp_transport_update_pmtu(sk, t, pmtu);  		/* Update association pmtu. */ -		sctp_assoc_sync_pmtu(asoc); +		sctp_assoc_sync_pmtu(sk, asoc);  	}  	/* Retransmit with the new pmtu setting. @@ -423,6 +411,18 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,  	sctp_retransmit(&asoc->outqueue, t, SCTP_RTXR_PMTUD);  } +void sctp_icmp_redirect(struct sock *sk, struct sctp_transport *t, +			struct sk_buff *skb) +{ +	struct dst_entry *dst; + +	if (!t) +		return; +	dst = sctp_transport_dst_check(t); +	if (dst) +		dst->ops->redirect(dst, sk, skb); +} +  /*   * SCTP Implementer's Guide, 2.37 ICMP handling procedures   * @@ -438,8 +438,6 @@ void sctp_icmp_proto_unreachable(struct sock *sk,  			   struct sctp_association *asoc,  			   struct sctp_transport *t)  { -	SCTP_DEBUG_PRINTK("%s\n",  __func__); -  	if (sock_owned_by_user(sk)) {  		if (timer_pending(&t->proto_unreach_timer))  			return; @@ -448,13 +446,16 @@ void sctp_icmp_proto_unreachable(struct sock *sk,  						jiffies + (HZ/20)))  				sctp_association_hold(asoc);  		} -			  	} else { -		if (timer_pending(&t->proto_unreach_timer) && -		    del_timer(&t->proto_unreach_timer)) +		struct net *net = sock_net(sk); + +		pr_debug("%s: unrecognized next header type " +			 "encountered!\n", __func__); + +		if (del_timer(&t->proto_unreach_timer))  			sctp_association_put(asoc); -		sctp_do_sm(SCTP_EVENT_T_OTHER, +		sctp_do_sm(net, SCTP_EVENT_T_OTHER,  			   SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),  			   asoc->state, asoc->ep, asoc, t,  			   GFP_ATOMIC); @@ -462,7 +463,7 @@ void sctp_icmp_proto_unreachable(struct sock *sk,  }  /* Common lookup code for icmp/icmpv6 error handler. */ -struct sock *sctp_err_lookup(int family, struct sk_buff *skb, +struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *skb,  			     struct sctphdr *sctphdr,  			     struct sctp_association **app,  			     struct sctp_transport **tpp) @@ -491,7 +492,7 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,  	/* Look for an association that matches the incoming ICMP error  	 * packet.  	 */ -	asoc = __sctp_lookup_association(&saddr, &daddr, &transport); +	asoc = __sctp_lookup_association(net, &saddr, &daddr, &transport);  	if (!asoc)  		return NULL; @@ -510,8 +511,7 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,  	 * discard the packet.  	 */  	if (vtag == 0) { -		chunkhdr = (struct sctp_init_chunk *)((void *)sctphdr -				+ sizeof(struct sctphdr)); +		chunkhdr = (void *)sctphdr + sizeof(struct sctphdr);  		if (len < sizeof(struct sctphdr) + sizeof(sctp_chunkhdr_t)  			  + sizeof(__be32) ||  		    chunkhdr->chunk_hdr.type != SCTP_CID_INIT || @@ -522,30 +522,28 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,  		goto out;  	} -	sctp_bh_lock_sock(sk); +	bh_lock_sock(sk);  	/* If too many ICMPs get dropped on busy  	 * servers this needs to be solved differently.  	 */  	if (sock_owned_by_user(sk)) -		NET_INC_STATS_BH(&init_net, LINUX_MIB_LOCKDROPPEDICMPS); +		NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);  	*app = asoc;  	*tpp = transport;  	return sk;  out: -	if (asoc) -		sctp_association_put(asoc); +	sctp_association_put(asoc);  	return NULL;  }  /* Common cleanup code for icmp/icmpv6 error handler. */  void sctp_err_finish(struct sock *sk, struct sctp_association *asoc)  { -	sctp_bh_unlock_sock(sk); -	if (asoc) -		sctp_association_put(asoc); +	bh_unlock_sock(sk); +	sctp_association_put(asoc);  }  /* @@ -565,7 +563,7 @@ void sctp_err_finish(struct sock *sk, struct sctp_association *asoc)   */  void sctp_v4_err(struct sk_buff *skb, __u32 info)  { -	struct iphdr *iph = (struct iphdr *)skb->data; +	const struct iphdr *iph = (const struct iphdr *)skb->data;  	const int ihlen = iph->ihl * 4;  	const int type = icmp_hdr(skb)->type;  	const int code = icmp_hdr(skb)->code; @@ -573,11 +571,12 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)  	struct sctp_association *asoc = NULL;  	struct sctp_transport *transport;  	struct inet_sock *inet; -	sk_buff_data_t saveip, savesctp; +	__u16 saveip, savesctp;  	int err; +	struct net *net = dev_net(skb->dev);  	if (skb->len < ihlen + 8) { -		ICMP_INC_STATS_BH(&init_net, ICMP_MIB_INERRORS); +		ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);  		return;  	} @@ -586,12 +585,12 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)  	savesctp = skb->transport_header;  	skb_reset_network_header(skb);  	skb_set_transport_header(skb, ihlen); -	sk = sctp_err_lookup(AF_INET, skb, sctp_hdr(skb), &asoc, &transport); +	sk = sctp_err_lookup(net, AF_INET, skb, sctp_hdr(skb), &asoc, &transport);  	/* Put back, the original values. */  	skb->network_header = saveip;  	skb->transport_header = savesctp;  	if (!sk) { -		ICMP_INC_STATS_BH(&init_net, ICMP_MIB_INERRORS); +		ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);  		return;  	}  	/* Warning:  The sock lock is held.  Remember to call @@ -610,8 +609,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)  		if (ICMP_FRAG_NEEDED == code) {  			sctp_icmp_frag_needed(sk, asoc, transport, info);  			goto out_unlock; -		} -		else { +		} else {  			if (ICMP_PROT_UNREACH == code) {  				sctp_icmp_proto_unreachable(sk, asoc,  							    transport); @@ -629,6 +627,9 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)  		err = EHOSTUNREACH;  		break; +	case ICMP_REDIRECT: +		sctp_icmp_redirect(sk, transport, skb); +		/* Fall through to out_unlock. */  	default:  		goto out_unlock;  	} @@ -661,7 +662,6 @@ static int sctp_rcv_ootb(struct sk_buff *skb)  {  	sctp_chunkhdr_t *ch;  	__u8 *ch_end; -	sctp_errhdr_t *err;  	ch = (sctp_chunkhdr_t *) skb->data; @@ -697,20 +697,6 @@ static int sctp_rcv_ootb(struct sk_buff *skb)  		if (SCTP_CID_INIT == ch->type && (void *)ch != skb->data)  			goto discard; -		/* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR -		 * or a COOKIE ACK the SCTP Packet should be silently -		 * discarded. -		 */ -		if (SCTP_CID_COOKIE_ACK == ch->type) -			goto discard; - -		if (SCTP_CID_ERROR == ch->type) { -			sctp_walk_errors(err, ch) { -				if (SCTP_ERROR_STALE_COOKIE == err->cause) -					goto discard; -			} -		} -  		ch = (sctp_chunkhdr_t *) ch_end;  	} while (ch_end < skb_tail_pointer(skb)); @@ -723,74 +709,73 @@ discard:  /* Insert endpoint into the hash table.  */  static void __sctp_hash_endpoint(struct sctp_endpoint *ep)  { +	struct net *net = sock_net(ep->base.sk);  	struct sctp_ep_common *epb;  	struct sctp_hashbucket *head;  	epb = &ep->base; -	epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); +	epb->hashent = sctp_ep_hashfn(net, epb->bind_addr.port);  	head = &sctp_ep_hashtable[epb->hashent]; -	sctp_write_lock(&head->lock); +	write_lock(&head->lock);  	hlist_add_head(&epb->node, &head->chain); -	sctp_write_unlock(&head->lock); +	write_unlock(&head->lock);  }  /* Add an endpoint to the hash. Local BH-safe. */  void sctp_hash_endpoint(struct sctp_endpoint *ep)  { -	sctp_local_bh_disable(); +	local_bh_disable();  	__sctp_hash_endpoint(ep); -	sctp_local_bh_enable(); +	local_bh_enable();  }  /* Remove endpoint from the hash table.  */  static void __sctp_unhash_endpoint(struct sctp_endpoint *ep)  { +	struct net *net = sock_net(ep->base.sk);  	struct sctp_hashbucket *head;  	struct sctp_ep_common *epb;  	epb = &ep->base; -	if (hlist_unhashed(&epb->node)) -		return; - -	epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); +	epb->hashent = sctp_ep_hashfn(net, epb->bind_addr.port);  	head = &sctp_ep_hashtable[epb->hashent]; -	sctp_write_lock(&head->lock); -	__hlist_del(&epb->node); -	sctp_write_unlock(&head->lock); +	write_lock(&head->lock); +	hlist_del_init(&epb->node); +	write_unlock(&head->lock);  }  /* Remove endpoint from the hash.  Local BH-safe. */  void sctp_unhash_endpoint(struct sctp_endpoint *ep)  { -	sctp_local_bh_disable(); +	local_bh_disable();  	__sctp_unhash_endpoint(ep); -	sctp_local_bh_enable(); +	local_bh_enable();  }  /* Look up an endpoint. */ -static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr) +static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(struct net *net, +						const union sctp_addr *laddr)  {  	struct sctp_hashbucket *head;  	struct sctp_ep_common *epb;  	struct sctp_endpoint *ep; -	struct hlist_node *node;  	int hash; -	hash = sctp_ep_hashfn(ntohs(laddr->v4.sin_port)); +	hash = sctp_ep_hashfn(net, ntohs(laddr->v4.sin_port));  	head = &sctp_ep_hashtable[hash];  	read_lock(&head->lock); -	sctp_for_each_hentry(epb, node, &head->chain) { +	sctp_for_each_hentry(epb, &head->chain) {  		ep = sctp_ep(epb); -		if (sctp_endpoint_is_match(ep, laddr)) +		if (sctp_endpoint_is_match(ep, net, laddr))  			goto hit;  	} -	ep = sctp_sk((sctp_get_ctl_sock()))->ep; +	ep = sctp_sk(net->sctp.ctl_sock)->ep;  hit:  	sctp_endpoint_hold(ep); @@ -801,19 +786,21 @@ hit:  /* Insert association into the hash table.  */  static void __sctp_hash_established(struct sctp_association *asoc)  { +	struct net *net = sock_net(asoc->base.sk);  	struct sctp_ep_common *epb;  	struct sctp_hashbucket *head;  	epb = &asoc->base;  	/* Calculate which chain this entry will belong to. */ -	epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, asoc->peer.port); +	epb->hashent = sctp_assoc_hashfn(net, epb->bind_addr.port, +					 asoc->peer.port);  	head = &sctp_assoc_hashtable[epb->hashent]; -	sctp_write_lock(&head->lock); +	write_lock(&head->lock);  	hlist_add_head(&epb->node, &head->chain); -	sctp_write_unlock(&head->lock); +	write_unlock(&head->lock);  }  /* Add an association to the hash. Local BH-safe. */ @@ -822,27 +809,28 @@ void sctp_hash_established(struct sctp_association *asoc)  	if (asoc->temp)  		return; -	sctp_local_bh_disable(); +	local_bh_disable();  	__sctp_hash_established(asoc); -	sctp_local_bh_enable(); +	local_bh_enable();  }  /* Remove association from the hash table.  */  static void __sctp_unhash_established(struct sctp_association *asoc)  { +	struct net *net = sock_net(asoc->base.sk);  	struct sctp_hashbucket *head;  	struct sctp_ep_common *epb;  	epb = &asoc->base; -	epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, +	epb->hashent = sctp_assoc_hashfn(net, epb->bind_addr.port,  					 asoc->peer.port);  	head = &sctp_assoc_hashtable[epb->hashent]; -	sctp_write_lock(&head->lock); -	__hlist_del(&epb->node); -	sctp_write_unlock(&head->lock); +	write_lock(&head->lock); +	hlist_del_init(&epb->node); +	write_unlock(&head->lock);  }  /* Remove association from the hash table.  Local BH-safe. */ @@ -851,13 +839,14 @@ void sctp_unhash_established(struct sctp_association *asoc)  	if (asoc->temp)  		return; -	sctp_local_bh_disable(); +	local_bh_disable();  	__sctp_unhash_established(asoc); -	sctp_local_bh_enable(); +	local_bh_enable();  }  /* Look up an association. */  static struct sctp_association *__sctp_lookup_association( +					struct net *net,  					const union sctp_addr *local,  					const union sctp_addr *peer,  					struct sctp_transport **pt) @@ -866,18 +855,18 @@ static struct sctp_association *__sctp_lookup_association(  	struct sctp_ep_common *epb;  	struct sctp_association *asoc;  	struct sctp_transport *transport; -	struct hlist_node *node;  	int hash;  	/* Optimize here for direct hit, only listening connections can  	 * have wildcards anyways.  	 */ -	hash = sctp_assoc_hashfn(ntohs(local->v4.sin_port), ntohs(peer->v4.sin_port)); +	hash = sctp_assoc_hashfn(net, ntohs(local->v4.sin_port), +				 ntohs(peer->v4.sin_port));  	head = &sctp_assoc_hashtable[hash];  	read_lock(&head->lock); -	sctp_for_each_hentry(epb, node, &head->chain) { +	sctp_for_each_hentry(epb, &head->chain) {  		asoc = sctp_assoc(epb); -		transport = sctp_assoc_is_match(asoc, local, peer); +		transport = sctp_assoc_is_match(asoc, net, local, peer);  		if (transport)  			goto hit;  	} @@ -894,28 +883,30 @@ hit:  }  /* Look up an association. BH-safe. */ -SCTP_STATIC -struct sctp_association *sctp_lookup_association(const union sctp_addr *laddr, +static +struct sctp_association *sctp_lookup_association(struct net *net, +						 const union sctp_addr *laddr,  						 const union sctp_addr *paddr, -					    struct sctp_transport **transportp) +						 struct sctp_transport **transportp)  {  	struct sctp_association *asoc; -	sctp_local_bh_disable(); -	asoc = __sctp_lookup_association(laddr, paddr, transportp); -	sctp_local_bh_enable(); +	local_bh_disable(); +	asoc = __sctp_lookup_association(net, laddr, paddr, transportp); +	local_bh_enable();  	return asoc;  }  /* Is there an association matching the given local and peer addresses? */ -int sctp_has_association(const union sctp_addr *laddr, +int sctp_has_association(struct net *net, +			 const union sctp_addr *laddr,  			 const union sctp_addr *paddr)  {  	struct sctp_association *asoc;  	struct sctp_transport *transport; -	if ((asoc = sctp_lookup_association(laddr, paddr, &transport))) { +	if ((asoc = sctp_lookup_association(net, laddr, paddr, &transport))) {  		sctp_association_put(asoc);  		return 1;  	} @@ -941,21 +932,19 @@ int sctp_has_association(const union sctp_addr *laddr,   * in certain circumstances.   *   */ -static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, +static struct sctp_association *__sctp_rcv_init_lookup(struct net *net, +	struct sk_buff *skb,  	const union sctp_addr *laddr, struct sctp_transport **transportp)  {  	struct sctp_association *asoc;  	union sctp_addr addr;  	union sctp_addr *paddr = &addr;  	struct sctphdr *sh = sctp_hdr(skb); -	sctp_chunkhdr_t *ch;  	union sctp_params params;  	sctp_init_chunk_t *init;  	struct sctp_transport *transport;  	struct sctp_af *af; -	ch = (sctp_chunkhdr_t *) skb->data; -  	/*  	 * This code will NOT touch anything inside the chunk--it is  	 * strictly READ-ONLY. @@ -984,7 +973,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,  		af->from_addr_param(paddr, params.addr, sh->source, 0); -		asoc = __sctp_lookup_association(laddr, paddr, &transport); +		asoc = __sctp_lookup_association(net, laddr, paddr, &transport);  		if (asoc)  			return asoc;  	} @@ -1007,6 +996,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,   * subsequent ASCONF Chunks. If found, proceed to rule D4.   */  static struct sctp_association *__sctp_rcv_asconf_lookup( +					struct net *net,  					sctp_chunkhdr_t *ch,  					const union sctp_addr *laddr,  					__be16 peer_port, @@ -1020,13 +1010,13 @@ static struct sctp_association *__sctp_rcv_asconf_lookup(  	/* Skip over the ADDIP header and find the Address parameter */  	param = (union sctp_addr_param *)(asconf + 1); -	af = sctp_get_af_specific(param_type2af(param->v4.param_hdr.type)); +	af = sctp_get_af_specific(param_type2af(param->p.type));  	if (unlikely(!af))  		return NULL;  	af->from_addr_param(&paddr, param, peer_port, 0); -	return __sctp_lookup_association(laddr, &paddr, transportp); +	return __sctp_lookup_association(net, laddr, &paddr, transportp);  } @@ -1037,9 +1027,10 @@ static struct sctp_association *__sctp_rcv_asconf_lookup(  *    association.  *  * This means that any chunks that can help us identify the association need -* to be looked at to find this assocation. +* to be looked at to find this association.  */ -static struct sctp_association *__sctp_rcv_walk_lookup(struct sk_buff *skb, +static struct sctp_association *__sctp_rcv_walk_lookup(struct net *net, +				      struct sk_buff *skb,  				      const union sctp_addr *laddr,  				      struct sctp_transport **transportp)  { @@ -1062,30 +1053,31 @@ static struct sctp_association *__sctp_rcv_walk_lookup(struct sk_buff *skb,  		if (ch_end > skb_tail_pointer(skb))  			break; -		switch(ch->type) { -		    case SCTP_CID_AUTH: -			    have_auth = chunk_num; -			    break; - -		    case SCTP_CID_COOKIE_ECHO: -			    /* If a packet arrives containing an AUTH chunk as -			     * a first chunk, a COOKIE-ECHO chunk as the second -			     * chunk, and possibly more chunks after them, and -			     * the receiver does not have an STCB for that -			     * packet, then authentication is based on -			     * the contents of the COOKIE- ECHO chunk. -			     */ -			    if (have_auth == 1 && chunk_num == 2) -				    return NULL; -			    break; - -		    case SCTP_CID_ASCONF: -			    if (have_auth || sctp_addip_noauth) -				    asoc = __sctp_rcv_asconf_lookup(ch, laddr, -							sctp_hdr(skb)->source, -							transportp); -		    default: -			    break; +		switch (ch->type) { +		case SCTP_CID_AUTH: +			have_auth = chunk_num; +			break; + +		case SCTP_CID_COOKIE_ECHO: +			/* If a packet arrives containing an AUTH chunk as +			 * a first chunk, a COOKIE-ECHO chunk as the second +			 * chunk, and possibly more chunks after them, and +			 * the receiver does not have an STCB for that +			 * packet, then authentication is based on +			 * the contents of the COOKIE- ECHO chunk. +			 */ +			if (have_auth == 1 && chunk_num == 2) +				return NULL; +			break; + +		case SCTP_CID_ASCONF: +			if (have_auth || net->sctp.addip_noauth) +				asoc = __sctp_rcv_asconf_lookup( +						net, ch, laddr, +						sctp_hdr(skb)->source, +						transportp); +		default: +			break;  		}  		if (asoc) @@ -1104,7 +1096,8 @@ static struct sctp_association *__sctp_rcv_walk_lookup(struct sk_buff *skb,   * include looking inside of INIT/INIT-ACK chunks or after the AUTH   * chunks.   */ -static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb, +static struct sctp_association *__sctp_rcv_lookup_harder(struct net *net, +				      struct sk_buff *skb,  				      const union sctp_addr *laddr,  				      struct sctp_transport **transportp)  { @@ -1121,37 +1114,29 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb,  		return NULL;  	/* If this is INIT/INIT-ACK look inside the chunk too. */ -	switch (ch->type) { -	case SCTP_CID_INIT: -	case SCTP_CID_INIT_ACK: -		return __sctp_rcv_init_lookup(skb, laddr, transportp); -		break; +	if (ch->type == SCTP_CID_INIT || ch->type == SCTP_CID_INIT_ACK) +		return __sctp_rcv_init_lookup(net, skb, laddr, transportp); -	default: -		return __sctp_rcv_walk_lookup(skb, laddr, transportp); -		break; -	} - - -	return NULL; +	return __sctp_rcv_walk_lookup(net, skb, laddr, transportp);  }  /* Lookup an association for an inbound skb. */ -static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb, +static struct sctp_association *__sctp_rcv_lookup(struct net *net, +				      struct sk_buff *skb,  				      const union sctp_addr *paddr,  				      const union sctp_addr *laddr,  				      struct sctp_transport **transportp)  {  	struct sctp_association *asoc; -	asoc = __sctp_lookup_association(laddr, paddr, transportp); +	asoc = __sctp_lookup_association(net, laddr, paddr, transportp);  	/* Further lookup for INIT/INIT-ACK packets.  	 * SCTP Implementors Guide, 2.18 Handling of address  	 * parameters within the INIT or INIT-ACK.  	 */  	if (!asoc) -		asoc = __sctp_rcv_lookup_harder(skb, laddr, transportp); +		asoc = __sctp_rcv_lookup_harder(net, skb, laddr, transportp);  	return asoc;  }  | 
