X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=net%2Fsctp%2Finput.c;h=885109fb3dda129a551ccac0ca4e88d29236c712;hb=21564fd2a3deb48200b595332f9ed4c9f311f2a7;hp=1662f9cc869e0a1cd463b7f3575c0c243dfc4ded;hpb=d90125bfe958ed0451c6b98f831c86aba08b43d5;p=powerpc.git diff --git a/net/sctp/input.c b/net/sctp/input.c index 1662f9cc86..885109fb3d 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -79,14 +79,10 @@ static void 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) { - struct sctphdr *sh; - __u32 cmp, val; struct sk_buff *list = skb_shinfo(skb)->frag_list; - - sh = (struct sctphdr *) skb->h.raw; - cmp = ntohl(sh->checksum); - - val = sctp_start_cksum((__u8 *)sh, skb_headlen(skb)); + struct sctphdr *sh = sctp_hdr(skb); + __u32 cmp = ntohl(sh->checksum); + __u32 val = sctp_start_cksum((__u8 *)sh, skb_headlen(skb)); for (; list; list = list->next) val = sctp_update_cksum((__u8 *)list->data, skb_headlen(list), @@ -135,13 +131,16 @@ int sctp_rcv(struct sk_buff *skb) SCTP_INC_STATS_BH(SCTP_MIB_INSCTPPACKS); - sh = (struct sctphdr *) skb->h.raw; + if (skb_linearize(skb)) + goto discard_it; + + sh = sctp_hdr(skb); /* Pull up the IP and SCTP headers. */ - __skb_pull(skb, skb->h.raw - skb->data); + __skb_pull(skb, skb_transport_offset(skb)); if (skb->len < sizeof(struct sctphdr)) goto discard_it; - if (sctp_rcv_checksum(skb) < 0) + if (!skb_csum_unnecessary(skb) && sctp_rcv_checksum(skb) < 0) goto discard_it; skb_pull(skb, sizeof(struct sctphdr)); @@ -150,7 +149,7 @@ int sctp_rcv(struct sk_buff *skb) if (skb->len < sizeof(struct sctp_chunkhdr)) goto discard_it; - family = ipver2af(skb->nh.iph->version); + family = ipver2af(ip_hdr(skb)->version); af = sctp_get_af_specific(family); if (unlikely(!af)) goto discard_it; @@ -170,7 +169,8 @@ int sctp_rcv(struct sk_buff *skb) * IP broadcast addresses cannot be used in an SCTP transport * address." */ - if (!af->addr_valid(&src, NULL) || !af->addr_valid(&dest, NULL)) + if (!af->addr_valid(&src, NULL, skb) || + !af->addr_valid(&dest, NULL, skb)) goto discard_it; asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport); @@ -216,18 +216,12 @@ int sctp_rcv(struct sk_buff *skb) } } - /* SCTP seems to always need a timestamp right now (FIXME) */ - if (skb->tstamp.off_sec == 0) { - __net_timestamp(skb); - sock_enable_timestamp(sk); - } - if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb, family)) goto discard_release; nf_reset(skb); - if (sk_filter(sk, skb, 1)) - goto discard_release; + if (sk_filter(sk, skb)) + goto discard_release; /* Create an SCTP packet structure. */ chunk = sctp_chunkify(skb, asoc, sk); @@ -253,10 +247,13 @@ int sctp_rcv(struct sk_buff *skb) */ sctp_bh_lock_sock(sk); - if (sock_owned_by_user(sk)) + if (sock_owned_by_user(sk)) { + SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_BACKLOG); sctp_add_backlog(sk, skb); - else + } else { + SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_SOFTIRQ); sctp_inq_push(&chunk->rcvr->inqueue, chunk); + } sctp_bh_unlock_sock(sk); @@ -269,6 +266,7 @@ int sctp_rcv(struct sk_buff *skb) return 0; discard_it: + SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_DISCARDS); kfree_skb(skb); return 0; @@ -290,11 +288,11 @@ discard_release: int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) { struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk; - struct sctp_inq *inqueue = &chunk->rcvr->inqueue; - struct sctp_ep_common *rcvr = NULL; + struct sctp_inq *inqueue = &chunk->rcvr->inqueue; + struct sctp_ep_common *rcvr = NULL; int backloged = 0; - rcvr = chunk->rcvr; + rcvr = chunk->rcvr; /* If the rcvr is dead then the association or endpoint * has been deleted and we can safely drop the chunk @@ -344,7 +342,7 @@ done: else BUG(); - return 0; + return 0; } static void sctp_add_backlog(struct sock *sk, struct sk_buff *skb) @@ -382,7 +380,7 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, * pmtu discovery on this transport. */ t->pathmtu = SCTP_DEFAULT_MINSEGMENT; - t->param_flags = (t->param_flags & ~SPP_HB) | + t->param_flags = (t->param_flags & ~SPP_PMTUD) | SPP_PMTUD_DISABLE; } else { t->pathmtu = pmtu; @@ -396,7 +394,7 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, * Normally, if PMTU discovery is disabled, an ICMP Fragmentation * Needed will never be sent, but if a message was sent before * PMTU discovery was disabled that was larger than the PMTU, it - * would not be fragmented, so it must be re-transmitted fragmented. + * would not be fragmented, so it must be re-transmitted fragmented. */ sctp_retransmit(&asoc->outqueue, t, SCTP_RTXR_PMTUD); } @@ -413,8 +411,8 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, * */ void sctp_icmp_proto_unreachable(struct sock *sk, - struct sctp_association *asoc, - struct sctp_transport *t) + struct sctp_association *asoc, + struct sctp_transport *t) { SCTP_DEBUG_PRINTK("%s\n", __FUNCTION__); @@ -507,30 +505,30 @@ 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; - struct sctphdr *sh = (struct sctphdr *)(skb->data + (iph->ihl <<2)); - int type = skb->h.icmph->type; - int code = skb->h.icmph->code; + const int ihlen = iph->ihl * 4; + const int type = icmp_hdr(skb)->type; + const int code = icmp_hdr(skb)->code; struct sock *sk; struct sctp_association *asoc = NULL; struct sctp_transport *transport; struct inet_sock *inet; - char *saveip, *savesctp; + sk_buff_data_t saveip, savesctp; int err; - if (skb->len < ((iph->ihl << 2) + 8)) { + if (skb->len < ihlen + 8) { ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); return; } /* Fix up skb to look at the embedded net header. */ - saveip = skb->nh.raw; - savesctp = skb->h.raw; - skb->nh.iph = iph; - skb->h.raw = (char *)sh; - sk = sctp_err_lookup(AF_INET, skb, sh, &asoc, &transport); - /* Put back, the original pointers. */ - skb->nh.raw = saveip; - skb->h.raw = savesctp; + saveip = skb->network_header; + 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); + /* Put back, the original values. */ + skb->network_header = saveip; + skb->transport_header = savesctp; if (!sk) { ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); return; @@ -613,7 +611,7 @@ int sctp_rcv_ootb(struct sk_buff *skb) break; ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); - if (ch_end > skb->tail) + if (ch_end > skb_tail_pointer(skb)) break; /* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the @@ -645,7 +643,7 @@ int sctp_rcv_ootb(struct sk_buff *skb) } ch = (sctp_chunkhdr_t *) ch_end; - } while (ch_end < skb->tail); + } while (ch_end < skb_tail_pointer(skb)); return 0; @@ -723,7 +721,7 @@ static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *l struct sctp_endpoint *ep; int hash; - hash = sctp_ep_hashfn(laddr->v4.sin_port); + hash = sctp_ep_hashfn(ntohs(laddr->v4.sin_port)); head = &sctp_ep_hashtable[hash]; read_lock(&head->lock); for (epb = head->chain; epb; epb = epb->next) { @@ -768,6 +766,9 @@ static void __sctp_hash_established(struct sctp_association *asoc) /* Add an association to the hash. Local BH-safe. */ void sctp_hash_established(struct sctp_association *asoc) { + if (asoc->temp) + return; + sctp_local_bh_disable(); __sctp_hash_established(asoc); sctp_local_bh_enable(); @@ -801,6 +802,9 @@ static void __sctp_unhash_established(struct sctp_association *asoc) /* Remove association from the hash table. Local BH-safe. */ void sctp_unhash_established(struct sctp_association *asoc) { + if (asoc->temp) + return; + sctp_local_bh_disable(); __sctp_unhash_established(asoc); sctp_local_bh_enable(); @@ -821,7 +825,7 @@ static struct sctp_association *__sctp_lookup_association( /* Optimize here for direct hit, only listening connections can * have wildcards anyways. */ - hash = sctp_assoc_hashfn(local->v4.sin_port, peer->v4.sin_port); + hash = sctp_assoc_hashfn(ntohs(local->v4.sin_port), ntohs(peer->v4.sin_port)); head = &sctp_assoc_hashtable[hash]; read_lock(&head->lock); for (epb = head->chain; epb; epb = epb->next) { @@ -896,7 +900,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, struct sctp_association *asoc; union sctp_addr addr; union sctp_addr *paddr = &addr; - struct sctphdr *sh = (struct sctphdr *) skb->h.raw; + struct sctphdr *sh = sctp_hdr(skb); sctp_chunkhdr_t *ch; union sctp_params params; sctp_init_chunk_t *init; @@ -948,7 +952,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, if (!af) continue; - af->from_addr_param(paddr, params.addr, ntohs(sh->source), 0); + af->from_addr_param(paddr, params.addr, sh->source, 0); asoc = __sctp_lookup_association(laddr, paddr, &transport); if (asoc)