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