tipc: fix broadcast link synchronization problem
[cascardo/linux.git] / net / sctp / input.c
index 69444d3..a2ea1d1 100644 (file)
@@ -605,7 +605,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
                /* PMTU discovery (RFC1191) */
                if (ICMP_FRAG_NEEDED == code) {
                        sctp_icmp_frag_needed(sk, asoc, transport,
-                                             WORD_TRUNC(info));
+                                             SCTP_TRUNC4(info));
                        goto out_unlock;
                } else {
                        if (ICMP_PROT_UNREACH == code) {
@@ -673,7 +673,7 @@ static int sctp_rcv_ootb(struct sk_buff *skb)
                if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t))
                        break;
 
-               ch_end = offset + WORD_ROUND(ntohs(ch->length));
+               ch_end = offset + SCTP_PAD4(ntohs(ch->length));
                if (ch_end > skb->len)
                        break;
 
@@ -796,27 +796,34 @@ struct sctp_hash_cmp_arg {
 static inline int sctp_hash_cmp(struct rhashtable_compare_arg *arg,
                                const void *ptr)
 {
+       struct sctp_transport *t = (struct sctp_transport *)ptr;
        const struct sctp_hash_cmp_arg *x = arg->key;
-       const struct sctp_transport *t = ptr;
-       struct sctp_association *asoc = t->asoc;
-       const struct net *net = x->net;
+       struct sctp_association *asoc;
+       int err = 1;
 
        if (!sctp_cmp_addr_exact(&t->ipaddr, x->paddr))
-               return 1;
-       if (!net_eq(sock_net(asoc->base.sk), net))
-               return 1;
+               return err;
+       if (!sctp_transport_hold(t))
+               return err;
+
+       asoc = t->asoc;
+       if (!net_eq(sock_net(asoc->base.sk), x->net))
+               goto out;
        if (x->ep) {
                if (x->ep != asoc->ep)
-                       return 1;
+                       goto out;
        } else {
                if (x->laddr->v4.sin_port != htons(asoc->base.bind_addr.port))
-                       return 1;
+                       goto out;
                if (!sctp_bind_addr_match(&asoc->base.bind_addr,
                                          x->laddr, sctp_sk(asoc->base.sk)))
-                       return 1;
+                       goto out;
        }
 
-       return 0;
+       err = 0;
+out:
+       sctp_transport_put(t);
+       return err;
 }
 
 static inline u32 sctp_hash_obj(const void *data, u32 len, u32 seed)
@@ -1121,7 +1128,7 @@ static struct sctp_association *__sctp_rcv_walk_lookup(struct net *net,
                if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t))
                        break;
 
-               ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
+               ch_end = ((__u8 *)ch) + SCTP_PAD4(ntohs(ch->length));
                if (ch_end > skb_tail_pointer(skb))
                        break;
 
@@ -1190,7 +1197,7 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct net *net,
         * that the chunk length doesn't cause overflow.  Otherwise, we'll
         * walk off the end.
         */
-       if (WORD_ROUND(ntohs(ch->length)) > skb->len)
+       if (SCTP_PAD4(ntohs(ch->length)) > skb->len)
                return NULL;
 
        /* If this is INIT/INIT-ACK look inside the chunk too. */