Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband
[linux-drm-fsl-dcu.git] / net / x25 / af_x25.c
index b5c80b18990224439e512fb819a96e75fb909b97..e62ba41b05c59b06e8889440f079ccbd9f19344b 100644 (file)
@@ -3,7 +3,7 @@
  *
  *     This is ALPHA test software. This code may break your machine,
  *     randomly fail to work with new releases, misbehave and/or generally
- *     screw up. It might even work. 
+ *     screw up. It might even work.
  *
  *     This code REQUIRES 2.1.15 or higher
  *
  *     X.25 002        Jonathan Naylor Centralised disconnect handling.
  *                                     New timer architecture.
  *     2000-03-11      Henner Eisen    MSG_EOR handling more POSIX compliant.
- *     2000-03-22      Daniela Squassoni Allowed disabling/enabling of 
- *                                       facilities negotiation and increased 
+ *     2000-03-22      Daniela Squassoni Allowed disabling/enabling of
+ *                                       facilities negotiation and increased
  *                                       the throughput upper limit.
  *     2000-08-27      Arnaldo C. Melo s/suser/capable/ + micro cleanups
- *     2000-09-04      Henner Eisen    Set sock->state in x25_accept(). 
+ *     2000-09-04      Henner Eisen    Set sock->state in x25_accept().
  *                                     Fixed x25_output() related skb leakage.
  *     2000-10-02      Henner Eisen    Made x25_kick() single threaded per socket.
  *     2000-10-27      Henner Eisen    MSG_DONTWAIT for fragment allocation.
@@ -63,6 +63,7 @@ int sysctl_x25_call_request_timeout    = X25_DEFAULT_T21;
 int sysctl_x25_reset_request_timeout   = X25_DEFAULT_T22;
 int sysctl_x25_clear_request_timeout   = X25_DEFAULT_T23;
 int sysctl_x25_ack_holdback_timeout    = X25_DEFAULT_T2;
+int sysctl_x25_forward                 = 0;
 
 HLIST_HEAD(x25_list);
 DEFINE_RWLOCK(x25_list_lock);
@@ -255,8 +256,8 @@ static struct sock *x25_find_listener(struct x25_address *addr,
                         * call user data vs this sockets call user data
                         */
                        if(skb->len > 0 && x25_sk(s)->cudmatchlength > 0) {
-                               if((memcmp(x25_sk(s)->calluserdata.cuddata,
-                                       skb->data,
+                               if((memcmp(x25_sk(s)->calluserdata.cuddata,
+                                       skb->data,
                                        x25_sk(s)->cudmatchlength)) == 0) {
                                        sock_hold(s);
                                        goto found;
@@ -420,7 +421,7 @@ static int x25_getsockopt(struct socket *sock, int level, int optname,
 {
        struct sock *sk = sock->sk;
        int val, len, rc = -ENOPROTOOPT;
-       
+
        if (level != SOL_X25 || optname != X25_QBITINCL)
                goto out;
 
@@ -433,7 +434,7 @@ static int x25_getsockopt(struct socket *sock, int level, int optname,
        rc = -EINVAL;
        if (len < 0)
                goto out;
-               
+
        rc = -EFAULT;
        if (put_user(len, optlen))
                goto out;
@@ -522,12 +523,12 @@ static int x25_create(struct socket *sock, int protocol)
        x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE;
        x25->facilities.throughput  = X25_DEFAULT_THROUGHPUT;
        x25->facilities.reverse     = X25_DEFAULT_REVERSE;
-       x25->dte_facilities.calling_len = 0;
-       x25->dte_facilities.called_len = 0;
-       memset(x25->dte_facilities.called_ae, '\0',
-                       sizeof(x25->dte_facilities.called_ae));
-       memset(x25->dte_facilities.calling_ae, '\0',
-                       sizeof(x25->dte_facilities.calling_ae));
+       x25->dte_facilities.calling_len = 0;
+       x25->dte_facilities.called_len = 0;
+       memset(x25->dte_facilities.called_ae, '\0',
+                       sizeof(x25->dte_facilities.called_ae));
+       memset(x25->dte_facilities.calling_ae, '\0',
+                       sizeof(x25->dte_facilities.calling_ae));
 
        rc = 0;
 out:
@@ -607,7 +608,7 @@ static int x25_release(struct socket *sock)
                        break;
        }
 
-       sock->sk        = NULL; 
+       sock->sk        = NULL;
        sk->sk_socket   = NULL; /* Not used, but we should do this */
 out:
        return 0;
@@ -634,7 +635,7 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 static int x25_wait_for_connection_establishment(struct sock *sk)
 {
        DECLARE_WAITQUEUE(wait, current);
-        int rc;
+       int rc;
 
        add_wait_queue_exclusive(sk->sk_sleep, &wait);
        for (;;) {
@@ -685,7 +686,7 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr,
        if (sk->sk_state == TCP_ESTABLISHED)
                goto out;
 
-       sk->sk_state   = TCP_CLOSE;     
+       sk->sk_state   = TCP_CLOSE;
        sock->state = SS_UNCONNECTED;
 
        rc = -EINVAL;
@@ -777,7 +778,7 @@ static int x25_wait_for_data(struct sock *sk, long timeout)
        remove_wait_queue(sk->sk_sleep, &wait);
        return rc;
 }
-       
+
 static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
 {
        struct sock *sk = sock->sk;
@@ -836,7 +837,7 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr,
 
        return 0;
 }
+
 int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
                        unsigned int lci)
 {
@@ -846,7 +847,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
        struct x25_address source_addr, dest_addr;
        struct x25_facilities facilities;
        struct x25_dte_facilities dte_facilities;
-       int len, rc;
+       int len, addr_len, rc;
 
        /*
         *      Remove the LCI and frame type.
@@ -857,7 +858,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
         *      Extract the X.25 addresses and convert them to ASCII strings,
         *      and remove them.
         */
-       skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr));
+       addr_len = x25_addr_ntoa(skb->data, &source_addr, &dest_addr);
+       skb_pull(skb, addr_len);
 
        /*
         *      Get the length of the facilities, skip past them for the moment
@@ -873,11 +875,28 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
        sk = x25_find_listener(&source_addr,skb);
        skb_push(skb,len);
 
+       if (sk != NULL && sk_acceptq_is_full(sk)) {
+               goto out_sock_put;
+       }
+
        /*
-        *      We can't accept the Call Request.
+        *      We dont have any listeners for this incoming call.
+        *      Try forwarding it.
         */
-       if (sk == NULL || sk_acceptq_is_full(sk))
-               goto out_clear_request;
+       if (sk == NULL) {
+               skb_push(skb, addr_len + X25_STD_MIN_LEN);
+               if (sysctl_x25_forward &&
+                               x25_forward_call(&dest_addr, nb, skb, lci) > 0)
+               {
+                       /* Call was forwarded, dont process it any more */
+                       kfree_skb(skb);
+                       rc = 1;
+                       goto out;
+               } else {
+                       /* No listeners, can't forward, clear the call */
+                       goto out_clear_request;
+               }
+       }
 
        /*
         *      Try to reach a compromise on the requested facilities.
@@ -1101,7 +1120,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
        if (msg->msg_flags & MSG_OOB)
                skb_queue_tail(&x25->interrupt_out_queue, skb);
        else {
-               len = x25_output(sk, skb);
+               len = x25_output(sk, skb);
                if (len < 0)
                        kfree_skb(skb);
                else if (x25->qbitincl)
@@ -1200,7 +1219,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
                msg->msg_flags |= MSG_TRUNC;
        }
 
-       /* Currently, each datagram always contains a complete record */ 
+       /* Currently, each datagram always contains a complete record */
        msg->msg_flags |= MSG_EOR;
 
        rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
@@ -1258,8 +1277,8 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                case SIOCGSTAMP:
                        rc = -EINVAL;
                        if (sk)
-                               rc = sock_get_timestamp(sk, 
-                                               (struct timeval __user *)argp); 
+                               rc = sock_get_timestamp(sk,
+                                               (struct timeval __user *)argp);
                        break;
                case SIOCGIFADDR:
                case SIOCSIFADDR:
@@ -1327,17 +1346,17 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                }
 
                case SIOCX25GDTEFACILITIES: {
-                       rc = copy_to_user(argp, &x25->dte_facilities,
+                       rc = copy_to_user(argp, &x25->dte_facilities,
                                                sizeof(x25->dte_facilities));
                        if (rc)
                                rc = -EFAULT;
-                       break;
-               }
+                       break;
+               }
 
-               case SIOCX25SDTEFACILITIES: {
-                       struct x25_dte_facilities dtefacs;
-                       rc = -EFAULT;
-                       if (copy_from_user(&dtefacs, argp, sizeof(dtefacs)))
+               case SIOCX25SDTEFACILITIES: {
+                       struct x25_dte_facilities dtefacs;
+                       rc = -EFAULT;
+                       if (copy_from_user(&dtefacs, argp, sizeof(dtefacs)))
                                break;
                        rc = -EINVAL;
                        if (sk->sk_state != TCP_LISTEN &&
@@ -1395,7 +1414,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        if (copy_from_user(&sub_addr, argp,
                                        sizeof(sub_addr)))
                                break;
-                       rc = -EINVAL;
+                       rc = -EINVAL;
                        if(sub_addr.cudmatchlength > X25_MAX_CUD_LEN)
                                break;
                        x25->cudmatchlength = sub_addr.cudmatchlength;
@@ -1424,7 +1443,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        break;
                }
 
-               default:
+               default:
                        rc = -ENOIOCTLCMD;
                        break;
        }
@@ -1598,6 +1617,9 @@ void x25_kill_by_neigh(struct x25_neigh *nb)
                        x25_disconnect(s, ENETUNREACH, 0, 0);
 
        write_unlock_bh(&x25_list_lock);
+
+       /* Remove any related forwards */
+       x25_clear_forward_by_dev(nb->dev);
 }
 
 static int __init x25_init(void)