Fix occurrences of "the the "
[powerpc.git] / net / sctp / socket.c
index 1e787a2..83a76ba 100644 (file)
@@ -941,7 +941,7 @@ SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk,
        default:
                err = -EINVAL;
                break;
-       };
+       }
 
 out:
        kfree(kaddrs);
@@ -972,6 +972,7 @@ static int __sctp_connect(struct sock* sk,
        int walk_size = 0;
        union sctp_addr *sa_addr;
        void *addr_buf;
+       unsigned short port;
 
        sp = sctp_sk(sk);
        ep = sp->ep;
@@ -992,6 +993,7 @@ static int __sctp_connect(struct sock* sk,
        while (walk_size < addrs_size) {
                sa_addr = (union sctp_addr *)addr_buf;
                af = sctp_get_af_specific(sa_addr->sa.sa_family);
+               port = ntohs(sa_addr->v4.sin_port);
 
                /* If the address family is not supported or if this address
                 * causes the address buffer to overflow return EINVAL.
@@ -1005,6 +1007,12 @@ static int __sctp_connect(struct sock* sk,
                if (err)
                        goto out_free;
 
+               /* Make sure the destination port is correctly set
+                * in all addresses.
+                */
+               if (asoc && asoc->peer.port && asoc->peer.port != port)
+                       goto out_free;
+
                memcpy(&to, sa_addr, af->sockaddr_len);
 
                /* Check if there already is a matching association on the
@@ -2039,6 +2047,10 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,
  *                     SPP_HB_DEMAND - Request a user initiated heartbeat
  *                     to be made immediately.
  *
+ *                     SPP_HB_TIME_IS_ZERO - Specify's that the time for
+ *                     heartbeat delayis to be set to the value of 0
+ *                     milliseconds.
+ *
  *                     SPP_PMTUD_ENABLE - This field will enable PMTU
  *                     discovery upon the specified address. Note that
  *                     if the address feild is empty then all addresses
@@ -2081,13 +2093,30 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
                        return error;
        }
 
-       if (params->spp_hbinterval) {
-               if (trans) {
-                       trans->hbinterval = msecs_to_jiffies(params->spp_hbinterval);
-               } else if (asoc) {
-                       asoc->hbinterval = msecs_to_jiffies(params->spp_hbinterval);
-               } else {
-                       sp->hbinterval = params->spp_hbinterval;
+       /* Note that unless the spp_flag is set to SPP_HB_ENABLE the value of
+        * this field is ignored.  Note also that a value of zero indicates
+        * the current setting should be left unchanged.
+        */
+       if (params->spp_flags & SPP_HB_ENABLE) {
+
+               /* Re-zero the interval if the SPP_HB_TIME_IS_ZERO is
+                * set.  This lets us use 0 value when this flag
+                * is set.
+                */
+               if (params->spp_flags & SPP_HB_TIME_IS_ZERO)
+                       params->spp_hbinterval = 0;
+
+               if (params->spp_hbinterval ||
+                   (params->spp_flags & SPP_HB_TIME_IS_ZERO)) {
+                       if (trans) {
+                               trans->hbinterval =
+                                   msecs_to_jiffies(params->spp_hbinterval);
+                       } else if (asoc) {
+                               asoc->hbinterval =
+                                   msecs_to_jiffies(params->spp_hbinterval);
+                       } else {
+                               sp->hbinterval = params->spp_hbinterval;
+                       }
                }
        }
 
@@ -2104,7 +2133,12 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
                }
        }
 
-       if (params->spp_pathmtu) {
+       /* When Path MTU discovery is disabled the value specified here will
+        * be the "fixed" path mtu (i.e. the value of the spp_flags field must
+        * include the flag SPP_PMTUD_DISABLE for this field to have any
+        * effect).
+        */
+       if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) {
                if (trans) {
                        trans->pathmtu = params->spp_pathmtu;
                        sctp_assoc_sync_pmtu(asoc);
@@ -2135,7 +2169,11 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
                }
        }
 
-       if (params->spp_sackdelay) {
+       /* Note that unless the spp_flag is set to SPP_SACKDELAY_ENABLE the
+        * value of this field is ignored.  Note also that a value of zero
+        * indicates the current setting should be left unchanged.
+        */
+       if ((params->spp_flags & SPP_SACKDELAY_ENABLE) && params->spp_sackdelay) {
                if (trans) {
                        trans->sackdelay =
                                msecs_to_jiffies(params->spp_sackdelay);
@@ -2163,7 +2201,11 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
                }
        }
 
-       if (params->spp_pathmaxrxt) {
+       /* Note that unless the spp_flag is set to SPP_PMTUD_ENABLE the value
+        * of this field is ignored.  Note also that a value of zero
+        * indicates the current setting should be left unchanged.
+        */
+       if ((params->spp_flags & SPP_PMTUD_ENABLE) && params->spp_pathmaxrxt) {
                if (trans) {
                        trans->pathmaxrxt = params->spp_pathmaxrxt;
                } else if (asoc) {
@@ -2544,7 +2586,7 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, int opt
  *
  * 7.1.2 SCTP_ASSOCINFO
  *
- * This option is used to tune the the maximum retransmission attempts
+ * This option is used to tune the maximum retransmission attempts
  * of the association.
  * Returns an error if the new association retransmission value is
  * greater than the sum of the retransmission value  of the peer.
@@ -2858,6 +2900,36 @@ static int sctp_setsockopt_partial_delivery_point(struct sock *sk,
        return 0; /* is this the right error code? */
 }
 
+/*
+ * 7.1.28.  Set or Get the maximum burst (SCTP_MAX_BURST)
+ *
+ * This option will allow a user to change the maximum burst of packets
+ * that can be emitted by this association.  Note that the default value
+ * is 4, and some implementations may restrict this setting so that it
+ * can only be lowered.
+ *
+ * NOTE: This text doesn't seem right.  Do this on a socket basis with
+ * future associations inheriting the socket value.
+ */
+static int sctp_setsockopt_maxburst(struct sock *sk,
+                                   char __user *optval,
+                                   int optlen)
+{
+       int val;
+
+       if (optlen != sizeof(int))
+               return -EINVAL;
+       if (get_user(val, (int __user *)optval))
+               return -EFAULT;
+
+       if (val < 0)
+               return -EINVAL;
+
+       sctp_sk(sk)->max_burst = val;
+
+       return 0;
+}
+
 /* API 6.2 setsockopt(), getsockopt()
  *
  * Applications use setsockopt() and getsockopt() to set or retrieve
@@ -2978,10 +3050,13 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
        case SCTP_FRAGMENT_INTERLEAVE:
                retval = sctp_setsockopt_fragment_interleave(sk, optval, optlen);
                break;
+       case SCTP_MAX_BURST:
+               retval = sctp_setsockopt_maxburst(sk, optval, optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;
-       };
+       }
 
        sctp_release_sock(sk);
 
@@ -3137,6 +3212,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
        sp->default_timetolive = 0;
 
        sp->default_rcv_context = 0;
+       sp->max_burst = sctp_max_burst;
 
        /* Initialize default setup parameters. These parameters
         * can be modified with the SCTP_INITMSG socket option or
@@ -3919,7 +3995,7 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
                memcpy(&temp, &from->ipaddr, 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)
+               if (space_left < addrlen)
                        return -ENOMEM;
                if (copy_to_user(to, &temp, addrlen))
                        return -EFAULT;
@@ -4008,8 +4084,9 @@ done:
 /* Helper function that copies local addresses to user and returns the number
  * of addresses copied.
  */
-static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs,
-                                       void __user *to)
+static int sctp_copy_laddrs_old(struct sock *sk, __u16 port,
+                                       int max_addrs, void *to,
+                                       int *bytes_copied)
 {
        struct list_head *pos, *next;
        struct sctp_sockaddr_entry *addr;
@@ -4026,10 +4103,10 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
                                                                &temp);
                addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
-               if (copy_to_user(to, &temp, addrlen))
-                       return -EFAULT;
+               memcpy(to, &temp, addrlen);
 
                to += addrlen;
+               *bytes_copied += addrlen;
                cnt ++;
                if (cnt >= max_addrs) break;
        }
@@ -4037,8 +4114,8 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add
        return cnt;
 }
 
-static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port,
-                                   void __user **to, size_t space_left)
+static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
+                           size_t space_left, int *bytes_copied)
 {
        struct list_head *pos, *next;
        struct sctp_sockaddr_entry *addr;
@@ -4055,14 +4132,14 @@ static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port,
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
                                                                &temp);
                addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
-               if(space_left<addrlen)
+               if (space_left < addrlen)
                        return -ENOMEM;
-               if (copy_to_user(*to, &temp, addrlen))
-                       return -EFAULT;
+               memcpy(to, &temp, addrlen);
 
-               *to += addrlen;
+               to += addrlen;
                cnt ++;
                space_left -= addrlen;
+               bytes_copied += addrlen;
        }
 
        return cnt;
@@ -4086,6 +4163,8 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
        int addrlen;
        rwlock_t *addr_lock;
        int err = 0;
+       void *addrs;
+       int bytes_copied = 0;
 
        if (len != sizeof(struct sctp_getaddrs_old))
                return -EINVAL;
@@ -4113,6 +4192,15 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
 
        to = getaddrs.addrs;
 
+       /* Allocate space for a local instance of packed array to hold all
+        * the data.  We store addresses here first and then put write them
+        * to the user in one shot.
+        */
+       addrs = kmalloc(sizeof(union sctp_addr) * getaddrs.addr_num,
+                       GFP_KERNEL);
+       if (!addrs)
+               return -ENOMEM;
+
        sctp_read_lock(addr_lock);
 
        /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
@@ -4122,13 +4210,9 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
                addr = list_entry(bp->address_list.next,
                                  struct sctp_sockaddr_entry, list);
                if (sctp_is_any(&addr->a)) {
-                       cnt = sctp_copy_laddrs_to_user_old(sk, bp->port,
-                                                          getaddrs.addr_num,
-                                                          to);
-                       if (cnt < 0) {
-                               err = cnt;
-                               goto unlock;
-                       }
+                       cnt = sctp_copy_laddrs_old(sk, bp->port,
+                                                  getaddrs.addr_num,
+                                                  addrs, &bytes_copied);
                        goto copy_getaddrs;
                }
        }
@@ -4138,22 +4222,29 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
                memcpy(&temp, &addr->a, 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 (copy_to_user(to, &temp, addrlen)) {
-                       err = -EFAULT;
-                       goto unlock;
-               }
+               memcpy(addrs, &temp, addrlen);
                to += addrlen;
+               bytes_copied += addrlen;
                cnt ++;
                if (cnt >= getaddrs.addr_num) break;
        }
 
 copy_getaddrs:
+       sctp_read_unlock(addr_lock);
+
+       /* copy the entire address list into the user provided space */
+       if (copy_to_user(to, addrs, bytes_copied)) {
+               err = -EFAULT;
+               goto error;
+       }
+
+       /* copy the leading structure back to user */
        getaddrs.addr_num = cnt;
        if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old)))
                err = -EFAULT;
 
-unlock:
-       sctp_read_unlock(addr_lock);
+error:
+       kfree(addrs);
        return err;
 }
 
@@ -4173,7 +4264,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
        rwlock_t *addr_lock;
        int err = 0;
        size_t space_left;
-       int bytes_copied;
+       int bytes_copied = 0;
+       void *addrs;
 
        if (len <= sizeof(struct sctp_getaddrs))
                return -EINVAL;
@@ -4201,6 +4293,9 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
        to = optval + offsetof(struct sctp_getaddrs,addrs);
        space_left = len - sizeof(struct sctp_getaddrs) -
                         offsetof(struct sctp_getaddrs,addrs);
+       addrs = kmalloc(space_left, GFP_KERNEL);
+       if (!addrs)
+               return -ENOMEM;
 
        sctp_read_lock(addr_lock);
 
@@ -4211,11 +4306,11 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
                addr = list_entry(bp->address_list.next,
                                  struct sctp_sockaddr_entry, list);
                if (sctp_is_any(&addr->a)) {
-                       cnt = sctp_copy_laddrs_to_user(sk, bp->port,
-                                                      &to, space_left);
+                       cnt = sctp_copy_laddrs(sk, bp->port, addrs,
+                                               space_left, &bytes_copied);
                        if (cnt < 0) {
                                err = cnt;
-                               goto unlock;
+                               goto error;
                        }
                        goto copy_getaddrs;
                }
@@ -4226,26 +4321,31 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
                memcpy(&temp, &addr->a, 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)
-                       return -ENOMEM; /*fixme: right error?*/
-               if (copy_to_user(to, &temp, addrlen)) {
-                       err = -EFAULT;
-                       goto unlock;
+               if (space_left < addrlen) {
+                       err =  -ENOMEM; /*fixme: right error?*/
+                       goto error;
                }
+               memcpy(addrs, &temp, addrlen);
                to += addrlen;
+               bytes_copied += addrlen;
                cnt ++;
                space_left -= addrlen;
        }
 
 copy_getaddrs:
+       sctp_read_unlock(addr_lock);
+
+       if (copy_to_user(to, addrs, bytes_copied)) {
+               err = -EFAULT;
+               goto error;
+       }
        if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num))
                return -EFAULT;
-       bytes_copied = ((char __user *)to) - optval;
        if (put_user(bytes_copied, optlen))
                return -EFAULT;
 
-unlock:
-       sctp_read_unlock(addr_lock);
+error:
+       kfree(addrs);
        return err;
 }
 
@@ -4447,7 +4547,7 @@ static int sctp_getsockopt_rtoinfo(struct sock *sk, int len,
  *
  * 7.1.2 SCTP_ASSOCINFO
  *
- * This option is used to tune the the maximum retransmission attempts
+ * This option is used to tune the maximum retransmission attempts
  * of the association.
  * Returns an error if the new association retransmission value is
  * greater than the sum of the retransmission value  of the peer.
@@ -4655,6 +4755,30 @@ static int sctp_getsockopt_partial_delivery_point(struct sock *sk, int len,
        return -ENOTSUPP;
 }
 
+/*
+ * 7.1.28.  Set or Get the maximum burst (SCTP_MAX_BURST)
+ * (chapter and verse is quoted at sctp_setsockopt_maxburst())
+ */
+static int sctp_getsockopt_maxburst(struct sock *sk, int len,
+                                   char __user *optval,
+                                   int __user *optlen)
+{
+        int val;
+
+       if (len < sizeof(int))
+               return -EINVAL;
+
+       len = sizeof(int);
+
+       val = sctp_sk(sk)->max_burst;
+       if (put_user(len, optlen))
+               return -EFAULT;
+       if (copy_to_user(optval, &val, len))
+               return -EFAULT;
+
+       return -ENOTSUPP;
+}
+
 SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
                                char __user *optval, int __user *optlen)
 {
@@ -4775,10 +4899,13 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
                retval = sctp_getsockopt_partial_delivery_point(sk, len, optval,
                                                                optlen);
                break;
+       case SCTP_MAX_BURST:
+               retval = sctp_getsockopt_maxburst(sk, len, optval, optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;
-       };
+       }
 
        sctp_release_sock(sk);
        return retval;
@@ -4893,7 +5020,8 @@ pp_found:
                struct hlist_node *node;
 
                SCTP_DEBUG_PRINTK("sctp_get_port() found a possible match\n");
-               if (pp->fastreuse && sk->sk_reuse)
+               if (pp->fastreuse && sk->sk_reuse &&
+                       sk->sk_state != SCTP_SS_LISTENING)
                        goto success;
 
                /* Run through the list of sockets bound to the port
@@ -4910,7 +5038,8 @@ pp_found:
                        struct sctp_endpoint *ep2;
                        ep2 = sctp_sk(sk2)->ep;
 
-                       if (reuse && sk2->sk_reuse)
+                       if (reuse && sk2->sk_reuse &&
+                           sk2->sk_state != SCTP_SS_LISTENING)
                                continue;
 
                        if (sctp_bind_addr_match(&ep2->base.bind_addr, addr,
@@ -4931,9 +5060,13 @@ pp_not_found:
         * if sk->sk_reuse is too (that is, if the caller requested
         * SO_REUSEADDR on this socket -sk-).
         */
-       if (hlist_empty(&pp->owner))
-               pp->fastreuse = sk->sk_reuse ? 1 : 0;
-       else if (pp->fastreuse && !sk->sk_reuse)
+       if (hlist_empty(&pp->owner)) {
+               if (sk->sk_reuse && sk->sk_state != SCTP_SS_LISTENING)
+                       pp->fastreuse = 1;
+               else
+                       pp->fastreuse = 0;
+       } else if (pp->fastreuse &&
+               (!sk->sk_reuse || sk->sk_state == SCTP_SS_LISTENING))
                pp->fastreuse = 0;
 
        /* We are set, so fill up all the data in the hash table
@@ -4941,8 +5074,8 @@ pp_not_found:
         * sockets FIXME: Blurry, NPI (ipg).
         */
 success:
-       inet_sk(sk)->num = snum;
        if (!sctp_sk(sk)->bind_hash) {
+               inet_sk(sk)->num = snum;
                sk_add_bind_node(sk, &pp->owner);
                sctp_sk(sk)->bind_hash = pp;
        }
@@ -5015,12 +5148,16 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
         * This is not currently spelled out in the SCTP sockets
         * extensions draft, but follows the practice as seen in TCP
         * sockets.
+        *
+        * Additionally, turn off fastreuse flag since we are not listening
         */
+       sk->sk_state = SCTP_SS_LISTENING;
        if (!ep->base.bind_addr.port) {
                if (sctp_autobind(sk))
                        return -EAGAIN;
-       }
-       sk->sk_state = SCTP_SS_LISTENING;
+       } else
+               sctp_sk(sk)->bind_hash->fastreuse = 0;
+
        sctp_hash_endpoint(ep);
        return 0;
 }
@@ -5058,11 +5195,13 @@ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog)
         * extensions draft, but follows the practice as seen in TCP
         * sockets.
         */
+       sk->sk_state = SCTP_SS_LISTENING;
        if (!ep->base.bind_addr.port) {
                if (sctp_autobind(sk))
                        return -EAGAIN;
-       }
-       sk->sk_state = SCTP_SS_LISTENING;
+       } else
+               sctp_sk(sk)->bind_hash->fastreuse = 0;
+
        sk->sk_max_ack_backlog = backlog;
        sctp_hash_endpoint(ep);
        return 0;
@@ -5103,7 +5242,8 @@ int sctp_inet_listen(struct socket *sock, int backlog)
                break;
        default:
                break;
-       };
+       }
+
        if (err)
                goto cleanup;
 
@@ -5366,7 +5506,7 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
 
                default:
                        return -EINVAL;
-               };
+               }
        }
        return 0;
 }