linux/net/x25/x25_facilities.c
<<
>>
Prefs
   1/*
   2 *      X.25 Packet Layer release 002
   3 *
   4 *      This is ALPHA test software. This code may break your machine,
   5 *      randomly fail to work with new releases, misbehave and/or generally
   6 *      screw up. It might even work.
   7 *
   8 *      This code REQUIRES 2.1.15 or higher
   9 *
  10 *      This module:
  11 *              This module is free software; you can redistribute it and/or
  12 *              modify it under the terms of the GNU General Public License
  13 *              as published by the Free Software Foundation; either version
  14 *              2 of the License, or (at your option) any later version.
  15 *
  16 *      History
  17 *      X.25 001        Split from x25_subr.c
  18 *      mar/20/00       Daniela Squassoni Disabling/enabling of facilities
  19 *                                        negotiation.
  20 *      apr/14/05       Shaun Pereira - Allow fast select with no restriction
  21 *                                      on response.
  22 */
  23
  24#include <linux/kernel.h>
  25#include <linux/string.h>
  26#include <linux/skbuff.h>
  27#include <net/sock.h>
  28#include <net/x25.h>
  29
  30/**
  31 * x25_parse_facilities - Parse facilities from skb into the facilities structs
  32 *
  33 * @skb: sk_buff to parse
  34 * @facilities: Regular facilities, updated as facilities are found
  35 * @dte_facs: ITU DTE facilities, updated as DTE facilities are found
  36 * @vc_fac_mask: mask is updated with all facilities found
  37 *
  38 * Return codes:
  39 *  -1 - Parsing error, caller should drop call and clean up
  40 *   0 - Parse OK, this skb has no facilities
  41 *  >0 - Parse OK, returns the length of the facilities header
  42 *
  43 */
  44int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
  45                struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask)
  46{
  47        unsigned char *p;
  48        unsigned int len;
  49
  50        *vc_fac_mask = 0;
  51
  52        /*
  53         * The kernel knows which facilities were set on an incoming call but
  54         * currently this information is not available to userspace.  Here we
  55         * give userspace who read incoming call facilities 0 length to indicate
  56         * it wasn't set.
  57         */
  58        dte_facs->calling_len = 0;
  59        dte_facs->called_len = 0;
  60        memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae));
  61        memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae));
  62
  63        if (!pskb_may_pull(skb, 1))
  64                return 0;
  65
  66        len = skb->data[0];
  67
  68        if (!pskb_may_pull(skb, 1 + len))
  69                return -1;
  70
  71        p = skb->data + 1;
  72
  73        while (len > 0) {
  74                switch (*p & X25_FAC_CLASS_MASK) {
  75                case X25_FAC_CLASS_A:
  76                        if (len < 2)
  77                                return -1;
  78                        switch (*p) {
  79                        case X25_FAC_REVERSE:
  80                                if((p[1] & 0x81) == 0x81) {
  81                                        facilities->reverse = p[1] & 0x81;
  82                                        *vc_fac_mask |= X25_MASK_REVERSE;
  83                                        break;
  84                                }
  85
  86                                if((p[1] & 0x01) == 0x01) {
  87                                        facilities->reverse = p[1] & 0x01;
  88                                        *vc_fac_mask |= X25_MASK_REVERSE;
  89                                        break;
  90                                }
  91
  92                                if((p[1] & 0x80) == 0x80) {
  93                                        facilities->reverse = p[1] & 0x80;
  94                                        *vc_fac_mask |= X25_MASK_REVERSE;
  95                                        break;
  96                                }
  97
  98                                if(p[1] == 0x00) {
  99                                        facilities->reverse
 100                                                = X25_DEFAULT_REVERSE;
 101                                        *vc_fac_mask |= X25_MASK_REVERSE;
 102                                        break;
 103                                }
 104
 105                        case X25_FAC_THROUGHPUT:
 106                                facilities->throughput = p[1];
 107                                *vc_fac_mask |= X25_MASK_THROUGHPUT;
 108                                break;
 109                        case X25_MARKER:
 110                                break;
 111                        default:
 112                                printk(KERN_DEBUG "X.25: unknown facility "
 113                                       "%02X, value %02X\n",
 114                                       p[0], p[1]);
 115                                break;
 116                        }
 117                        p   += 2;
 118                        len -= 2;
 119                        break;
 120                case X25_FAC_CLASS_B:
 121                        if (len < 3)
 122                                return -1;
 123                        switch (*p) {
 124                        case X25_FAC_PACKET_SIZE:
 125                                facilities->pacsize_in  = p[1];
 126                                facilities->pacsize_out = p[2];
 127                                *vc_fac_mask |= X25_MASK_PACKET_SIZE;
 128                                break;
 129                        case X25_FAC_WINDOW_SIZE:
 130                                facilities->winsize_in  = p[1];
 131                                facilities->winsize_out = p[2];
 132                                *vc_fac_mask |= X25_MASK_WINDOW_SIZE;
 133                                break;
 134                        default:
 135                                printk(KERN_DEBUG "X.25: unknown facility "
 136                                       "%02X, values %02X, %02X\n",
 137                                       p[0], p[1], p[2]);
 138                                break;
 139                        }
 140                        p   += 3;
 141                        len -= 3;
 142                        break;
 143                case X25_FAC_CLASS_C:
 144                        if (len < 4)
 145                                return -1;
 146                        printk(KERN_DEBUG "X.25: unknown facility %02X, "
 147                               "values %02X, %02X, %02X\n",
 148                               p[0], p[1], p[2], p[3]);
 149                        p   += 4;
 150                        len -= 4;
 151                        break;
 152                case X25_FAC_CLASS_D:
 153                        if (len < p[1] + 2)
 154                                return -1;
 155                        switch (*p) {
 156                        case X25_FAC_CALLING_AE:
 157                                if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
 158                                        return -1;
 159                                dte_facs->calling_len = p[2];
 160                                memcpy(dte_facs->calling_ae, &p[3], p[1] - 1);
 161                                *vc_fac_mask |= X25_MASK_CALLING_AE;
 162                                break;
 163                        case X25_FAC_CALLED_AE:
 164                                if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
 165                                        return -1;
 166                                dte_facs->called_len = p[2];
 167                                memcpy(dte_facs->called_ae, &p[3], p[1] - 1);
 168                                *vc_fac_mask |= X25_MASK_CALLED_AE;
 169                                break;
 170                        default:
 171                                printk(KERN_DEBUG "X.25: unknown facility %02X,"
 172                                        "length %d\n", p[0], p[1]);
 173                                break;
 174                        }
 175                        len -= p[1] + 2;
 176                        p += p[1] + 2;
 177                        break;
 178                }
 179        }
 180
 181        return p - skb->data;
 182}
 183
 184/*
 185 *      Create a set of facilities.
 186 */
 187int x25_create_facilities(unsigned char *buffer,
 188                struct x25_facilities *facilities,
 189                struct x25_dte_facilities *dte_facs, unsigned long facil_mask)
 190{
 191        unsigned char *p = buffer + 1;
 192        int len;
 193
 194        if (!facil_mask) {
 195                /*
 196                 * Length of the facilities field in call_req or
 197                 * call_accept packets
 198                 */
 199                buffer[0] = 0;
 200                len = 1; /* 1 byte for the length field */
 201                return len;
 202        }
 203
 204        if (facilities->reverse && (facil_mask & X25_MASK_REVERSE)) {
 205                *p++ = X25_FAC_REVERSE;
 206                *p++ = facilities->reverse;
 207        }
 208
 209        if (facilities->throughput && (facil_mask & X25_MASK_THROUGHPUT)) {
 210                *p++ = X25_FAC_THROUGHPUT;
 211                *p++ = facilities->throughput;
 212        }
 213
 214        if ((facilities->pacsize_in || facilities->pacsize_out) &&
 215            (facil_mask & X25_MASK_PACKET_SIZE)) {
 216                *p++ = X25_FAC_PACKET_SIZE;
 217                *p++ = facilities->pacsize_in ? : facilities->pacsize_out;
 218                *p++ = facilities->pacsize_out ? : facilities->pacsize_in;
 219        }
 220
 221        if ((facilities->winsize_in || facilities->winsize_out) &&
 222            (facil_mask & X25_MASK_WINDOW_SIZE)) {
 223                *p++ = X25_FAC_WINDOW_SIZE;
 224                *p++ = facilities->winsize_in ? : facilities->winsize_out;
 225                *p++ = facilities->winsize_out ? : facilities->winsize_in;
 226        }
 227
 228        if (facil_mask & (X25_MASK_CALLING_AE|X25_MASK_CALLED_AE)) {
 229                *p++ = X25_MARKER;
 230                *p++ = X25_DTE_SERVICES;
 231        }
 232
 233        if (dte_facs->calling_len && (facil_mask & X25_MASK_CALLING_AE)) {
 234                unsigned int bytecount = (dte_facs->calling_len + 1) >> 1;
 235                *p++ = X25_FAC_CALLING_AE;
 236                *p++ = 1 + bytecount;
 237                *p++ = dte_facs->calling_len;
 238                memcpy(p, dte_facs->calling_ae, bytecount);
 239                p += bytecount;
 240        }
 241
 242        if (dte_facs->called_len && (facil_mask & X25_MASK_CALLED_AE)) {
 243                unsigned int bytecount = (dte_facs->called_len % 2) ?
 244                dte_facs->called_len / 2 + 1 :
 245                dte_facs->called_len / 2;
 246                *p++ = X25_FAC_CALLED_AE;
 247                *p++ = 1 + bytecount;
 248                *p++ = dte_facs->called_len;
 249                memcpy(p, dte_facs->called_ae, bytecount);
 250                p+=bytecount;
 251        }
 252
 253        len       = p - buffer;
 254        buffer[0] = len - 1;
 255
 256        return len;
 257}
 258
 259/*
 260 *      Try to reach a compromise on a set of facilities.
 261 *
 262 *      The only real problem is with reverse charging.
 263 */
 264int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
 265                struct x25_facilities *new, struct x25_dte_facilities *dte)
 266{
 267        struct x25_sock *x25 = x25_sk(sk);
 268        struct x25_facilities *ours = &x25->facilities;
 269        struct x25_facilities theirs;
 270        int len;
 271
 272        memset(&theirs, 0, sizeof(theirs));
 273        memcpy(new, ours, sizeof(*new));
 274
 275        len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask);
 276        if (len < 0)
 277                return len;
 278
 279        /*
 280         *      They want reverse charging, we won't accept it.
 281         */
 282        if ((theirs.reverse & 0x01 ) && (ours->reverse & 0x01)) {
 283                SOCK_DEBUG(sk, "X.25: rejecting reverse charging request\n");
 284                return -1;
 285        }
 286
 287        new->reverse = theirs.reverse;
 288
 289        if (theirs.throughput) {
 290                int theirs_in =  theirs.throughput & 0x0f;
 291                int theirs_out = theirs.throughput & 0xf0;
 292                int ours_in  = ours->throughput & 0x0f;
 293                int ours_out = ours->throughput & 0xf0;
 294                if (!ours_in || theirs_in < ours_in) {
 295                        SOCK_DEBUG(sk, "X.25: inbound throughput negotiated\n");
 296                        new->throughput = (new->throughput & 0xf0) | theirs_in;
 297                }
 298                if (!ours_out || theirs_out < ours_out) {
 299                        SOCK_DEBUG(sk,
 300                                "X.25: outbound throughput negotiated\n");
 301                        new->throughput = (new->throughput & 0x0f) | theirs_out;
 302                }
 303        }
 304
 305        if (theirs.pacsize_in && theirs.pacsize_out) {
 306                if (theirs.pacsize_in < ours->pacsize_in) {
 307                        SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down\n");
 308                        new->pacsize_in = theirs.pacsize_in;
 309                }
 310                if (theirs.pacsize_out < ours->pacsize_out) {
 311                        SOCK_DEBUG(sk, "X.25: packet size outwards negotiated down\n");
 312                        new->pacsize_out = theirs.pacsize_out;
 313                }
 314        }
 315
 316        if (theirs.winsize_in && theirs.winsize_out) {
 317                if (theirs.winsize_in < ours->winsize_in) {
 318                        SOCK_DEBUG(sk, "X.25: window size inwards negotiated down\n");
 319                        new->winsize_in = theirs.winsize_in;
 320                }
 321                if (theirs.winsize_out < ours->winsize_out) {
 322                        SOCK_DEBUG(sk, "X.25: window size outwards negotiated down\n");
 323                        new->winsize_out = theirs.winsize_out;
 324                }
 325        }
 326
 327        return len;
 328}
 329
 330/*
 331 *      Limit values of certain facilities according to the capability of the
 332 *      currently attached x25 link.
 333 */
 334void x25_limit_facilities(struct x25_facilities *facilities,
 335                          struct x25_neigh *nb)
 336{
 337
 338        if (!nb->extended) {
 339                if (facilities->winsize_in  > 7) {
 340                        printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n");
 341                        facilities->winsize_in = 7;
 342                }
 343                if (facilities->winsize_out > 7) {
 344                        facilities->winsize_out = 7;
 345                        printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n");
 346                }
 347        }
 348}
 349
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.