mac80211 & nl80211: add support to abort a scan request on tx
[linux-2.6.git] / net / x25 / x25_subr.c
index 183fea3..5170d52 100644 (file)
  *     mar/20/00       Daniela Squassoni Disabling/enabling of facilities
  *                                       negotiation.
  *     jun/24/01       Arnaldo C. Melo   use skb_queue_purge, cleanups
+ *     apr/04/15       Shaun Pereira           Fast select with no
+ *                                             restriction on response.
  */
 
+#include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
-#include <net/tcp.h>
+#include <net/tcp_states.h>
 #include <net/x25.h>
 
 /*
@@ -78,7 +81,7 @@ void x25_requeue_frames(struct sock *sk)
                if (!skb_prev)
                        skb_queue_head(&sk->sk_write_queue, skb);
                else
-                       skb_append(skb_prev, skb);
+                       skb_append(skb_prev, skb, &sk->sk_write_queue);
                skb_prev = skb;
        }
 }
@@ -123,28 +126,30 @@ void x25_write_internal(struct sock *sk, int frametype)
         *      Adjust frame size.
         */
        switch (frametype) {
-               case X25_CALL_REQUEST:
-                       len += 1 + X25_ADDR_LEN + X25_MAX_FAC_LEN +
-                              X25_MAX_CUD_LEN;
-                       break;
-               case X25_CALL_ACCEPTED:
+       case X25_CALL_REQUEST:
+               len += 1 + X25_ADDR_LEN + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN;
+               break;
+       case X25_CALL_ACCEPTED: /* fast sel with no restr on resp */
+               if (x25->facilities.reverse & 0x80) {
                        len += 1 + X25_MAX_FAC_LEN + X25_MAX_CUD_LEN;
-                       break;
-               case X25_CLEAR_REQUEST:
-               case X25_RESET_REQUEST:
-                       len += 2;
-                       break;
-               case X25_RR:
-               case X25_RNR:
-               case X25_REJ:
-               case X25_CLEAR_CONFIRMATION:
-               case X25_INTERRUPT_CONFIRMATION:
-               case X25_RESET_CONFIRMATION:
-                       break;
-               default:
-                       printk(KERN_ERR "X.25: invalid frame type %02X\n",
-                              frametype);
-                       return;
+               } else {
+                       len += 1 + X25_MAX_FAC_LEN;
+               }
+               break;
+       case X25_CLEAR_REQUEST:
+       case X25_RESET_REQUEST:
+               len += 2;
+               break;
+       case X25_RR:
+       case X25_RNR:
+       case X25_REJ:
+       case X25_CLEAR_CONFIRMATION:
+       case X25_INTERRUPT_CONFIRMATION:
+       case X25_RESET_CONFIRMATION:
+               break;
+       default:
+               printk(KERN_ERR "X.25: invalid frame type %02X\n", frametype);
+               return;
        }
 
        if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
@@ -184,8 +189,9 @@ void x25_write_internal(struct sock *sk, int frametype)
                        dptr    = skb_put(skb, len);
                        memcpy(dptr, addresses, len);
                        len     = x25_create_facilities(facilities,
-                                                       &x25->facilities,
-                                            x25->neighbour->global_facil_mask);
+                                       &x25->facilities,
+                                       &x25->dte_facilities,
+                                       x25->neighbour->global_facil_mask);
                        dptr    = skb_put(skb, len);
                        memcpy(dptr, facilities, len);
                        dptr = skb_put(skb, x25->calluserdata.cudlength);
@@ -200,16 +206,30 @@ void x25_write_internal(struct sock *sk, int frametype)
                        *dptr++ = 0x00;         /* Address lengths */
                        len     = x25_create_facilities(facilities,
                                                        &x25->facilities,
+                                                       &x25->dte_facilities,
                                                        x25->vc_facil_mask);
                        dptr    = skb_put(skb, len);
                        memcpy(dptr, facilities, len);
-                       dptr = skb_put(skb, x25->calluserdata.cudlength);
-                       memcpy(dptr, x25->calluserdata.cuddata,
-                              x25->calluserdata.cudlength);
+
+                       /* fast select with no restriction on response
+                               allows call user data. Userland must
+                               ensure it is ours and not theirs */
+                       if(x25->facilities.reverse & 0x80) {
+                               dptr = skb_put(skb,
+                                       x25->calluserdata.cudlength);
+                               memcpy(dptr, x25->calluserdata.cuddata,
+                                      x25->calluserdata.cudlength);
+                       }
                        x25->calluserdata.cudlength = 0;
                        break;
 
                case X25_CLEAR_REQUEST:
+                       dptr    = skb_put(skb, 3);
+                       *dptr++ = frametype;
+                       *dptr++ = x25->causediag.cause;
+                       *dptr++ = x25->causediag.diagnostic;
+                       break;
+
                case X25_RESET_REQUEST:
                        dptr    = skb_put(skb, 3);
                        *dptr++ = frametype;
@@ -249,31 +269,39 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
               int *d, int *m)
 {
        struct x25_sock *x25 = x25_sk(sk);
-       unsigned char *frame = skb->data;
+       unsigned char *frame;
+
+       if (!pskb_may_pull(skb, X25_STD_MIN_LEN))
+               return X25_ILLEGAL;
+       frame = skb->data;
 
        *ns = *nr = *q = *d = *m = 0;
 
        switch (frame[2]) {
-               case X25_CALL_REQUEST:
-               case X25_CALL_ACCEPTED:
-               case X25_CLEAR_REQUEST:
-               case X25_CLEAR_CONFIRMATION:
-               case X25_INTERRUPT:
-               case X25_INTERRUPT_CONFIRMATION:
-               case X25_RESET_REQUEST:
-               case X25_RESET_CONFIRMATION:
-               case X25_RESTART_REQUEST:
-               case X25_RESTART_CONFIRMATION:
-               case X25_REGISTRATION_REQUEST:
-               case X25_REGISTRATION_CONFIRMATION:
-               case X25_DIAGNOSTIC:
-                       return frame[2];
+       case X25_CALL_REQUEST:
+       case X25_CALL_ACCEPTED:
+       case X25_CLEAR_REQUEST:
+       case X25_CLEAR_CONFIRMATION:
+       case X25_INTERRUPT:
+       case X25_INTERRUPT_CONFIRMATION:
+       case X25_RESET_REQUEST:
+       case X25_RESET_CONFIRMATION:
+       case X25_RESTART_REQUEST:
+       case X25_RESTART_CONFIRMATION:
+       case X25_REGISTRATION_REQUEST:
+       case X25_REGISTRATION_CONFIRMATION:
+       case X25_DIAGNOSTIC:
+               return frame[2];
        }
 
        if (x25->neighbour->extended) {
                if (frame[2] == X25_RR  ||
                    frame[2] == X25_RNR ||
                    frame[2] == X25_REJ) {
+                       if (!pskb_may_pull(skb, X25_EXT_MIN_LEN))
+                               return X25_ILLEGAL;
+                       frame = skb->data;
+
                        *nr = (frame[3] >> 1) & 0x7F;
                        return frame[2];
                }
@@ -288,6 +316,10 @@ int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
 
        if (x25->neighbour->extended) {
                if ((frame[2] & 0x01) == X25_DATA) {
+                       if (!pskb_may_pull(skb, X25_EXT_MIN_LEN))
+                               return X25_ILLEGAL;
+                       frame = skb->data;
+
                        *q  = (frame[0] & X25_Q_BIT) == X25_Q_BIT;
                        *d  = (frame[0] & X25_D_BIT) == X25_D_BIT;
                        *m  = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT;
@@ -344,7 +376,7 @@ void x25_check_rbuf(struct sock *sk)
 {
        struct x25_sock *x25 = x25_sk(sk);
 
-       if (atomic_read(&sk->sk_rmem_alloc) < (sk->sk_rcvbuf / 2) &&
+       if (atomic_read(&sk->sk_rmem_alloc) < (sk->sk_rcvbuf >> 1) &&
            (x25->condition & X25_COND_OWN_RX_BUSY)) {
                x25->condition &= ~X25_COND_OWN_RX_BUSY;
                x25->condition &= ~X25_COND_ACK_PENDING;
@@ -354,21 +386,3 @@ void x25_check_rbuf(struct sock *sk)
        }
 }
 
-/*
- * Compare 2 calluserdata structures, used to find correct listening sockets
- * when call user data is used.
- */
-int x25_check_calluserdata(struct x25_calluserdata *ours, struct x25_calluserdata *theirs)
-{
-       int i;
-       if (ours->cudlength != theirs->cudlength)
-               return 0;
-
-       for (i=0;i<ours->cudlength;i++) {
-               if (ours->cuddata[i] != theirs->cuddata[i]) {
-                       return 0;
-               }
-       }
-       return 1;
-}
-