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