Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-drm-fsl-dcu.git] / net / x25 / x25_facilities.c
index 54278b962f4ce1403d89e560196065811b7fc369..dec404afa11333830ac69330ce2d6ef4a7fa357a 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
  *
@@ -15,7 +15,7 @@
  *
  *     History
  *     X.25 001        Split from x25_subr.c
- *     mar/20/00       Daniela Squassoni Disabling/enabling of facilities 
+ *     mar/20/00       Daniela Squassoni Disabling/enabling of facilities
  *                                       negotiation.
  *     apr/14/05       Shaun Pereira - Allow fast select with no restriction
  *                                     on response.
 #include <net/x25.h>
 
 /*
- *     Parse a set of facilities into the facilities structure. Unrecognised
+ * Parse a set of facilities into the facilities structures. Unrecognised
  *     facilities are written to the debug log file.
  */
-int x25_parse_facilities(struct sk_buff *skb,
-                        struct x25_facilities *facilities,
-                        unsigned long *vc_fac_mask)
+int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
+               struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask)
 {
        unsigned char *p = skb->data;
        unsigned int len = *p++;
 
        *vc_fac_mask = 0;
 
+       /*
+        * The kernel knows which facilities were set on an incoming call but
+        * currently this information is not available to userspace.  Here we
+        * give userspace who read incoming call facilities 0 length to indicate
+        * it wasn't set.
+        */
+       dte_facs->calling_len = 0;
+       dte_facs->called_len = 0;
+       memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae));
+       memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae));
+
        while (len > 0) {
                switch (*p & X25_FAC_CLASS_MASK) {
                case X25_FAC_CLASS_A:
@@ -74,6 +84,8 @@ int x25_parse_facilities(struct sk_buff *skb,
                                facilities->throughput = p[1];
                                *vc_fac_mask |= X25_MASK_THROUGHPUT;
                                break;
+                       case X25_MARKER:
+                               break;
                        default:
                                printk(KERN_DEBUG "X.25: unknown facility "
                                       "%02X, value %02X\n",
@@ -112,11 +124,30 @@ int x25_parse_facilities(struct sk_buff *skb,
                        len -= 4;
                        break;
                case X25_FAC_CLASS_D:
-                       printk(KERN_DEBUG "X.25: unknown facility %02X, "
-                              "length %d, values %02X, %02X, %02X, %02X\n",
-                              p[0], p[1], p[2], p[3], p[4], p[5]);
+                       switch (*p) {
+                       case X25_FAC_CALLING_AE:
+                               if (p[1] > X25_MAX_DTE_FACIL_LEN)
+                                       break;
+                               dte_facs->calling_len = p[2];
+                               memcpy(dte_facs->calling_ae, &p[3], p[1] - 1);
+                               *vc_fac_mask |= X25_MASK_CALLING_AE;
+                               break;
+                       case X25_FAC_CALLED_AE:
+                               if (p[1] > X25_MAX_DTE_FACIL_LEN)
+                                       break;
+                               dte_facs->called_len = p[2];
+                               memcpy(dte_facs->called_ae, &p[3], p[1] - 1);
+                               *vc_fac_mask |= X25_MASK_CALLED_AE;
+                               break;
+                       default:
+                               printk(KERN_DEBUG "X.25: unknown facility %02X,"
+                                       "length %d, values %02X, %02X, "
+                                       "%02X, %02X\n",
+                                       p[0], p[1], p[2], p[3], p[4], p[5]);
+                               break;
+                       }
                        len -= p[1] + 2;
-                       p   += p[1] + 2;
+                       p += p[1] + 2;
                        break;
                }
        }
@@ -128,8 +159,8 @@ int x25_parse_facilities(struct sk_buff *skb,
  *     Create a set of facilities.
  */
 int x25_create_facilities(unsigned char *buffer,
-                         struct x25_facilities *facilities,
-                         unsigned long facil_mask)
+               struct x25_facilities *facilities,
+               struct x25_dte_facilities *dte_facs, unsigned long facil_mask)
 {
        unsigned char *p = buffer + 1;
        int len;
@@ -168,6 +199,33 @@ int x25_create_facilities(unsigned char *buffer,
                *p++ = facilities->winsize_out ? : facilities->winsize_in;
        }
 
+       if (facil_mask & (X25_MASK_CALLING_AE|X25_MASK_CALLED_AE)) {
+               *p++ = X25_MARKER;
+               *p++ = X25_DTE_SERVICES;
+       }
+
+       if (dte_facs->calling_len && (facil_mask & X25_MASK_CALLING_AE)) {
+               unsigned bytecount = (dte_facs->calling_len % 2) ?
+                                       dte_facs->calling_len / 2 + 1 :
+                                       dte_facs->calling_len / 2;
+               *p++ = X25_FAC_CALLING_AE;
+               *p++ = 1 + bytecount;
+               *p++ = dte_facs->calling_len;
+               memcpy(p, dte_facs->calling_ae, bytecount);
+               p += bytecount;
+       }
+
+       if (dte_facs->called_len && (facil_mask & X25_MASK_CALLED_AE)) {
+               unsigned bytecount = (dte_facs->called_len % 2) ?
+               dte_facs->called_len / 2 + 1 :
+               dte_facs->called_len / 2;
+               *p++ = X25_FAC_CALLED_AE;
+               *p++ = 1 + bytecount;
+               *p++ = dte_facs->called_len;
+               memcpy(p, dte_facs->called_ae, bytecount);
+               p+=bytecount;
+       }
+
        len       = p - buffer;
        buffer[0] = len - 1;
 
@@ -180,7 +238,7 @@ int x25_create_facilities(unsigned char *buffer,
  *     The only real problem is with reverse charging.
  */
 int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
-                            struct x25_facilities *new)
+               struct x25_facilities *new, struct x25_dte_facilities *dte)
 {
        struct x25_sock *x25 = x25_sk(sk);
        struct x25_facilities *ours = &x25->facilities;
@@ -190,13 +248,13 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
        memset(&theirs, 0, sizeof(theirs));
        memcpy(new, ours, sizeof(*new));
 
-       len = x25_parse_facilities(skb, &theirs, &x25->vc_facil_mask);
+       len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask);
 
        /*
         *      They want reverse charging, we won't accept it.
         */
        if ((theirs.reverse & 0x01 ) && (ours->reverse & 0x01)) {
-               SOCK_DEBUG(sk, "X.25: rejecting reverse charging request");
+               SOCK_DEBUG(sk, "X.25: rejecting reverse charging request\n");
                return -1;
        }
 
@@ -204,29 +262,29 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
 
        if (theirs.throughput) {
                if (theirs.throughput < ours->throughput) {
-                       SOCK_DEBUG(sk, "X.25: throughput negotiated down");
+                       SOCK_DEBUG(sk, "X.25: throughput negotiated down\n");
                        new->throughput = theirs.throughput;
                }
        }
 
        if (theirs.pacsize_in && theirs.pacsize_out) {
                if (theirs.pacsize_in < ours->pacsize_in) {
-                       SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down");
+                       SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down\n");
                        new->pacsize_in = theirs.pacsize_in;
                }
                if (theirs.pacsize_out < ours->pacsize_out) {
-                       SOCK_DEBUG(sk, "X.25: packet size outwards negotiated down");
+                       SOCK_DEBUG(sk, "X.25: packet size outwards negotiated down\n");
                        new->pacsize_out = theirs.pacsize_out;
                }
        }
 
        if (theirs.winsize_in && theirs.winsize_out) {
                if (theirs.winsize_in < ours->winsize_in) {
-                       SOCK_DEBUG(sk, "X.25: window size inwards negotiated down");
+                       SOCK_DEBUG(sk, "X.25: window size inwards negotiated down\n");
                        new->winsize_in = theirs.winsize_in;
                }
                if (theirs.winsize_out < ours->winsize_out) {
-                       SOCK_DEBUG(sk, "X.25: window size outwards negotiated down");
+                       SOCK_DEBUG(sk, "X.25: window size outwards negotiated down\n");
                        new->winsize_out = theirs.winsize_out;
                }
        }
@@ -235,7 +293,7 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
 }
 
 /*
- *     Limit values of certain facilities according to the capability of the 
+ *     Limit values of certain facilities according to the capability of the
  *      currently attached x25 link.
  */
 void x25_limit_facilities(struct x25_facilities *facilities,