cfg80211: fix NULL ptr deref
[safe/jmp/linux-2.6] / net / sctp / sm_make_chunk.c
index 6dd9b3e..9d881a6 100644 (file)
@@ -100,11 +100,11 @@ int sctp_chunk_iif(const struct sctp_chunk *chunk)
  */
 static const struct sctp_paramhdr ecap_param = {
        SCTP_PARAM_ECN_CAPABLE,
-       __constant_htons(sizeof(struct sctp_paramhdr)),
+       cpu_to_be16(sizeof(struct sctp_paramhdr)),
 };
 static const struct sctp_paramhdr prsctp_param = {
        SCTP_PARAM_FWD_TSN_SUPPORT,
-       __constant_htons(sizeof(struct sctp_paramhdr)),
+       cpu_to_be16(sizeof(struct sctp_paramhdr)),
 };
 
 /* A helper to initialize to initialize an op error inside a
@@ -224,7 +224,9 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
                num_ext += 2;
        }
 
-       chunksize += sizeof(aiparam);
+       if (sp->adaptation_ind)
+               chunksize += sizeof(aiparam);
+
        chunksize += vparam_len;
 
        /* Account for AUTH related parameters */
@@ -304,10 +306,12 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
        if (sctp_prsctp_enable)
                sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
 
-       aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
-       aiparam.param_hdr.length = htons(sizeof(aiparam));
-       aiparam.adaptation_ind = htonl(sp->adaptation_ind);
-       sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
+       if (sp->adaptation_ind) {
+               aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
+               aiparam.param_hdr.length = htons(sizeof(aiparam));
+               aiparam.adaptation_ind = htonl(sp->adaptation_ind);
+               sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
+       }
 
        /* Add SCTP-AUTH chunks to the parameter list */
        if (sctp_auth_enable) {
@@ -332,6 +336,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        sctp_inithdr_t initack;
        struct sctp_chunk *retval;
        union sctp_params addrs;
+       struct sctp_sock *sp;
        int addrs_len;
        sctp_cookie_param_t *cookie;
        int cookie_len;
@@ -366,22 +371,24 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        /* Calculate the total size of allocation, include the reserved
         * space for reporting unknown parameters if it is specified.
         */
+       sp = sctp_sk(asoc->base.sk);
        chunksize = sizeof(initack) + addrs_len + cookie_len + unkparam_len;
 
        /* Tell peer that we'll do ECN only if peer advertised such cap.  */
        if (asoc->peer.ecn_capable)
                chunksize += sizeof(ecap_param);
 
-       if (sctp_prsctp_enable)
+       if (asoc->peer.prsctp_capable)
                chunksize += sizeof(prsctp_param);
 
-       if (sctp_addip_enable) {
+       if (asoc->peer.asconf_capable) {
                extensions[num_ext] = SCTP_CID_ASCONF;
                extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;
                num_ext += 2;
        }
 
-       chunksize += sizeof(aiparam);
+       if (sp->adaptation_ind)
+               chunksize += sizeof(aiparam);
 
        if (asoc->peer.auth_capable) {
                auth_random = (sctp_paramhdr_t *)asoc->c.auth_random;
@@ -432,10 +439,12 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        if (asoc->peer.prsctp_capable)
                sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
 
-       aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
-       aiparam.param_hdr.length = htons(sizeof(aiparam));
-       aiparam.adaptation_ind = htonl(sctp_sk(asoc->base.sk)->adaptation_ind);
-       sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
+       if (sp->adaptation_ind) {
+               aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
+               aiparam.param_hdr.length = htons(sizeof(aiparam));
+               aiparam.adaptation_ind = htonl(sp->adaptation_ind);
+               sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
+       }
 
        if (asoc->peer.auth_capable) {
                sctp_addto_chunk(retval, ntohs(auth_random->length),
@@ -702,12 +711,14 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
        __u32 ctsn;
        __u16 num_gabs, num_dup_tsns;
        struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
+       struct sctp_gap_ack_block gabs[SCTP_MAX_GABS];
 
+       memset(gabs, 0, sizeof(gabs));
        ctsn = sctp_tsnmap_get_ctsn(map);
        SCTP_DEBUG_PRINTK("sackCTSNAck sent:  0x%x.\n", ctsn);
 
        /* How much room is needed in the chunk? */
-       num_gabs = sctp_tsnmap_num_gabs(map);
+       num_gabs = sctp_tsnmap_num_gabs(map, gabs);
        num_dup_tsns = sctp_tsnmap_num_dups(map);
 
        /* Initialize the SACK header.  */
@@ -763,7 +774,7 @@ struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
        /* Add the gap ack block information.   */
        if (num_gabs)
                sctp_addto_chunk(retval, sizeof(__u32) * num_gabs,
-                                sctp_tsnmap_get_gabs(map));
+                                gabs);
 
        /* Add the duplicate TSN information.  */
        if (num_dup_tsns)
@@ -2850,22 +2861,27 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
        addr_param = (union sctp_addr_param *)
                        ((void *)asconf_param + sizeof(sctp_addip_param_t));
 
+       if (asconf_param->param_hdr.type != SCTP_PARAM_ADD_IP &&
+           asconf_param->param_hdr.type != SCTP_PARAM_DEL_IP &&
+           asconf_param->param_hdr.type != SCTP_PARAM_SET_PRIMARY)
+               return SCTP_ERROR_UNKNOWN_PARAM;
+
        switch (addr_param->v4.param_hdr.type) {
        case SCTP_PARAM_IPV6_ADDRESS:
                if (!asoc->peer.ipv6_address)
-                       return SCTP_ERROR_INV_PARAM;
+                       return SCTP_ERROR_DNS_FAILED;
                break;
        case SCTP_PARAM_IPV4_ADDRESS:
                if (!asoc->peer.ipv4_address)
-                       return SCTP_ERROR_INV_PARAM;
+                       return SCTP_ERROR_DNS_FAILED;
                break;
        default:
-               return SCTP_ERROR_INV_PARAM;
+               return SCTP_ERROR_DNS_FAILED;
        }
 
        af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type));
        if (unlikely(!af))
-               return SCTP_ERROR_INV_PARAM;
+               return SCTP_ERROR_DNS_FAILED;
 
        af->from_addr_param(&addr, addr_param, htons(asoc->peer.port), 0);
 
@@ -2875,7 +2891,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
         *  make sure we check for that)
         */
        if (!af->is_any(&addr) && !af->addr_valid(&addr, NULL, asconf->skb))
-               return SCTP_ERROR_INV_PARAM;
+               return SCTP_ERROR_DNS_FAILED;
 
        switch (asconf_param->param_hdr.type) {
        case SCTP_PARAM_ADD_IP:
@@ -2943,13 +2959,10 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
 
                peer = sctp_assoc_lookup_paddr(asoc, &addr);
                if (!peer)
-                       return SCTP_ERROR_INV_PARAM;
+                       return SCTP_ERROR_DNS_FAILED;
 
                sctp_assoc_set_primary(asoc, peer);
                break;
-       default:
-               return SCTP_ERROR_INV_PARAM;
-               break;
        }
 
        return SCTP_ERROR_NO_ERROR;
@@ -3093,7 +3106,7 @@ done:
 }
 
 /* Process a asconf parameter that is successfully acked. */
-static int sctp_asconf_param_success(struct sctp_association *asoc,
+static void sctp_asconf_param_success(struct sctp_association *asoc,
                                     sctp_addip_param_t *asconf_param)
 {
        struct sctp_af *af;
@@ -3102,7 +3115,6 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,
        union sctp_addr_param *addr_param;
        struct sctp_transport *transport;
        struct sctp_sockaddr_entry *saddr;
-       int retval = 0;
 
        addr_param = (union sctp_addr_param *)
                        ((void *)asconf_param + sizeof(sctp_addip_param_t));
@@ -3122,10 +3134,18 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,
                                saddr->state = SCTP_ADDR_SRC;
                }
                local_bh_enable();
+               list_for_each_entry(transport, &asoc->peer.transport_addr_list,
+                               transports) {
+                       if (transport->state == SCTP_ACTIVE)
+                               continue;
+                       dst_release(transport->dst);
+                       sctp_transport_route(transport, NULL,
+                                            sctp_sk(asoc->base.sk));
+               }
                break;
        case SCTP_PARAM_DEL_IP:
                local_bh_disable();
-               retval = sctp_del_bind_addr(bp, &addr);
+               sctp_del_bind_addr(bp, &addr);
                local_bh_enable();
                list_for_each_entry(transport, &asoc->peer.transport_addr_list,
                                transports) {
@@ -3137,8 +3157,6 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,
        default:
                break;
        }
-
-       return retval;
 }
 
 /* Get the corresponding ASCONF response error code from the ASCONF_ACK chunk
@@ -3255,14 +3273,14 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
 
                switch (err_code) {
                case SCTP_ERROR_NO_ERROR:
-                       retval = sctp_asconf_param_success(asoc, asconf_param);
+                       sctp_asconf_param_success(asoc, asconf_param);
                        break;
 
                case SCTP_ERROR_RSRC_LOW:
                        retval = 1;
                        break;
 
-               case SCTP_ERROR_INV_PARAM:
+               case SCTP_ERROR_UNKNOWN_PARAM:
                        /* Disable sending this type of asconf parameter in
                         * future.
                         */