[PATCH] Add retain_initrd boot option
[linux-2.6.git] / net / x25 / af_x25.c
index 03725c05175294732418b62107db627059179a50..b37d894358ec28fb68e83d387a79b486024e40a2 100644 (file)
@@ -35,7 +35,6 @@
  *                                     response
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/capability.h>
 #include <linux/errno.h>
@@ -64,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);
@@ -485,8 +485,6 @@ out:
        return sk;
 }
 
-void x25_init_timers(struct sock *sk);
-
 static int x25_create(struct socket *sock, int protocol)
 {
        struct sock *sk;
@@ -525,6 +523,13 @@ 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));
+
        rc = 0;
 out:
        return rc;
@@ -561,6 +566,7 @@ static struct sock *x25_make_new(struct sock *osk)
        x25->t2         = ox25->t2;
        x25->facilities = ox25->facilities;
        x25->qbitincl   = ox25->qbitincl;
+       x25->dte_facilities = ox25->dte_facilities;
        x25->cudmatchlength = ox25->cudmatchlength;
        x25->accptapprv = ox25->accptapprv;
 
@@ -840,7 +846,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
        struct x25_sock *makex25;
        struct x25_address source_addr, dest_addr;
        struct x25_facilities facilities;
-       int len, rc;
+       struct x25_dte_facilities dte_facilities;
+       int len, addr_len, rc;
 
        /*
         *      Remove the LCI and frame type.
@@ -851,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
@@ -867,16 +875,34 @@ 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.
         */
-       if ((len = x25_negotiate_facilities(skb, sk, &facilities)) == -1)
+       len = x25_negotiate_facilities(skb, sk, &facilities, &dte_facilities);
+       if (len == -1)
                goto out_sock_put;
 
        /*
@@ -907,9 +933,12 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
        makex25->source_addr   = source_addr;
        makex25->neighbour     = nb;
        makex25->facilities    = facilities;
+       makex25->dte_facilities= dte_facilities;
        makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask;
        /* ensure no reverse facil on accept */
        makex25->vc_facil_mask &= ~X25_MASK_REVERSE;
+       /* ensure no calling address extension on accept */
+       makex25->vc_facil_mask &= ~X25_MASK_CALLING_AE;
        makex25->cudmatchlength = x25_sk(sk)->cudmatchlength;
 
        /* Normally all calls are accepted immediatly */
@@ -1316,6 +1345,36 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        break;
                }
 
+               case SIOCX25GDTEFACILITIES: {
+                       rc = copy_to_user(argp, &x25->dte_facilities,
+                                               sizeof(x25->dte_facilities));
+                       if (rc)
+                               rc = -EFAULT;
+                       break;
+               }
+
+               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 &&
+                                       sk->sk_state != TCP_CLOSE)
+                               break;
+                       if (dtefacs.calling_len > X25_MAX_AE_LEN)
+                               break;
+                       if (dtefacs.calling_ae == NULL)
+                               break;
+                       if (dtefacs.called_len > X25_MAX_AE_LEN)
+                               break;
+                       if (dtefacs.called_ae == NULL)
+                               break;
+                       x25->dte_facilities = dtefacs;
+                       rc = 0;
+                       break;
+               }
+
                case SIOCX25GCALLUSERDATA: {
                        struct x25_calluserdata cud = x25->calluserdata;
                        rc = copy_to_user(argp, &cud,
@@ -1492,6 +1551,8 @@ static int compat_x25_ioctl(struct socket *sock, unsigned int cmd,
                break;
        case SIOCX25GFACILITIES:
        case SIOCX25SFACILITIES:
+       case SIOCX25GDTEFACILITIES:
+       case SIOCX25SDTEFACILITIES:
        case SIOCX25GCALLUSERDATA:
        case SIOCX25SCALLUSERDATA:
        case SIOCX25GCAUSEDIAG:
@@ -1556,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)