diff options
Diffstat (limited to 'net/sctp/input.c')
-rw-r--r-- | net/sctp/input.c | 117 |
1 files changed, 70 insertions, 47 deletions
diff --git a/net/sctp/input.c b/net/sctp/input.c index e64d5210ed13..8bd3c279427e 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -66,12 +66,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,7 +83,7 @@ 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; @@ -96,7 +99,7 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb) 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; @@ -129,11 +132,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) 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 +149,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 +182,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; @@ -200,7 +204,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 +220,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; } } @@ -272,9 +276,9 @@ int sctp_rcv(struct sk_buff *skb) 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); } @@ -289,7 +293,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; @@ -462,11 +466,13 @@ void sctp_icmp_proto_unreachable(struct sock *sk, } } else { + struct net *net = sock_net(sk); + if (timer_pending(&t->proto_unreach_timer) && 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); @@ -474,7 +480,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) @@ -503,7 +509,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; @@ -539,7 +545,7 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb, * 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; @@ -586,9 +592,10 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info) struct inet_sock *inet; sk_buff_data_t 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; } @@ -597,12 +604,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 @@ -723,12 +730,13 @@ 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); @@ -747,12 +755,13 @@ void sctp_hash_endpoint(struct sctp_endpoint *ep) /* 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; - 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]; @@ -770,7 +779,8 @@ void sctp_unhash_endpoint(struct sctp_endpoint *ep) } /* 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; @@ -778,16 +788,16 @@ static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *l 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) { 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); @@ -798,13 +808,15 @@ 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]; @@ -827,12 +839,13 @@ void sctp_hash_established(struct sctp_association *asoc) /* 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]; @@ -855,6 +868,7 @@ void sctp_unhash_established(struct sctp_association *asoc) /* 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) @@ -869,12 +883,13 @@ static struct sctp_association *__sctp_lookup_association( /* 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) { 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; } @@ -892,27 +907,29 @@ hit: /* Look up an association. BH-safe. */ SCTP_STATIC -struct sctp_association *sctp_lookup_association(const union sctp_addr *laddr, +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_association *asoc; sctp_local_bh_disable(); - asoc = __sctp_lookup_association(laddr, paddr, transportp); + asoc = __sctp_lookup_association(net, laddr, paddr, transportp); sctp_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; } @@ -938,7 +955,8 @@ 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; @@ -978,7 +996,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; } @@ -1001,6 +1019,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,7 +1039,7 @@ static struct sctp_association *__sctp_rcv_asconf_lookup( af->from_addr_param(&paddr, param, peer_port, 0); - return __sctp_lookup_association(laddr, &paddr, transportp); + return __sctp_lookup_association(net, laddr, &paddr, transportp); } @@ -1033,7 +1052,8 @@ static struct sctp_association *__sctp_rcv_asconf_lookup( * This means that any chunks that can help us identify the association need * 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) { @@ -1074,8 +1094,9 @@ static struct sctp_association *__sctp_rcv_walk_lookup(struct sk_buff *skb, break; case SCTP_CID_ASCONF: - if (have_auth || sctp_addip_noauth) - asoc = __sctp_rcv_asconf_lookup(ch, laddr, + if (have_auth || net->sctp.addip_noauth) + asoc = __sctp_rcv_asconf_lookup( + net, ch, laddr, sctp_hdr(skb)->source, transportp); default: @@ -1098,7 +1119,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) { @@ -1118,11 +1140,11 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb, switch (ch->type) { case SCTP_CID_INIT: case SCTP_CID_INIT_ACK: - return __sctp_rcv_init_lookup(skb, laddr, transportp); + return __sctp_rcv_init_lookup(net, skb, laddr, transportp); break; default: - return __sctp_rcv_walk_lookup(skb, laddr, transportp); + return __sctp_rcv_walk_lookup(net, skb, laddr, transportp); break; } @@ -1131,21 +1153,22 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb, } /* 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; } |