[SCTP]: Beginning of conversion to net-endian for embedded sctp_addr.
[linux-drm-fsl-dcu.git] / net / sctp / socket.c
index 3fe906d6506982f9e1c7a0bdcf6e67b6d2772d58..459f32c5c3ae7f4b17f88e85de172d4fde282f3f 100644 (file)
@@ -228,12 +228,12 @@ static struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
        struct sctp_association *addr_asoc = NULL, *id_asoc = NULL;
        struct sctp_transport *transport;
        union sctp_addr *laddr = (union sctp_addr *)addr;
+       union sctp_addr tmp;
 
-       laddr->v4.sin_port = ntohs(laddr->v4.sin_port);
+       flip_to_h(&tmp, laddr);
        addr_asoc = sctp_endpoint_lookup_assoc(sctp_sk(sk)->ep,
-                                              (union sctp_addr *)addr,
+                                              &tmp,
                                               &transport);
-       laddr->v4.sin_port = htons(laddr->v4.sin_port);
 
        if (!addr_asoc)
                return NULL;
@@ -313,6 +313,7 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
        struct sctp_af *af;
        unsigned short snum;
        int ret = 0;
+       union sctp_addr tmp;
 
        /* Common sockaddr verification. */
        af = sctp_sockaddr_af(sp, addr, len);
@@ -368,9 +369,8 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
        sctp_write_lock(&ep->base.addr_lock);
 
        /* Use GFP_ATOMIC since BHs are disabled.  */
-       addr->v4.sin_port = ntohs(addr->v4.sin_port);
-       ret = sctp_add_bind_addr(bp, addr, 1, GFP_ATOMIC);
-       addr->v4.sin_port = htons(addr->v4.sin_port);
+       flip_to_h(&tmp, addr);
+       ret = sctp_add_bind_addr(bp, &tmp, 1, GFP_ATOMIC);
        sctp_write_unlock(&ep->base.addr_lock);
        sctp_local_bh_enable();
 
@@ -551,7 +551,7 @@ static int sctp_send_asconf_add_ip(struct sock              *sk,
                laddr = list_entry(p, struct sctp_sockaddr_entry, list);
                sctp_read_unlock(&asoc->base.addr_lock);
 
-               chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs,
+               chunk = sctp_make_asconf_update_ip(asoc, &laddr->a_h, addrs,
                                                   addrcnt, SCTP_PARAM_ADD_IP);
                if (!chunk) {
                        retval = -ENOMEM;
@@ -779,7 +779,7 @@ static int sctp_send_asconf_del_ip(struct sock              *sk,
                                saddr = list_entry(pos1,
                                                   struct sctp_sockaddr_entry,
                                                   list);
-                               if (sctp_cmp_addr_exact(&saddr->a, &saveaddr))
+                               if (sctp_cmp_addr_exact(&saddr->a_h, &saveaddr))
                                        saddr->use_as_src = 0;
                        }
                        addr_buf += af->sockaddr_len;
@@ -821,7 +821,7 @@ out:
  * addrs is a pointer to an array of one or more socket addresses. Each
  * address is contained in its appropriate structure (i.e. struct
  * sockaddr_in or struct sockaddr_in6) the family of the address type
- * must be used to distengish the address length (note that this
+ * must be used to distinguish the address length (note that this
  * representation is termed a "packed array" of addresses). The caller
  * specifies the number of addresses in the array with addrcnt.
  *
@@ -3217,8 +3217,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len,
        status.sstat_outstrms = asoc->c.sinit_num_ostreams;
        status.sstat_fragmentation_point = asoc->frag_point;
        status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
-       memcpy(&status.sstat_primary.spinfo_address,
-              &(transport->ipaddr), sizeof(union sctp_addr));
+       flip_to_n((union sctp_addr *)&status.sstat_primary.spinfo_address,
+              &transport->ipaddr_h);
        /* Map ipv4 address into v4-mapped-on-v6 address.  */
        sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
                (union sctp_addr *)&status.sstat_primary.spinfo_address);
@@ -3372,6 +3372,7 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
 {
        struct sock *sk = asoc->base.sk;
        struct socket *sock;
+       struct inet_sock *inetsk;
        int err = 0;
 
        /* An association cannot be branched off from an already peeled-off
@@ -3389,6 +3390,14 @@ SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
         * asoc to the newsk.
         */
        sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
+
+       /* Make peeled-off sockets more like 1-1 accepted sockets.
+        * Set the daddr and initialize id to something more random
+        */
+       inetsk = inet_sk(sock->sk);
+       inetsk->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr;
+       inetsk->id = asoc->next_tsn ^ jiffies;
+
        *sockp = sock;
 
        return err;
@@ -3758,7 +3767,7 @@ static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len,
        to = (void __user *)getaddrs.addrs;
        list_for_each(pos, &asoc->peer.transport_addr_list) {
                from = list_entry(pos, struct sctp_transport, transports);
-               memcpy(&temp, &from->ipaddr, sizeof(temp));
+               memcpy(&temp, &from->ipaddr_h, sizeof(temp));
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
                addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
                temp.v4.sin_port = htons(temp.v4.sin_port);
@@ -3807,7 +3816,7 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
 
        list_for_each(pos, &asoc->peer.transport_addr_list) {
                from = list_entry(pos, struct sctp_transport, transports);
-               memcpy(&temp, &from->ipaddr, sizeof(temp));
+               memcpy(&temp, &from->ipaddr_h, sizeof(temp));
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
                addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
                if(space_left < addrlen)
@@ -3873,14 +3882,14 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
        if (sctp_list_single_entry(&bp->address_list)) {
                addr = list_entry(bp->address_list.next,
                                  struct sctp_sockaddr_entry, list);
-               if (sctp_is_any(&addr->a)) {
+               if (sctp_is_any(&addr->a_h)) {
                        sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
                        list_for_each(pos, &sctp_local_addr_list) {
                                addr = list_entry(pos,
                                                  struct sctp_sockaddr_entry,
                                                  list);
                                if ((PF_INET == sk->sk_family) && 
-                                   (AF_INET6 == addr->a.sa.sa_family)) 
+                                   (AF_INET6 == addr->a_h.sa.sa_family))
                                        continue;
                                cnt++;
                        }
@@ -3918,9 +3927,9 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add
        list_for_each(pos, &sctp_local_addr_list) {
                addr = list_entry(pos, struct sctp_sockaddr_entry, list);
                if ((PF_INET == sk->sk_family) && 
-                   (AF_INET6 == addr->a.sa.sa_family))
+                   (AF_INET6 == addr->a_h.sa.sa_family))
                        continue;
-               memcpy(&temp, &addr->a, sizeof(temp));
+               memcpy(&temp, &addr->a_h, sizeof(temp));
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
                                                                &temp);
                addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
@@ -3953,9 +3962,9 @@ static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port,
        list_for_each(pos, &sctp_local_addr_list) {
                addr = list_entry(pos, struct sctp_sockaddr_entry, list);
                if ((PF_INET == sk->sk_family) && 
-                   (AF_INET6 == addr->a.sa.sa_family))
+                   (AF_INET6 == addr->a_h.sa.sa_family))
                        continue;
-               memcpy(&temp, &addr->a, sizeof(temp));
+               memcpy(&temp, &addr->a_h, sizeof(temp));
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
                                                                &temp);
                addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
@@ -4029,7 +4038,7 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
        if (sctp_list_single_entry(&bp->address_list)) {
                addr = list_entry(bp->address_list.next,
                                  struct sctp_sockaddr_entry, list);
-               if (sctp_is_any(&addr->a)) {
+               if (sctp_is_any(&addr->a_h)) {
                        cnt = sctp_copy_laddrs_to_user_old(sk, bp->port,
                                                           getaddrs.addr_num,
                                                           to);
@@ -4043,7 +4052,7 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
 
        list_for_each(pos, &bp->address_list) {
                addr = list_entry(pos, struct sctp_sockaddr_entry, list);
-               memcpy(&temp, &addr->a, sizeof(temp));
+               memcpy(&temp, &addr->a_h, sizeof(temp));
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
                addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
                temp.v4.sin_port = htons(temp.v4.sin_port);
@@ -4119,7 +4128,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
        if (sctp_list_single_entry(&bp->address_list)) {
                addr = list_entry(bp->address_list.next,
                                  struct sctp_sockaddr_entry, list);
-               if (sctp_is_any(&addr->a)) {
+               if (sctp_is_any(&addr->a_h)) {
                        cnt = sctp_copy_laddrs_to_user(sk, bp->port,
                                                       &to, space_left);
                        if (cnt < 0) {
@@ -4132,7 +4141,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
 
        list_for_each(pos, &bp->address_list) {
                addr = list_entry(pos, struct sctp_sockaddr_entry, list);
-               memcpy(&temp, &addr->a, sizeof(temp));
+               memcpy(&temp, &addr->a_h, sizeof(temp));
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
                addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
                if(space_left < addrlen)
@@ -4185,12 +4194,8 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
        if (!asoc->peer.primary_path)
                return -ENOTCONN;
        
-       asoc->peer.primary_path->ipaddr.v4.sin_port =
-               htons(asoc->peer.primary_path->ipaddr.v4.sin_port);
-       memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr,
-              sizeof(union sctp_addr));
-       asoc->peer.primary_path->ipaddr.v4.sin_port =
-               ntohs(asoc->peer.primary_path->ipaddr.v4.sin_port);
+       flip_to_n((union sctp_addr *)&prim.ssp_addr,
+                 &asoc->peer.primary_path->ipaddr_h);
 
        sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp,
                        (union sctp_addr *)&prim.ssp_addr);
@@ -4633,12 +4638,12 @@ 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 */
+       union sctp_addr tmp;
        unsigned short snum;
        int ret;
 
-       /* NOTE:  Remember to put this back to net order. */
-       addr->v4.sin_port = ntohs(addr->v4.sin_port);
-       snum = addr->v4.sin_port;
+       flip_to_h(&tmp, addr);
+       snum = ntohs(addr->v4.sin_port);
 
        SCTP_DEBUG_PRINTK("sctp_get_port() begins, snum=%d\n", snum);
        sctp_local_bh_disable();
@@ -4735,7 +4740,7 @@ pp_found:
                        if (reuse && sk2->sk_reuse)
                                continue;
 
-                       if (sctp_bind_addr_match(&ep2->base.bind_addr, addr,
+                       if (sctp_bind_addr_match(&ep2->base.bind_addr, &tmp,
                                                 sctp_sk(sk))) {
                                ret = (long)sk2;
                                goto fail_unlock;
@@ -4775,7 +4780,6 @@ fail_unlock:
 
 fail:
        sctp_local_bh_enable();
-       addr->v4.sin_port = htons(addr->v4.sin_port);
        return ret;
 }
 
@@ -5362,6 +5366,20 @@ static void sctp_wfree(struct sk_buff *skb)
        sctp_association_put(asoc);
 }
 
+/* Do accounting for the receive space on the socket.
+ * Accounting for the association is done in ulpevent.c
+ * We set this as a destructor for the cloned data skbs so that
+ * accounting is done at the correct time.
+ */
+void sctp_sock_rfree(struct sk_buff *skb)
+{
+       struct sock *sk = skb->sk;
+       struct sctp_ulpevent *event = sctp_skb2event(skb);
+
+       atomic_sub(event->rmem_len, &sk->sk_rmem_alloc);
+}
+
+
 /* Helper function to wait for space in the sndbuf.  */
 static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
                                size_t msg_len)
@@ -5634,10 +5652,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
        sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
                event = sctp_skb2event(skb);
                if (event->asoc == assoc) {
-                       sock_rfree(skb);
+                       sctp_sock_rfree(skb);
                        __skb_unlink(skb, &oldsk->sk_receive_queue);
                        __skb_queue_tail(&newsk->sk_receive_queue, skb);
-                       skb_set_owner_r(skb, newsk);
+                       sctp_skb_set_owner_r(skb, newsk);
                }
        }
 
@@ -5665,10 +5683,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
                sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
                        event = sctp_skb2event(skb);
                        if (event->asoc == assoc) {
-                               sock_rfree(skb);
+                               sctp_sock_rfree(skb);
                                __skb_unlink(skb, &oldsp->pd_lobby);
                                __skb_queue_tail(queue, skb);
-                               skb_set_owner_r(skb, newsk);
+                               sctp_skb_set_owner_r(skb, newsk);
                        }
                }