]> Pileus Git - ~andy/linux/blobdiff - net/sctp/sm_make_chunk.c
Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jlbec...
[~andy/linux] / net / sctp / sm_make_chunk.c
index b3434cc7d0cf960dc275938054f50c13016a0a42..58eb27fed4b4f7b393479c9f239f2e110826769e 100644 (file)
@@ -1075,20 +1075,28 @@ nodata:
 
 /* Make a HEARTBEAT chunk.  */
 struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
-                                 const struct sctp_transport *transport,
-                                 const void *payload, const size_t paylen)
+                                 const struct sctp_transport *transport)
 {
-       struct sctp_chunk *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT,
-                                                   0, paylen);
+       struct sctp_chunk *retval;
+       sctp_sender_hb_info_t hbinfo;
+
+       retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT, 0, sizeof(hbinfo));
 
        if (!retval)
                goto nodata;
 
+       hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO;
+       hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t));
+       hbinfo.daddr = transport->ipaddr;
+       hbinfo.sent_at = jiffies;
+       hbinfo.hb_nonce = transport->hb_nonce;
+
        /* Cast away the 'const', as this is just telling the chunk
         * what transport it belongs to.
         */
        retval->transport = (struct sctp_transport *) transport;
-       retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload);
+       retval->subh.hbs_hdr = sctp_addto_chunk(retval, sizeof(hbinfo),
+                                               &hbinfo);
 
 nodata:
        return retval;
@@ -2242,14 +2250,17 @@ int sctp_verify_init(const struct sctp_association *asoc,
  * Returns 0 on failure, else success.
  * FIXME:  This is an association method.
  */
-int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
+int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk,
                      const union sctp_addr *peer_addr,
                      sctp_init_chunk_t *peer_init, gfp_t gfp)
 {
        union sctp_params param;
        struct sctp_transport *transport;
        struct list_head *pos, *temp;
+       struct sctp_af *af;
+       union sctp_addr addr;
        char *cookie;
+       int src_match = 0;
 
        /* We must include the address that the INIT packet came from.
         * This is the only address that matters for an INIT packet.
@@ -2261,18 +2272,31 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
         * added as the primary transport.  The source address seems to
         * be a a better choice than any of the embedded addresses.
         */
-       if (peer_addr) {
-               if(!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE))
-                       goto nomem;
-       }
+       if(!sctp_assoc_add_peer(asoc, peer_addr, gfp, SCTP_ACTIVE))
+               goto nomem;
+
+       if (sctp_cmp_addr_exact(sctp_source(chunk), peer_addr))
+               src_match = 1;
 
        /* Process the initialization parameters.  */
        sctp_walk_params(param, peer_init, init_hdr.params) {
+               if (!src_match && (param.p->type == SCTP_PARAM_IPV4_ADDRESS ||
+                   param.p->type == SCTP_PARAM_IPV6_ADDRESS)) {
+                       af = sctp_get_af_specific(param_type2af(param.p->type));
+                       af->from_addr_param(&addr, param.addr,
+                                           chunk->sctp_hdr->source, 0);
+                       if (sctp_cmp_addr_exact(sctp_source(chunk), &addr))
+                               src_match = 1;
+               }
 
                if (!sctp_process_param(asoc, param, peer_addr, gfp))
                        goto clean_up;
        }
 
+       /* source address of chunk may not match any valid address */
+       if (!src_match)
+               goto clean_up;
+
        /* AUTH: After processing the parameters, make sure that we
         * have all the required info to potentially do authentications.
         */
@@ -2923,7 +2947,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
            asconf_param->param_hdr.type != SCTP_PARAM_SET_PRIMARY)
                return SCTP_ERROR_UNKNOWN_PARAM;
 
-       switch (addr_param->v4.param_hdr.type) {
+       switch (addr_param->p.type) {
        case SCTP_PARAM_IPV6_ADDRESS:
                if (!asoc->peer.ipv6_address)
                        return SCTP_ERROR_DNS_FAILED;
@@ -2936,7 +2960,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
                return SCTP_ERROR_DNS_FAILED;
        }
 
-       af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type));
+       af = sctp_get_af_specific(param_type2af(addr_param->p.type));
        if (unlikely(!af))
                return SCTP_ERROR_DNS_FAILED;
 
@@ -3100,7 +3124,7 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
        /* Skip the address parameter and store a pointer to the first
         * asconf parameter.
         */
-       length = ntohs(addr_param->v4.param_hdr.length);
+       length = ntohs(addr_param->p.length);
        asconf_param = (sctp_addip_param_t *)((void *)addr_param + length);
        chunk_len -= length;
 
@@ -3177,7 +3201,7 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
                        ((void *)asconf_param + sizeof(sctp_addip_param_t));
 
        /* We have checked the packet before, so we do not check again. */
-       af = sctp_get_af_specific(param_type2af(addr_param->v4.param_hdr.type));
+       af = sctp_get_af_specific(param_type2af(addr_param->p.type));
        af->from_addr_param(&addr, addr_param, htons(bp->port), 0);
 
        switch (asconf_param->param_hdr.type) {
@@ -3193,11 +3217,8 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
                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));
+                       transport->dst = NULL;
                }
                break;
        case SCTP_PARAM_DEL_IP:
@@ -3207,8 +3228,7 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
                list_for_each_entry(transport, &asoc->peer.transport_addr_list,
                                transports) {
                        dst_release(transport->dst);
-                       sctp_transport_route(transport, NULL,
-                                            sctp_sk(asoc->base.sk));
+                       transport->dst = NULL;
                }
                break;
        default:
@@ -3304,7 +3324,7 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
        /* Skip the address parameter in the last asconf sent and store a
         * pointer to the first asconf parameter.
         */
-       length = ntohs(addr_param->v4.param_hdr.length);
+       length = ntohs(addr_param->p.length);
        asconf_param = (sctp_addip_param_t *)((void *)addr_param + length);
        asconf_len -= length;