]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'pending' of master.kernel.org:/pub/scm/linux/kernel/git/vxy/lksctp-dev
authorDavid S. Miller <davem@sunset.davemloft.net>
Tue, 13 Nov 2007 02:16:13 +0000 (18:16 -0800)
committerDavid S. Miller <davem@sunset.davemloft.net>
Tue, 13 Nov 2007 02:16:13 +0000 (18:16 -0800)
19 files changed:
include/net/sctp/command.h
include/net/sctp/constants.h
include/net/sctp/sctp.h
include/net/sctp/structs.h
net/sctp/associola.c
net/sctp/bind_addr.c
net/sctp/endpointola.c
net/sctp/input.c
net/sctp/inqueue.c
net/sctp/outqueue.c
net/sctp/proc.c
net/sctp/protocol.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/sm_statefuns.c
net/sctp/socket.c
net/sctp/sysctl.c
net/sctp/transport.c
net/sctp/ulpqueue.c

index b8733364557ff6d78403584c383a2a2e4334044c..c1f79767357196aecd1aff0235a0445605fe1edd 100644 (file)
@@ -103,6 +103,7 @@ typedef enum {
        SCTP_CMD_ASSOC_CHANGE,   /* generate and send assoc_change event */
        SCTP_CMD_ADAPTATION_IND, /* generate and send adaptation event */
        SCTP_CMD_ASSOC_SHKEY,    /* generate the association shared keys */
+       SCTP_CMD_T1_RETRAN,      /* Mark for retransmission after T1 timeout  */
        SCTP_CMD_LAST
 } sctp_verb_t;
 
index da8354e8e33c5269fa92ab4a1dd4a8f4d4971ad8..f30b537d69525168e078a2eb8a0c39a51ef6bdc1 100644 (file)
@@ -186,6 +186,8 @@ typedef enum {
        SCTP_IERROR_AUTH_BAD_HMAC,
        SCTP_IERROR_AUTH_BAD_KEYID,
        SCTP_IERROR_PROTO_VIOLATION,
+       SCTP_IERROR_ERROR,
+       SCTP_IERROR_ABORT,
 } sctp_ierror_t;
 
 
@@ -407,6 +409,7 @@ typedef enum {
        SCTP_RTXR_T3_RTX,
        SCTP_RTXR_FAST_RTX,
        SCTP_RTXR_PMTUD,
+       SCTP_RTXR_T1_RTX,
 } sctp_retransmit_reason_t;
 
 /* Reasons to lower cwnd. */
index 93eb708609e7ef588c3ee517ba80d106c481c140..34318a33a94c0471126a763439fe62ce695aa008 100644 (file)
@@ -65,7 +65,6 @@
 
 
 #ifdef TEST_FRAME
-#undef CONFIG_PROC_FS
 #undef CONFIG_SCTP_DBG_OBJCNT
 #undef CONFIG_SYSCTL
 #endif /* TEST_FRAME */
@@ -267,6 +266,7 @@ enum
        SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS,
        SCTP_MIB_DELAY_SACK_EXPIREDS,
        SCTP_MIB_AUTOCLOSE_EXPIREDS,
+       SCTP_MIB_T1_RETRANSMITS,
        SCTP_MIB_T3_RETRANSMITS,
        SCTP_MIB_PMTUD_RETRANSMITS,
        SCTP_MIB_FAST_RETRANSMITS,
@@ -664,6 +664,9 @@ static inline int sctp_vtag_hashfn(__u16 lport, __u16 rport, __u32 vtag)
        return (h & (sctp_assoc_hashsize-1));
 }
 
+#define sctp_for_each_hentry(epb, node, head) \
+       hlist_for_each_entry(epb, node, head, node)
+
 /* Is a socket of this style? */
 #define sctp_style(sk, style) __sctp_style((sk), (SCTP_SOCKET_##style))
 static inline int __sctp_style(const struct sock *sk, sctp_socket_type_t style)
index ef892e00c83365acdccb3810158277364b5ddae9..eb3113c38a943469c74b76163f6ee448b528d66f 100644 (file)
@@ -100,20 +100,19 @@ struct crypto_hash;
 struct sctp_bind_bucket {
        unsigned short  port;
        unsigned short  fastreuse;
-       struct sctp_bind_bucket *next;
-       struct sctp_bind_bucket **pprev;
+       struct hlist_node       node;
        struct hlist_head       owner;
 };
 
 struct sctp_bind_hashbucket {
        spinlock_t      lock;
-       struct sctp_bind_bucket *chain;
+       struct hlist_head       chain;
 };
 
 /* Used for hashing all associations.  */
 struct sctp_hashbucket {
        rwlock_t        lock;
-       struct sctp_ep_common  *chain;
+       struct hlist_head       chain;
 } __attribute__((__aligned__(8)));
 
 
@@ -212,6 +211,7 @@ extern struct sctp_globals {
        
        /* Flag to indicate if addip is enabled. */
        int addip_enable;
+       int addip_noauth_enable;
 
        /* Flag to indicate if PR-SCTP is enabled. */
        int prsctp_enable;
@@ -249,6 +249,7 @@ extern struct sctp_globals {
 #define sctp_local_addr_list           (sctp_globals.local_addr_list)
 #define sctp_local_addr_lock           (sctp_globals.addr_list_lock)
 #define sctp_addip_enable              (sctp_globals.addip_enable)
+#define sctp_addip_noauth              (sctp_globals.addip_noauth_enable)
 #define sctp_prsctp_enable             (sctp_globals.prsctp_enable)
 #define sctp_auth_enable               (sctp_globals.auth_enable)
 
@@ -873,10 +874,11 @@ struct sctp_transport {
         * address list derived from the INIT or INIT ACK chunk, a
         * number of data elements needs to be maintained including:
         */
-       __u32 rtt;              /* This is the most recent RTT.  */
-
        /* RTO         : The current retransmission timeout value.  */
        unsigned long rto;
+       unsigned long last_rto;
+
+       __u32 rtt;              /* This is the most recent RTT.  */
 
        /* RTTVAR      : The current RTT variation.  */
        __u32 rttvar;
@@ -1184,9 +1186,7 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
                        int flags);
 int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
                       __u8 use_as_src, gfp_t gfp);
-int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
-                       void fastcall (*rcu_call)(struct rcu_head *,
-                                         void (*func)(struct rcu_head *)));
+int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *);
 int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *,
                         struct sctp_sock *);
 union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr  *bp,
@@ -1229,8 +1229,7 @@ typedef enum {
 
 struct sctp_ep_common {
        /* Fields to help us manage our entries in the hash tables. */
-       struct sctp_ep_common *next;
-       struct sctp_ep_common **pprev;
+       struct hlist_node node;
        int hashent;
 
        /* Runtime type information.  What kind of endpoint is this? */
@@ -1541,7 +1540,6 @@ struct sctp_association {
                __u8    asconf_capable;  /* Does peer support ADDIP? */
                __u8    prsctp_capable;  /* Can peer do PR-SCTP? */
                __u8    auth_capable;    /* Is peer doing SCTP-AUTH? */
-               __u8    addip_capable;   /* Can peer do ADD-IP */
 
                __u32   adaptation_ind;  /* Adaptation Code point. */
 
index 03158e3665da0b34786843104d4ab5f4b5fa4736..013e3d3ab0f1a6217868785c5d160b0acb0eacb8 100644 (file)
@@ -262,10 +262,14 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
         */
        asoc->peer.sack_needed = 1;
 
-       /* Assume that the peer recongizes ASCONF until reported otherwise
-        * via an ERROR chunk.
+       /* Assume that the peer will tell us if he recognizes ASCONF
+        * as part of INIT exchange.
+        * The sctp_addip_noauth option is there for backward compatibilty
+        * and will revert old behavior.
         */
-       asoc->peer.asconf_capable = 1;
+       asoc->peer.asconf_capable = 0;
+       if (sctp_addip_noauth)
+               asoc->peer.asconf_capable = 1;
 
        /* Create an input queue.  */
        sctp_inq_init(&asoc->base.inqueue);
index dfffa94fb9f636366616ca3e349ffcfee746f5cb..cae95af9a8cc147f2652c7b2a3c6c80880fd0f7a 100644 (file)
@@ -180,9 +180,7 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
 /* Delete an address from the bind address list in the SCTP_bind_addr
  * structure.
  */
-int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr,
-                       void fastcall (*rcu_call)(struct rcu_head *head,
-                                        void (*func)(struct rcu_head *head)))
+int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr)
 {
        struct sctp_sockaddr_entry *addr, *temp;
 
@@ -198,15 +196,10 @@ int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr,
                }
        }
 
-       /* Call the rcu callback provided in the args.  This function is
-        * called by both BH packet processing and user side socket option
-        * processing, but it works on different lists in those 2 contexts.
-        * Each context provides it's own callback, whether call_rcu_bh()
-        * or call_rcu(), to make sure that we wait for an appropriate time.
-        */
        if (addr && !addr->valid) {
-               rcu_call(&addr->rcu, sctp_local_addr_free);
+               call_rcu(&addr->rcu, sctp_local_addr_free);
                SCTP_DBG_OBJCNT_DEC(addr);
+               return 0;
        }
 
        return -EINVAL;
index 2d2d81ef4a69011d89e3dcc9ecdc15ce35dc806b..de6f505d6ff8250291972d4e53c391dcf1548e57 100644 (file)
@@ -328,24 +328,35 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc(
        const union sctp_addr *paddr,
        struct sctp_transport **transport)
 {
+       struct sctp_association *asoc = NULL;
+       struct sctp_transport *t = NULL;
+       struct sctp_hashbucket *head;
+       struct sctp_ep_common *epb;
+       struct hlist_node *node;
+       int hash;
        int rport;
-       struct sctp_association *asoc;
-       struct list_head *pos;
 
+       *transport = NULL;
        rport = ntohs(paddr->v4.sin_port);
 
-       list_for_each(pos, &ep->asocs) {
-               asoc = list_entry(pos, struct sctp_association, asocs);
-               if (rport == asoc->peer.port) {
-                       *transport = sctp_assoc_lookup_paddr(asoc, paddr);
-
-                       if (*transport)
-                               return asoc;
+       hash = sctp_assoc_hashfn(ep->base.bind_addr.port, rport);
+       head = &sctp_assoc_hashtable[hash];
+       read_lock(&head->lock);
+       sctp_for_each_hentry(epb, node, &head->chain) {
+               asoc = sctp_assoc(epb);
+               if (asoc->ep != ep || rport != asoc->peer.port)
+                       goto next;
+
+               t = sctp_assoc_lookup_paddr(asoc, paddr);
+               if (t) {
+                       *transport = t;
+                       break;
                }
+next:
+               asoc = NULL;
        }
-
-       *transport = NULL;
-       return NULL;
+       read_unlock(&head->lock);
+       return asoc;
 }
 
 /* Lookup association on an endpoint based on a peer address.  BH-safe.  */
index 86503e7fa21e7fa55bcb54f1762dc5840c11cdfe..91ae463b079b13bf62c89fa7d8e7529e7af85685 100644 (file)
@@ -656,7 +656,6 @@ discard:
 /* Insert endpoint into the hash table.  */
 static void __sctp_hash_endpoint(struct sctp_endpoint *ep)
 {
-       struct sctp_ep_common **epp;
        struct sctp_ep_common *epb;
        struct sctp_hashbucket *head;
 
@@ -666,12 +665,7 @@ static void __sctp_hash_endpoint(struct sctp_endpoint *ep)
        head = &sctp_ep_hashtable[epb->hashent];
 
        sctp_write_lock(&head->lock);
-       epp = &head->chain;
-       epb->next = *epp;
-       if (epb->next)
-               (*epp)->pprev = &epb->next;
-       *epp = epb;
-       epb->pprev = epp;
+       hlist_add_head(&epb->node, &head->chain);
        sctp_write_unlock(&head->lock);
 }
 
@@ -691,19 +685,15 @@ static void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
 
        epb = &ep->base;
 
+       if (hlist_unhashed(&epb->node))
+               return;
+
        epb->hashent = sctp_ep_hashfn(epb->bind_addr.port);
 
        head = &sctp_ep_hashtable[epb->hashent];
 
        sctp_write_lock(&head->lock);
-
-       if (epb->pprev) {
-               if (epb->next)
-                       epb->next->pprev = epb->pprev;
-               *epb->pprev = epb->next;
-               epb->pprev = NULL;
-       }
-
+       __hlist_del(&epb->node);
        sctp_write_unlock(&head->lock);
 }
 
@@ -721,12 +711,13 @@ static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *l
        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));
        head = &sctp_ep_hashtable[hash];
        read_lock(&head->lock);
-       for (epb = head->chain; epb; epb = epb->next) {
+       sctp_for_each_hentry(epb, node, &head->chain) {
                ep = sctp_ep(epb);
                if (sctp_endpoint_is_match(ep, laddr))
                        goto hit;
@@ -744,7 +735,6 @@ hit:
 /* Insert association into the hash table.  */
 static void __sctp_hash_established(struct sctp_association *asoc)
 {
-       struct sctp_ep_common **epp;
        struct sctp_ep_common *epb;
        struct sctp_hashbucket *head;
 
@@ -756,12 +746,7 @@ static void __sctp_hash_established(struct sctp_association *asoc)
        head = &sctp_assoc_hashtable[epb->hashent];
 
        sctp_write_lock(&head->lock);
-       epp = &head->chain;
-       epb->next = *epp;
-       if (epb->next)
-               (*epp)->pprev = &epb->next;
-       *epp = epb;
-       epb->pprev = epp;
+       hlist_add_head(&epb->node, &head->chain);
        sctp_write_unlock(&head->lock);
 }
 
@@ -790,14 +775,7 @@ static void __sctp_unhash_established(struct sctp_association *asoc)
        head = &sctp_assoc_hashtable[epb->hashent];
 
        sctp_write_lock(&head->lock);
-
-       if (epb->pprev) {
-               if (epb->next)
-                       epb->next->pprev = epb->pprev;
-               *epb->pprev = epb->next;
-               epb->pprev = NULL;
-       }
-
+       __hlist_del(&epb->node);
        sctp_write_unlock(&head->lock);
 }
 
@@ -822,6 +800,7 @@ 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
@@ -830,7 +809,7 @@ static struct sctp_association *__sctp_lookup_association(
        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) {
+       sctp_for_each_hentry(epb, node, &head->chain) {
                asoc = sctp_assoc(epb);
                transport = sctp_assoc_is_match(asoc, local, peer);
                if (transport)
index f10fe7fbf24c425ca9609e46ed837d505a39552b..cf4b7eb023b3ba0819ce6d960128099c662360af 100644 (file)
@@ -90,6 +90,10 @@ void sctp_inq_free(struct sctp_inq *queue)
 void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *chunk)
 {
        /* Directly call the packet handling routine. */
+       if (chunk->rcvr->dead) {
+               sctp_chunk_free(chunk);
+               return;
+       }
 
        /* We are now calling this either from the soft interrupt
         * or from the backlog processing.
index 28f4fe77ceee2e44e9b2e29eefd2be632464c331..fa76f235169bfac3cedcb8517d4c62b0cd8daa5c 100644 (file)
@@ -382,7 +382,7 @@ static void sctp_insert_list(struct list_head *head, struct list_head *new)
 /* Mark all the eligible packets on a transport for retransmission.  */
 void sctp_retransmit_mark(struct sctp_outq *q,
                          struct sctp_transport *transport,
-                         __u8 fast_retransmit)
+                         __u8 reason)
 {
        struct list_head *lchunk, *ltemp;
        struct sctp_chunk *chunk;
@@ -412,20 +412,20 @@ void sctp_retransmit_mark(struct sctp_outq *q,
                        continue;
                }
 
-               /* If we are doing retransmission due to a fast retransmit,
-                * only the chunk's that are marked for fast retransmit
-                * should be added to the retransmit queue.  If we are doing
-                * retransmission due to a timeout or pmtu discovery, only the
-                * chunks that are not yet acked should be added to the
-                * retransmit queue.
+               /* If we are doing  retransmission due to a timeout or pmtu
+                * discovery, only the  chunks that are not yet acked should
+                * be added to the retransmit queue.
                 */
-               if ((fast_retransmit && (chunk->fast_retransmit > 0)) ||
-                  (!fast_retransmit && !chunk->tsn_gap_acked)) {
+               if ((reason == SCTP_RTXR_FAST_RTX  &&
+                           (chunk->fast_retransmit > 0)) ||
+                   (reason != SCTP_RTXR_FAST_RTX  && !chunk->tsn_gap_acked)) {
                        /* If this chunk was sent less then 1 rto ago, do not
                         * retransmit this chunk, but give the peer time
-                        * to acknowlege it.
+                        * to acknowlege it.  Do this only when
+                        * retransmitting due to T3 timeout.
                         */
-                       if ((jiffies - chunk->sent_at) < transport->rto)
+                       if (reason == SCTP_RTXR_T3_RTX &&
+                           (jiffies - chunk->sent_at) < transport->last_rto)
                                continue;
 
                        /* RFC 2960 6.2.1 Processing a Received SACK
@@ -467,10 +467,10 @@ void sctp_retransmit_mark(struct sctp_outq *q,
                }
        }
 
-       SCTP_DEBUG_PRINTK("%s: transport: %p, fast_retransmit: %d, "
+       SCTP_DEBUG_PRINTK("%s: transport: %p, reason: %d, "
                          "cwnd: %d, ssthresh: %d, flight_size: %d, "
                          "pba: %d\n", __FUNCTION__,
-                         transport, fast_retransmit,
+                         transport, reason,
                          transport->cwnd, transport->ssthresh,
                          transport->flight_size,
                          transport->partial_bytes_acked);
@@ -484,7 +484,6 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
                     sctp_retransmit_reason_t reason)
 {
        int error = 0;
-       __u8 fast_retransmit = 0;
 
        switch(reason) {
        case SCTP_RTXR_T3_RTX:
@@ -499,16 +498,18 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
        case SCTP_RTXR_FAST_RTX:
                SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS);
                sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
-               fast_retransmit = 1;
                break;
        case SCTP_RTXR_PMTUD:
                SCTP_INC_STATS(SCTP_MIB_PMTUD_RETRANSMITS);
                break;
+       case SCTP_RTXR_T1_RTX:
+               SCTP_INC_STATS(SCTP_MIB_T1_RETRANSMITS);
+               break;
        default:
                BUG();
        }
 
-       sctp_retransmit_mark(q, transport, fast_retransmit);
+       sctp_retransmit_mark(q, transport, reason);
 
        /* PR-SCTP A5) Any time the T3-rtx timer expires, on any destination,
         * the sender SHOULD try to advance the "Advanced.Peer.Ack.Point" by
@@ -641,7 +642,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
 
                /* If we are here due to a retransmit timeout or a fast
                 * retransmit and if there are any chunks left in the retransmit
-                * queue that could not fit in the PMTU sized packet, they need                  * to be marked as ineligible for a subsequent fast retransmit.
+                * queue that could not fit in the PMTU sized packet, they need
+                * to be marked as ineligible for a subsequent fast retransmit.
                 */
                if (rtx_timeout && !lchunk) {
                        list_for_each(lchunk1, lqueue) {
@@ -660,10 +662,9 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
 int sctp_outq_uncork(struct sctp_outq *q)
 {
        int error = 0;
-       if (q->cork) {
+       if (q->cork)
                q->cork = 0;
-               error = sctp_outq_flush(q, 0);
-       }
+       error = sctp_outq_flush(q, 0);
        return error;
 }
 
index e4cd841a22e478793e85e2701dc4da30b60db4b7..249973204070bfb811085b3b2ce988b7dc093128 100644 (file)
@@ -225,6 +225,7 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v)
        struct sctp_ep_common *epb;
        struct sctp_endpoint *ep;
        struct sock *sk;
+       struct hlist_node *node;
        int    hash = *(loff_t *)v;
 
        if (hash >= sctp_ep_hashsize)
@@ -233,7 +234,7 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v)
        head = &sctp_ep_hashtable[hash];
        sctp_local_bh_disable();
        read_lock(&head->lock);
-       for (epb = head->chain; epb; epb = epb->next) {
+       sctp_for_each_hentry(epb, node, &head->chain) {
                ep = sctp_ep(epb);
                sk = epb->sk;
                seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
@@ -328,6 +329,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
        struct sctp_ep_common *epb;
        struct sctp_association *assoc;
        struct sock *sk;
+       struct hlist_node *node;
        int    hash = *(loff_t *)v;
 
        if (hash >= sctp_assoc_hashsize)
@@ -336,7 +338,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
        head = &sctp_assoc_hashtable[hash];
        sctp_local_bh_disable();
        read_lock(&head->lock);
-       for (epb = head->chain; epb; epb = epb->next) {
+       sctp_for_each_hentry(epb, node, &head->chain) {
                assoc = sctp_assoc(epb);
                sk = epb->sk;
                seq_printf(seq,
index 40c1a47d1b8dc2972abcf481dc42c5d30ed55229..d50f610d1b02a4b44ffde9dee0d651f5d01fa49e 100644 (file)
@@ -1137,7 +1137,7 @@ SCTP_STATIC __init int sctp_init(void)
        }
        for (i = 0; i < sctp_assoc_hashsize; i++) {
                rwlock_init(&sctp_assoc_hashtable[i].lock);
-               sctp_assoc_hashtable[i].chain = NULL;
+               INIT_HLIST_HEAD(&sctp_assoc_hashtable[i].chain);
        }
 
        /* Allocate and initialize the endpoint hash table.  */
@@ -1151,7 +1151,7 @@ SCTP_STATIC __init int sctp_init(void)
        }
        for (i = 0; i < sctp_ep_hashsize; i++) {
                rwlock_init(&sctp_ep_hashtable[i].lock);
-               sctp_ep_hashtable[i].chain = NULL;
+               INIT_HLIST_HEAD(&sctp_ep_hashtable[i].chain);
        }
 
        /* Allocate and initialize the SCTP port hash table.  */
@@ -1170,7 +1170,7 @@ SCTP_STATIC __init int sctp_init(void)
        }
        for (i = 0; i < sctp_port_hashsize; i++) {
                spin_lock_init(&sctp_port_hashtable[i].lock);
-               sctp_port_hashtable[i].chain = NULL;
+               INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain);
        }
 
        printk(KERN_INFO "SCTP: Hash tables configured "
@@ -1179,6 +1179,7 @@ SCTP_STATIC __init int sctp_init(void)
 
        /* Disable ADDIP by default. */
        sctp_addip_enable = 0;
+       sctp_addip_noauth = 0;
 
        /* Enable PR-SCTP by default. */
        sctp_prsctp_enable = 1;
index c377e4e8f6533486ece6de765d0303b7bfa7f6fa..5a9783c38de160c40d66894dbefab7b6e4c76f1c 100644 (file)
@@ -1788,9 +1788,14 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
                                                sizeof(sctp_paramhdr_t);
 
 
+       /* This is a fatal error.  Any accumulated non-fatal errors are
+        * not reported.
+        */
+       if (*errp)
+               sctp_chunk_free(*errp);
+
        /* Create an error chunk and fill it in with our payload. */
-       if (!*errp)
-               *errp = sctp_make_op_error_space(asoc, chunk, payload_len);
+       *errp = sctp_make_op_error_space(asoc, chunk, payload_len);
 
        if (*errp) {
                sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION,
@@ -1813,9 +1818,15 @@ static int sctp_process_hn_param(const struct sctp_association *asoc,
 {
        __u16 len = ntohs(param.p->length);
 
-       /* Make an ERROR chunk. */
-       if (!*errp)
-               *errp = sctp_make_op_error_space(asoc, chunk, len);
+       /* Processing of the HOST_NAME parameter will generate an
+        * ABORT.  If we've accumulated any non-fatal errors, they
+        * would be unrecognized parameters and we should not include
+        * them in the ABORT.
+        */
+       if (*errp)
+               sctp_chunk_free(*errp);
+
+       *errp = sctp_make_op_error_space(asoc, chunk, len);
 
        if (*errp) {
                sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, len);
@@ -1847,7 +1858,7 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
                            break;
                    case SCTP_CID_ASCONF:
                    case SCTP_CID_ASCONF_ACK:
-                           asoc->peer.addip_capable = 1;
+                           asoc->peer.asconf_capable = 1;
                            break;
                    default:
                            break;
@@ -1862,56 +1873,40 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
  * taken if the processing endpoint does not recognize the
  * Parameter Type.
  *
- * 00 - Stop processing this SCTP chunk and discard it,
- *     do not process any further chunks within it.
+ * 00 - Stop processing this parameter; do not process any further
+ *     parameters within this chunk
  *
- * 01 - Stop processing this SCTP chunk and discard it,
- *     do not process any further chunks within it, and report
- *     the unrecognized parameter in an 'Unrecognized
- *     Parameter Type' (in either an ERROR or in the INIT ACK).
+ * 01 - Stop processing this parameter, do not process any further
+ *     parameters within this chunk, and report the unrecognized
+ *     parameter in an 'Unrecognized Parameter' ERROR chunk.
  *
  * 10 - Skip this parameter and continue processing.
  *
  * 11 - Skip this parameter and continue processing but
  *     report the unrecognized parameter in an
- *     'Unrecognized Parameter Type' (in either an ERROR or in
- *     the INIT ACK).
+ *     'Unrecognized Parameter' ERROR chunk.
  *
  * Return value:
- *     0 - discard the chunk
- *     1 - continue with the chunk
+ *     SCTP_IERROR_NO_ERROR - continue with the chunk
+ *     SCTP_IERROR_ERROR    - stop and report an error.
+ *     SCTP_IERROR_NOMEME   - out of memory.
  */
-static int sctp_process_unk_param(const struct sctp_association *asoc,
-                                 union sctp_params param,
-                                 struct sctp_chunk *chunk,
-                                 struct sctp_chunk **errp)
+static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc,
+                                           union sctp_params param,
+                                           struct sctp_chunk *chunk,
+                                           struct sctp_chunk **errp)
 {
-       int retval = 1;
+       int retval = SCTP_IERROR_NO_ERROR;
 
        switch (param.p->type & SCTP_PARAM_ACTION_MASK) {
        case SCTP_PARAM_ACTION_DISCARD:
-               retval =  0;
-               break;
-       case SCTP_PARAM_ACTION_DISCARD_ERR:
-               retval =  0;
-               /* Make an ERROR chunk, preparing enough room for
-                * returning multiple unknown parameters.
-                */
-               if (NULL == *errp)
-                       *errp = sctp_make_op_error_space(asoc, chunk,
-                                       ntohs(chunk->chunk_hdr->length));
-
-               if (*errp) {
-                       sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM,
-                                       WORD_ROUND(ntohs(param.p->length)));
-                       sctp_addto_chunk(*errp,
-                                       WORD_ROUND(ntohs(param.p->length)),
-                                       param.v);
-               }
-
+               retval =  SCTP_IERROR_ERROR;
                break;
        case SCTP_PARAM_ACTION_SKIP:
                break;
+       case SCTP_PARAM_ACTION_DISCARD_ERR:
+               retval =  SCTP_IERROR_ERROR;
+               /* Fall through */
        case SCTP_PARAM_ACTION_SKIP_ERR:
                /* Make an ERROR chunk, preparing enough room for
                 * returning multiple unknown parameters.
@@ -1932,9 +1927,8 @@ static int sctp_process_unk_param(const struct sctp_association *asoc,
                         * to the peer and the association won't be
                         * established.
                         */
-                       retval = 0;
+                       retval = SCTP_IERROR_NOMEM;
                }
-
                break;
        default:
                break;
@@ -1943,18 +1937,20 @@ static int sctp_process_unk_param(const struct sctp_association *asoc,
        return retval;
 }
 
-/* Find unrecognized parameters in the chunk.
+/* Verify variable length parameters
  * Return values:
- *     0 - discard the chunk
- *     1 - continue with the chunk
+ *     SCTP_IERROR_ABORT - trigger an ABORT
+ *     SCTP_IERROR_NOMEM - out of memory (abort)
+ *     SCTP_IERROR_ERROR - stop processing, trigger an ERROR
+ *     SCTP_IERROR_NO_ERROR - continue with the chunk
  */
-static int sctp_verify_param(const struct sctp_association *asoc,
-                            union sctp_params param,
-                            sctp_cid_t cid,
-                            struct sctp_chunk *chunk,
-                            struct sctp_chunk **err_chunk)
+static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
+                                       union sctp_params param,
+                                       sctp_cid_t cid,
+                                       struct sctp_chunk *chunk,
+                                       struct sctp_chunk **err_chunk)
 {
-       int retval = 1;
+       int retval = SCTP_IERROR_NO_ERROR;
 
        /* FIXME - This routine is not looking at each parameter per the
         * chunk type, i.e., unrecognized parameters should be further
@@ -1976,7 +1972,9 @@ static int sctp_verify_param(const struct sctp_association *asoc,
 
        case SCTP_PARAM_HOST_NAME_ADDRESS:
                /* Tell the peer, we won't support this param.  */
-               return sctp_process_hn_param(asoc, param, chunk, err_chunk);
+               sctp_process_hn_param(asoc, param, chunk, err_chunk);
+               retval = SCTP_IERROR_ABORT;
+               break;
 
        case SCTP_PARAM_FWD_TSN_SUPPORT:
                if (sctp_prsctp_enable)
@@ -1993,9 +1991,11 @@ static int sctp_verify_param(const struct sctp_association *asoc,
                 * cause 'Protocol Violation'.
                 */
                if (SCTP_AUTH_RANDOM_LENGTH !=
-                       ntohs(param.p->length) - sizeof(sctp_paramhdr_t))
-                       return sctp_process_inv_paramlength(asoc, param.p,
+                       ntohs(param.p->length) - sizeof(sctp_paramhdr_t)) {
+                       sctp_process_inv_paramlength(asoc, param.p,
                                                        chunk, err_chunk);
+                       retval = SCTP_IERROR_ABORT;
+               }
                break;
 
        case SCTP_PARAM_CHUNKS:
@@ -2007,9 +2007,11 @@ static int sctp_verify_param(const struct sctp_association *asoc,
                 *  INIT-ACK chunk if the sender wants to receive authenticated
                 *  chunks.  Its maximum length is 260 bytes.
                 */
-               if (260 < ntohs(param.p->length))
-                       return sctp_process_inv_paramlength(asoc, param.p,
-                                                       chunk, err_chunk);
+               if (260 < ntohs(param.p->length)) {
+                       sctp_process_inv_paramlength(asoc, param.p,
+                                                    chunk, err_chunk);
+                       retval = SCTP_IERROR_ABORT;
+               }
                break;
 
        case SCTP_PARAM_HMAC_ALGO:
@@ -2020,8 +2022,7 @@ fallthrough:
        default:
                SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n",
                                ntohs(param.p->type), cid);
-               return sctp_process_unk_param(asoc, param, chunk, err_chunk);
-
+               retval = sctp_process_unk_param(asoc, param, chunk, err_chunk);
                break;
        }
        return retval;
@@ -2036,6 +2037,7 @@ int sctp_verify_init(const struct sctp_association *asoc,
 {
        union sctp_params param;
        int has_cookie = 0;
+       int result;
 
        /* Verify stream values are non-zero. */
        if ((0 == peer_init->init_hdr.num_outbound_streams) ||
@@ -2043,8 +2045,7 @@ int sctp_verify_init(const struct sctp_association *asoc,
            (0 == peer_init->init_hdr.init_tag) ||
            (SCTP_DEFAULT_MINWINDOW > ntohl(peer_init->init_hdr.a_rwnd))) {
 
-               sctp_process_inv_mandatory(asoc, chunk, errp);
-               return 0;
+               return sctp_process_inv_mandatory(asoc, chunk, errp);
        }
 
        /* Check for missing mandatory parameters.  */
@@ -2062,29 +2063,29 @@ int sctp_verify_init(const struct sctp_association *asoc,
         * VIOLATION error.  We build the ERROR chunk here and let the normal
         * error handling code build and send the packet.
         */
-       if (param.v != (void*)chunk->chunk_end) {
-               sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
-               return 0;
-       }
+       if (param.v != (void*)chunk->chunk_end)
+               return sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
 
        /* The only missing mandatory param possible today is
         * the state cookie for an INIT-ACK chunk.
         */
-       if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) {
-               sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE,
-                                          chunk, errp);
-               return 0;
-       }
-
-       /* Find unrecognized parameters. */
+       if ((SCTP_CID_INIT_ACK == cid) && !has_cookie)
+               return sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE,
+                                                 chunk, errp);
 
+       /* Verify all the variable length parameters */
        sctp_walk_params(param, peer_init, init_hdr.params) {
 
-               if (!sctp_verify_param(asoc, param, cid, chunk, errp)) {
-                       if (SCTP_PARAM_HOST_NAME_ADDRESS == param.p->type)
+               result = sctp_verify_param(asoc, param, cid, chunk, errp);
+               switch (result) {
+                   case SCTP_IERROR_ABORT:
+                   case SCTP_IERROR_NOMEM:
                                return 0;
-                       else
+                   case SCTP_IERROR_ERROR:
                                return 1;
+                   case SCTP_IERROR_NO_ERROR:
+                   default:
+                               break;
                }
 
        } /* for (loop through all parameters) */
@@ -2137,11 +2138,14 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
 
        /* If the peer claims support for ADD-IP without support
         * for AUTH, disable support for ADD-IP.
+        * Do this only if backward compatible mode is turned off.
         */
-       if (asoc->peer.addip_capable && !asoc->peer.auth_capable) {
+       if (!sctp_addip_noauth &&
+            (asoc->peer.asconf_capable && !asoc->peer.auth_capable)) {
                asoc->peer.addip_disabled_mask |= (SCTP_PARAM_ADD_IP |
                                                  SCTP_PARAM_DEL_IP |
                                                  SCTP_PARAM_SET_PRIMARY);
+               asoc->peer.asconf_capable = 0;
        }
 
        /* Walk list of transports, removing transports in the UNKNOWN state. */
@@ -2848,10 +2852,11 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
 
        __be16  err_code;
        int     length = 0;
-       int     chunk_len = asconf->skb->len;
+       int     chunk_len;
        __u32   serial;
        int     all_param_pass = 1;
 
+       chunk_len = ntohs(asconf->chunk_hdr->length) - sizeof(sctp_chunkhdr_t);
        hdr = (sctp_addiphdr_t *)asconf->skb->data;
        serial = ntohl(hdr->serial);
 
@@ -2952,13 +2957,17 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,
                /* This is always done in BH context with a socket lock
                 * held, so the list can not change.
                 */
+               local_bh_disable();
                list_for_each_entry(saddr, &bp->address_list, list) {
                        if (sctp_cmp_addr_exact(&saddr->a, &addr))
                                saddr->use_as_src = 1;
                }
+               local_bh_enable();
                break;
        case SCTP_PARAM_DEL_IP:
-               retval = sctp_del_bind_addr(bp, &addr, call_rcu_bh);
+               local_bh_disable();
+               retval = sctp_del_bind_addr(bp, &addr);
+               local_bh_enable();
                list_for_each(pos, &asoc->peer.transport_addr_list) {
                        transport = list_entry(pos, struct sctp_transport,
                                                 transports);
@@ -2990,7 +2999,7 @@ static __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack,
        sctp_addip_param_t      *asconf_ack_param;
        sctp_errhdr_t           *err_param;
        int                     length;
-       int                     asconf_ack_len = asconf_ack->skb->len;
+       int                     asconf_ack_len;
        __be16                  err_code;
 
        if (no_err)
@@ -2998,6 +3007,9 @@ static __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack,
        else
                err_code = SCTP_ERROR_REQ_REFUSED;
 
+       asconf_ack_len = ntohs(asconf_ack->chunk_hdr->length) -
+                            sizeof(sctp_chunkhdr_t);
+
        /* Skip the addiphdr from the asconf_ack chunk and store a pointer to
         * the first asconf_ack parameter.
         */
index bbdc938da86fa37166866b27cd37fe2aa25efd05..78d1a8a49bd05bf53f4f58426d6ad4c7b0d498a0 100644 (file)
@@ -453,6 +453,7 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc,
         * maximum value discussed in rule C7 above (RTO.max) may be
         * used to provide an upper bound to this doubling operation.
         */
+       transport->last_rto = transport->rto;
        transport->rto = min((transport->rto * 2), transport->asoc->rto_max);
 }
 
@@ -1267,6 +1268,12 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
                        sctp_ootb_pkt_free(packet);
                        break;
 
+               case SCTP_CMD_T1_RETRAN:
+                       /* Mark a transport for retransmission.  */
+                       sctp_retransmit(&asoc->outqueue, cmd->obj.transport,
+                                       SCTP_RTXR_T1_RTX);
+                       break;
+
                case SCTP_CMD_RETRAN:
                        /* Mark a transport for retransmission.  */
                        sctp_retransmit(&asoc->outqueue, cmd->obj.transport,
@@ -1393,7 +1400,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
                        list_for_each(pos, &asoc->peer.transport_addr_list) {
                                t = list_entry(pos, struct sctp_transport,
                                               transports);
-                               sctp_retransmit_mark(&asoc->outqueue, t, 0);
+                               sctp_retransmit_mark(&asoc->outqueue, t,
+                                           SCTP_RTXR_T1_RTX);
                        }
 
                        sctp_add_cmd_sf(commands,
index f01b408508ff6144b94851f1a67ae09c7a7953d4..5ebbe808d801030341fbe3bd3cf7ff49b1c2d6f2 100644 (file)
@@ -2305,7 +2305,7 @@ static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
        /* If we've sent any data bundled with COOKIE-ECHO we will need to
         * resend
         */
-       sctp_add_cmd_sf(commands, SCTP_CMD_RETRAN,
+       sctp_add_cmd_sf(commands, SCTP_CMD_T1_RETRAN,
                        SCTP_TRANSPORT(asoc->peer.primary_path));
 
        /* Cast away the const modifier, as we want to just
@@ -4064,11 +4064,6 @@ static sctp_disposition_t sctp_sf_abort_violation(
        struct sctp_chunk *chunk =  arg;
        struct sctp_chunk *abort = NULL;
 
-       /* Make the abort chunk. */
-       abort = sctp_make_abort_violation(asoc, chunk, payload, paylen);
-       if (!abort)
-               goto nomem;
-
        /* SCTP-AUTH, Section 6.3:
         *    It should be noted that if the receiver wants to tear
         *    down an association in an authenticated way only, the
@@ -4083,6 +4078,11 @@ static sctp_disposition_t sctp_sf_abort_violation(
        if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
                goto discard;
 
+       /* Make the abort chunk. */
+       abort = sctp_make_abort_violation(asoc, chunk, payload, paylen);
+       if (!abort)
+               goto nomem;
+
        if (asoc) {
                sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
                SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
index a7ecf3159e53b0e759e6e8d674699f28617628d0..ff8bc95670edbfa6af9ece6d74d2dc656a9c3cba 100644 (file)
@@ -660,7 +660,7 @@ static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt)
                 * socket routing and failover schemes. Refer to comments in
                 * sctp_do_bind(). -daisy
                 */
-               retval = sctp_del_bind_addr(bp, sa_addr, call_rcu);
+               retval = sctp_del_bind_addr(bp, sa_addr);
 
                addr_buf += af->sockaddr_len;
 err_bindx_rem:
@@ -5307,6 +5307,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
 {
        struct sctp_bind_hashbucket *head; /* hash list */
        struct sctp_bind_bucket *pp; /* hash list port iterator */
+       struct hlist_node *node;
        unsigned short snum;
        int ret;
 
@@ -5331,7 +5332,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
                        index = sctp_phashfn(rover);
                        head = &sctp_port_hashtable[index];
                        sctp_spin_lock(&head->lock);
-                       for (pp = head->chain; pp; pp = pp->next)
+                       sctp_for_each_hentry(pp, node, &head->chain)
                                if (pp->port == rover)
                                        goto next;
                        break;
@@ -5358,7 +5359,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
                 */
                head = &sctp_port_hashtable[sctp_phashfn(snum)];
                sctp_spin_lock(&head->lock);
-               for (pp = head->chain; pp; pp = pp->next) {
+               sctp_for_each_hentry(pp, node, &head->chain) {
                        if (pp->port == snum)
                                goto pp_found;
                }
@@ -5702,10 +5703,7 @@ static struct sctp_bind_bucket *sctp_bucket_create(
                pp->port = snum;
                pp->fastreuse = 0;
                INIT_HLIST_HEAD(&pp->owner);
-               if ((pp->next = head->chain) != NULL)
-                       pp->next->pprev = &pp->next;
-               head->chain = pp;
-               pp->pprev = &head->chain;
+               hlist_add_head(&pp->node, &head->chain);
        }
        return pp;
 }
@@ -5714,9 +5712,7 @@ static struct sctp_bind_bucket *sctp_bucket_create(
 static void sctp_bucket_destroy(struct sctp_bind_bucket *pp)
 {
        if (pp && hlist_empty(&pp->owner)) {
-               if (pp->next)
-                       pp->next->pprev = pp->pprev;
-               *(pp->pprev) = pp->next;
+               __hlist_del(&pp->node);
                kmem_cache_free(sctp_bucket_cachep, pp);
                SCTP_DBG_OBJCNT_DEC(bind_bucket);
        }
index 0669778e4335aeb22911315882084b6189612ff5..da4f15734fb11f4e739059d5d0be49300ca3bbe8 100644 (file)
@@ -263,6 +263,15 @@ static ctl_table sctp_table[] = {
                .proc_handler   = &proc_dointvec,
                .strategy       = &sysctl_intvec
        },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "addip_noauth_enable",
+               .data           = &sctp_addip_noauth,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+               .strategy       = &sysctl_intvec
+       },
        { .ctl_name = 0 }
 };
 
index 5f467c914f8025fe595cf2a87bc355308abb587f..d55ce83a020b7a32059b92758afa790e4d912e4e 100644 (file)
@@ -74,8 +74,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
         * given destination transport address, set RTO to the protocol
         * parameter 'RTO.Initial'.
         */
+       peer->last_rto = peer->rto = msecs_to_jiffies(sctp_rto_initial);
        peer->rtt = 0;
-       peer->rto = msecs_to_jiffies(sctp_rto_initial);
        peer->rttvar = 0;
        peer->srtt = 0;
        peer->rto_pending = 0;
@@ -385,6 +385,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
                tp->rto = tp->asoc->rto_max;
 
        tp->rtt = rtt;
+       tp->last_rto = tp->rto;
 
        /* Reset rto_pending so that a new RTT measurement is started when a
         * new data chunk is sent.
@@ -578,7 +579,7 @@ void sctp_transport_reset(struct sctp_transport *t)
         */
        t->cwnd = min(4*asoc->pathmtu, max_t(__u32, 2*asoc->pathmtu, 4380));
        t->ssthresh = asoc->peer.i.a_rwnd;
-       t->rto = asoc->rto_initial;
+       t->last_rto = t->rto = asoc->rto_initial;
        t->rtt = 0;
        t->srtt = 0;
        t->rttvar = 0;
index 4be92d0a2cab51b3c9821c55b29092792bc4c59c..4908041ffb319c57d8ef1925f01d358c54f489aa 100644 (file)
@@ -862,7 +862,7 @@ static inline void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid)
                        continue;
 
                /* see if this ssn has been marked by skipping */
-               if (!SSN_lt(cssn, sctp_ssn_peek(in, csid)))
+               if (!SSN_lte(cssn, sctp_ssn_peek(in, csid)))
                        break;
 
                __skb_unlink(pos, &ulpq->lobby);