linux/net/irda/irlan/irlan_client.c
<<
>>
Prefs
   1/*********************************************************************
   2 *
   3 * Filename:      irlan_client.c
   4 * Version:       0.9
   5 * Description:   IrDA LAN Access Protocol (IrLAN) Client
   6 * Status:        Experimental.
   7 * Author:        Dag Brattli <dagb@cs.uit.no>
   8 * Created at:    Sun Aug 31 20:14:37 1997
   9 * Modified at:   Tue Dec 14 15:47:02 1999
  10 * Modified by:   Dag Brattli <dagb@cs.uit.no>
  11 * Sources:       skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
  12 *                slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
  13 *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  14 *
  15 *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
  16 *     All Rights Reserved.
  17 *
  18 *     This program is free software; you can redistribute it and/or
  19 *     modify it under the terms of the GNU General Public License as
  20 *     published by the Free Software Foundation; either version 2 of
  21 *     the License, or (at your option) any later version.
  22 *
  23 *     Neither Dag Brattli nor University of Tromsø admit liability nor
  24 *     provide warranty for any of this software. This material is
  25 *     provided "AS-IS" and at no charge.
  26 *
  27 ********************************************************************/
  28
  29#include <linux/kernel.h>
  30#include <linux/string.h>
  31#include <linux/slab.h>
  32#include <linux/errno.h>
  33#include <linux/init.h>
  34#include <linux/netdevice.h>
  35#include <linux/etherdevice.h>
  36#include <linux/if_arp.h>
  37#include <linux/bitops.h>
  38#include <net/arp.h>
  39
  40#include <asm/system.h>
  41#include <asm/byteorder.h>
  42
  43#include <net/irda/irda.h>
  44#include <net/irda/irttp.h>
  45#include <net/irda/irlmp.h>
  46#include <net/irda/irias_object.h>
  47#include <net/irda/iriap.h>
  48#include <net/irda/timer.h>
  49
  50#include <net/irda/irlan_common.h>
  51#include <net/irda/irlan_event.h>
  52#include <net/irda/irlan_eth.h>
  53#include <net/irda/irlan_provider.h>
  54#include <net/irda/irlan_client.h>
  55
  56#undef CONFIG_IRLAN_GRATUITOUS_ARP
  57
  58static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap,
  59                                                    LM_REASON reason,
  60                                                    struct sk_buff *);
  61static int irlan_client_ctrl_data_indication(void *instance, void *sap,
  62                                             struct sk_buff *skb);
  63static void irlan_client_ctrl_connect_confirm(void *instance, void *sap,
  64                                              struct qos_info *qos,
  65                                              __u32 max_sdu_size,
  66                                              __u8 max_header_size,
  67                                              struct sk_buff *);
  68static void irlan_check_response_param(struct irlan_cb *self, char *param,
  69                                       char *value, int val_len);
  70static void irlan_client_open_ctrl_tsap(struct irlan_cb *self);
  71
  72static void irlan_client_kick_timer_expired(void *data)
  73{
  74        struct irlan_cb *self = (struct irlan_cb *) data;
  75
  76        IRDA_DEBUG(2, "%s()\n", __func__ );
  77
  78        IRDA_ASSERT(self != NULL, return;);
  79        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
  80
  81        /*
  82         * If we are in peer mode, the client may not have got the discovery
  83         * indication it needs to make progress. If the client is still in
  84         * IDLE state, we must kick it to, but only if the provider is not IDLE
  85         */
  86        if ((self->provider.access_type == ACCESS_PEER) &&
  87            (self->client.state == IRLAN_IDLE) &&
  88            (self->provider.state != IRLAN_IDLE)) {
  89                irlan_client_wakeup(self, self->saddr, self->daddr);
  90        }
  91}
  92
  93static void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout)
  94{
  95        IRDA_DEBUG(4, "%s()\n", __func__ );
  96
  97        irda_start_timer(&self->client.kick_timer, timeout, (void *) self,
  98                         irlan_client_kick_timer_expired);
  99}
 100
 101/*
 102 * Function irlan_client_wakeup (self, saddr, daddr)
 103 *
 104 *    Wake up client
 105 *
 106 */
 107void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
 108{
 109        IRDA_DEBUG(1, "%s()\n", __func__ );
 110
 111        IRDA_ASSERT(self != NULL, return;);
 112        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 113
 114        /*
 115         * Check if we are already awake, or if we are a provider in direct
 116         * mode (in that case we must leave the client idle
 117         */
 118        if ((self->client.state != IRLAN_IDLE) ||
 119            (self->provider.access_type == ACCESS_DIRECT))
 120        {
 121                        IRDA_DEBUG(0, "%s(), already awake!\n", __func__ );
 122                        return;
 123        }
 124
 125        /* Addresses may have changed! */
 126        self->saddr = saddr;
 127        self->daddr = daddr;
 128
 129        if (self->disconnect_reason == LM_USER_REQUEST) {
 130                        IRDA_DEBUG(0, "%s(), still stopped by user\n", __func__ );
 131                        return;
 132        }
 133
 134        /* Open TSAPs */
 135        irlan_client_open_ctrl_tsap(self);
 136        irlan_open_data_tsap(self);
 137
 138        irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL);
 139
 140        /* Start kick timer */
 141        irlan_client_start_kick_timer(self, 2*HZ);
 142}
 143
 144/*
 145 * Function irlan_discovery_indication (daddr)
 146 *
 147 *    Remote device with IrLAN server support discovered
 148 *
 149 */
 150void irlan_client_discovery_indication(discinfo_t *discovery,
 151                                       DISCOVERY_MODE mode,
 152                                       void *priv)
 153{
 154        struct irlan_cb *self;
 155        __u32 saddr, daddr;
 156
 157        IRDA_DEBUG(1, "%s()\n", __func__ );
 158
 159        IRDA_ASSERT(discovery != NULL, return;);
 160
 161        /*
 162         * I didn't check it, but I bet that IrLAN suffer from the same
 163         * deficiency as IrComm and doesn't handle two instances
 164         * simultaneously connecting to each other.
 165         * Same workaround, drop passive discoveries.
 166         * Jean II */
 167        if(mode == DISCOVERY_PASSIVE)
 168                return;
 169
 170        saddr = discovery->saddr;
 171        daddr = discovery->daddr;
 172
 173        /* Find instance */
 174        rcu_read_lock();
 175        self = irlan_get_any();
 176        if (self) {
 177                IRDA_ASSERT(self->magic == IRLAN_MAGIC, goto out;);
 178
 179                IRDA_DEBUG(1, "%s(), Found instance (%08x)!\n", __func__ ,
 180                      daddr);
 181
 182                irlan_client_wakeup(self, saddr, daddr);
 183        }
 184IRDA_ASSERT_LABEL(out:)
 185        rcu_read_unlock();
 186}
 187
 188/*
 189 * Function irlan_client_data_indication (handle, skb)
 190 *
 191 *    This function gets the data that is received on the control channel
 192 *
 193 */
 194static int irlan_client_ctrl_data_indication(void *instance, void *sap,
 195                                             struct sk_buff *skb)
 196{
 197        struct irlan_cb *self;
 198
 199        IRDA_DEBUG(2, "%s()\n", __func__ );
 200
 201        self = (struct irlan_cb *) instance;
 202
 203        IRDA_ASSERT(self != NULL, return -1;);
 204        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
 205        IRDA_ASSERT(skb != NULL, return -1;);
 206
 207        irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb);
 208
 209        /* Ready for a new command */
 210        IRDA_DEBUG(2, "%s(), clearing tx_busy\n", __func__ );
 211        self->client.tx_busy = FALSE;
 212
 213        /* Check if we have some queued commands waiting to be sent */
 214        irlan_run_ctrl_tx_queue(self);
 215
 216        return 0;
 217}
 218
 219static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap,
 220                                                    LM_REASON reason,
 221                                                    struct sk_buff *userdata)
 222{
 223        struct irlan_cb *self;
 224        struct tsap_cb *tsap;
 225        struct sk_buff *skb;
 226
 227        IRDA_DEBUG(4, "%s(), reason=%d\n", __func__ , reason);
 228
 229        self = (struct irlan_cb *) instance;
 230        tsap = (struct tsap_cb *) sap;
 231
 232        IRDA_ASSERT(self != NULL, return;);
 233        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 234        IRDA_ASSERT(tsap != NULL, return;);
 235        IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
 236
 237        IRDA_ASSERT(tsap == self->client.tsap_ctrl, return;);
 238
 239        /* Remove frames queued on the control channel */
 240        while ((skb = skb_dequeue(&self->client.txq)) != NULL) {
 241                dev_kfree_skb(skb);
 242        }
 243        self->client.tx_busy = FALSE;
 244
 245        irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
 246}
 247
 248/*
 249 * Function irlan_client_open_tsaps (self)
 250 *
 251 *    Initialize callbacks and open IrTTP TSAPs
 252 *
 253 */
 254static void irlan_client_open_ctrl_tsap(struct irlan_cb *self)
 255{
 256        struct tsap_cb *tsap;
 257        notify_t notify;
 258
 259        IRDA_DEBUG(4, "%s()\n", __func__ );
 260
 261        IRDA_ASSERT(self != NULL, return;);
 262        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 263
 264        /* Check if already open */
 265        if (self->client.tsap_ctrl)
 266                return;
 267
 268        irda_notify_init(&notify);
 269
 270        /* Set up callbacks */
 271        notify.data_indication       = irlan_client_ctrl_data_indication;
 272        notify.connect_confirm       = irlan_client_ctrl_connect_confirm;
 273        notify.disconnect_indication = irlan_client_ctrl_disconnect_indication;
 274        notify.instance = self;
 275        strlcpy(notify.name, "IrLAN ctrl (c)", sizeof(notify.name));
 276
 277        tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, &notify);
 278        if (!tsap) {
 279                IRDA_DEBUG(2, "%s(), Got no tsap!\n", __func__ );
 280                return;
 281        }
 282        self->client.tsap_ctrl = tsap;
 283}
 284
 285/*
 286 * Function irlan_client_connect_confirm (handle, skb)
 287 *
 288 *    Connection to peer IrLAN laye confirmed
 289 *
 290 */
 291static void irlan_client_ctrl_connect_confirm(void *instance, void *sap,
 292                                              struct qos_info *qos,
 293                                              __u32 max_sdu_size,
 294                                              __u8 max_header_size,
 295                                              struct sk_buff *skb)
 296{
 297        struct irlan_cb *self;
 298
 299        IRDA_DEBUG(4, "%s()\n", __func__ );
 300
 301        self = (struct irlan_cb *) instance;
 302
 303        IRDA_ASSERT(self != NULL, return;);
 304        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 305
 306        self->client.max_sdu_size = max_sdu_size;
 307        self->client.max_header_size = max_header_size;
 308
 309        /* TODO: we could set the MTU depending on the max_sdu_size */
 310
 311        irlan_do_client_event(self, IRLAN_CONNECT_COMPLETE, NULL);
 312}
 313
 314/*
 315 * Function print_ret_code (code)
 316 *
 317 *    Print return code of request to peer IrLAN layer.
 318 *
 319 */
 320static void print_ret_code(__u8 code)
 321{
 322        switch(code) {
 323        case 0:
 324                printk(KERN_INFO "Success\n");
 325                break;
 326        case 1:
 327                IRDA_WARNING("IrLAN: Insufficient resources\n");
 328                break;
 329        case 2:
 330                IRDA_WARNING("IrLAN: Invalid command format\n");
 331                break;
 332        case 3:
 333                IRDA_WARNING("IrLAN: Command not supported\n");
 334                break;
 335        case 4:
 336                IRDA_WARNING("IrLAN: Parameter not supported\n");
 337                break;
 338        case 5:
 339                IRDA_WARNING("IrLAN: Value not supported\n");
 340                break;
 341        case 6:
 342                IRDA_WARNING("IrLAN: Not open\n");
 343                break;
 344        case 7:
 345                IRDA_WARNING("IrLAN: Authentication required\n");
 346                break;
 347        case 8:
 348                IRDA_WARNING("IrLAN: Invalid password\n");
 349                break;
 350        case 9:
 351                IRDA_WARNING("IrLAN: Protocol error\n");
 352                break;
 353        case 255:
 354                IRDA_WARNING("IrLAN: Asynchronous status\n");
 355                break;
 356        }
 357}
 358
 359/*
 360 * Function irlan_client_parse_response (self, skb)
 361 *
 362 *    Extract all parameters from received buffer, then feed them to
 363 *    check_params for parsing
 364 */
 365void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb)
 366{
 367        __u8 *frame;
 368        __u8 *ptr;
 369        int count;
 370        int ret;
 371        __u16 val_len;
 372        int i;
 373        char *name;
 374        char *value;
 375
 376        IRDA_ASSERT(skb != NULL, return;);
 377
 378        IRDA_DEBUG(4, "%s() skb->len=%d\n", __func__ , (int) skb->len);
 379
 380        IRDA_ASSERT(self != NULL, return;);
 381        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 382
 383        if (!skb) {
 384                IRDA_ERROR("%s(), Got NULL skb!\n", __func__);
 385                return;
 386        }
 387        frame = skb->data;
 388
 389        /*
 390         *  Check return code and print it if not success
 391         */
 392        if (frame[0]) {
 393                print_ret_code(frame[0]);
 394                return;
 395        }
 396
 397        name = kmalloc(255, GFP_ATOMIC);
 398        if (!name)
 399                return;
 400        value = kmalloc(1016, GFP_ATOMIC);
 401        if (!value) {
 402                kfree(name);
 403                return;
 404        }
 405
 406        /* How many parameters? */
 407        count = frame[1];
 408
 409        IRDA_DEBUG(4, "%s(), got %d parameters\n", __func__ , count);
 410
 411        ptr = frame+2;
 412
 413        /* For all parameters */
 414        for (i=0; i<count;i++) {
 415                ret = irlan_extract_param(ptr, name, value, &val_len);
 416                if (ret < 0) {
 417                        IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __func__ );
 418                        break;
 419                }
 420                ptr += ret;
 421                irlan_check_response_param(self, name, value, val_len);
 422        }
 423        /* Cleanup */
 424        kfree(name);
 425        kfree(value);
 426}
 427
 428/*
 429 * Function irlan_check_response_param (self, param, value, val_len)
 430 *
 431 *     Check which parameter is received and update local variables
 432 *
 433 */
 434static void irlan_check_response_param(struct irlan_cb *self, char *param,
 435                                       char *value, int val_len)
 436{
 437        __u16 tmp_cpu; /* Temporary value in host order */
 438        __u8 *bytes;
 439        int i;
 440
 441        IRDA_DEBUG(4, "%s(), parm=%s\n", __func__ , param);
 442
 443        IRDA_ASSERT(self != NULL, return;);
 444        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 445
 446        /* Media type */
 447        if (strcmp(param, "MEDIA") == 0) {
 448                if (strcmp(value, "802.3") == 0)
 449                        self->media = MEDIA_802_3;
 450                else
 451                        self->media = MEDIA_802_5;
 452                return;
 453        }
 454        if (strcmp(param, "FILTER_TYPE") == 0) {
 455                if (strcmp(value, "DIRECTED") == 0)
 456                        self->client.filter_type |= IRLAN_DIRECTED;
 457                else if (strcmp(value, "FUNCTIONAL") == 0)
 458                        self->client.filter_type |= IRLAN_FUNCTIONAL;
 459                else if (strcmp(value, "GROUP") == 0)
 460                        self->client.filter_type |= IRLAN_GROUP;
 461                else if (strcmp(value, "MAC_FRAME") == 0)
 462                        self->client.filter_type |= IRLAN_MAC_FRAME;
 463                else if (strcmp(value, "MULTICAST") == 0)
 464                        self->client.filter_type |= IRLAN_MULTICAST;
 465                else if (strcmp(value, "BROADCAST") == 0)
 466                        self->client.filter_type |= IRLAN_BROADCAST;
 467                else if (strcmp(value, "IPX_SOCKET") == 0)
 468                        self->client.filter_type |= IRLAN_IPX_SOCKET;
 469
 470        }
 471        if (strcmp(param, "ACCESS_TYPE") == 0) {
 472                if (strcmp(value, "DIRECT") == 0)
 473                        self->client.access_type = ACCESS_DIRECT;
 474                else if (strcmp(value, "PEER") == 0)
 475                        self->client.access_type = ACCESS_PEER;
 476                else if (strcmp(value, "HOSTED") == 0)
 477                        self->client.access_type = ACCESS_HOSTED;
 478                else {
 479                        IRDA_DEBUG(2, "%s(), unknown access type!\n", __func__ );
 480                }
 481        }
 482        /* IRLAN version */
 483        if (strcmp(param, "IRLAN_VER") == 0) {
 484                IRDA_DEBUG(4, "IrLAN version %d.%d\n", (__u8) value[0],
 485                      (__u8) value[1]);
 486
 487                self->version[0] = value[0];
 488                self->version[1] = value[1];
 489                return;
 490        }
 491        /* Which remote TSAP to use for data channel */
 492        if (strcmp(param, "DATA_CHAN") == 0) {
 493                self->dtsap_sel_data = value[0];
 494                IRDA_DEBUG(4, "Data TSAP = %02x\n", self->dtsap_sel_data);
 495                return;
 496        }
 497        if (strcmp(param, "CON_ARB") == 0) {
 498                memcpy(&tmp_cpu, value, 2); /* Align value */
 499                le16_to_cpus(&tmp_cpu);     /* Convert to host order */
 500                self->client.recv_arb_val = tmp_cpu;
 501                IRDA_DEBUG(2, "%s(), receive arb val=%d\n", __func__ ,
 502                           self->client.recv_arb_val);
 503        }
 504        if (strcmp(param, "MAX_FRAME") == 0) {
 505                memcpy(&tmp_cpu, value, 2); /* Align value */
 506                le16_to_cpus(&tmp_cpu);     /* Convert to host order */
 507                self->client.max_frame = tmp_cpu;
 508                IRDA_DEBUG(4, "%s(), max frame=%d\n", __func__ ,
 509                           self->client.max_frame);
 510        }
 511
 512        /* RECONNECT_KEY, in case the link goes down! */
 513        if (strcmp(param, "RECONNECT_KEY") == 0) {
 514                IRDA_DEBUG(4, "Got reconnect key: ");
 515                /* for (i = 0; i < val_len; i++) */
 516/*                      printk("%02x", value[i]); */
 517                memcpy(self->client.reconnect_key, value, val_len);
 518                self->client.key_len = val_len;
 519                IRDA_DEBUG(4, "\n");
 520        }
 521        /* FILTER_ENTRY, have we got an ethernet address? */
 522        if (strcmp(param, "FILTER_ENTRY") == 0) {
 523                bytes = value;
 524                IRDA_DEBUG(4, "Ethernet address = %pM\n", bytes);
 525                for (i = 0; i < 6; i++)
 526                        self->dev->dev_addr[i] = bytes[i];
 527        }
 528}
 529
 530/*
 531 * Function irlan_client_get_value_confirm (obj_id, value)
 532 *
 533 *    Got results from remote LM-IAS
 534 *
 535 */
 536void irlan_client_get_value_confirm(int result, __u16 obj_id,
 537                                    struct ias_value *value, void *priv)
 538{
 539        struct irlan_cb *self;
 540
 541        IRDA_DEBUG(4, "%s()\n", __func__ );
 542
 543        IRDA_ASSERT(priv != NULL, return;);
 544
 545        self = (struct irlan_cb *) priv;
 546        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 547
 548        /* We probably don't need to make any more queries */
 549        iriap_close(self->client.iriap);
 550        self->client.iriap = NULL;
 551
 552        /* Check if request succeeded */
 553        if (result != IAS_SUCCESS) {
 554                IRDA_DEBUG(2, "%s(), got NULL value!\n", __func__ );
 555                irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL,
 556                                      NULL);
 557                return;
 558        }
 559
 560        switch (value->type) {
 561        case IAS_INTEGER:
 562                self->dtsap_sel_ctrl = value->t.integer;
 563
 564                if (value->t.integer != -1) {
 565                        irlan_do_client_event(self, IRLAN_IAS_PROVIDER_AVAIL,
 566                                              NULL);
 567                        return;
 568                }
 569                irias_delete_value(value);
 570                break;
 571        default:
 572                IRDA_DEBUG(2, "%s(), unknown type!\n", __func__ );
 573                break;
 574        }
 575        irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL);
 576}
 577