linux/net/irda/iriap.c
<<
>>
Prefs
   1/*********************************************************************
   2 *
   3 * Filename:      iriap.c
   4 * Version:       0.8
   5 * Description:   Information Access Protocol (IAP)
   6 * Status:        Experimental.
   7 * Author:        Dag Brattli <dagb@cs.uit.no>
   8 * Created at:    Thu Aug 21 00:02:07 1997
   9 * Modified at:   Sat Dec 25 16:42:42 1999
  10 * Modified by:   Dag Brattli <dagb@cs.uit.no>
  11 *
  12 *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
  13 *     All Rights Reserved.
  14 *     Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
  15 *
  16 *     This program is free software; you can redistribute it and/or
  17 *     modify it under the terms of the GNU General Public License as
  18 *     published by the Free Software Foundation; either version 2 of
  19 *     the License, or (at your option) any later version.
  20 *
  21 *     Neither Dag Brattli nor University of Tromsø admit liability nor
  22 *     provide warranty for any of this software. This material is
  23 *     provided "AS-IS" and at no charge.
  24 *
  25 ********************************************************************/
  26
  27#include <linux/module.h>
  28#include <linux/types.h>
  29#include <linux/skbuff.h>
  30#include <linux/fs.h>
  31#include <linux/string.h>
  32#include <linux/init.h>
  33#include <linux/seq_file.h>
  34#include <linux/slab.h>
  35
  36#include <asm/byteorder.h>
  37#include <asm/unaligned.h>
  38
  39#include <net/irda/irda.h>
  40#include <net/irda/irttp.h>
  41#include <net/irda/irlmp.h>
  42#include <net/irda/irias_object.h>
  43#include <net/irda/iriap_event.h>
  44#include <net/irda/iriap.h>
  45
  46/* FIXME: This one should go in irlmp.c */
  47static const char *const ias_charset_types[] __maybe_unused = {
  48        "CS_ASCII",
  49        "CS_ISO_8859_1",
  50        "CS_ISO_8859_2",
  51        "CS_ISO_8859_3",
  52        "CS_ISO_8859_4",
  53        "CS_ISO_8859_5",
  54        "CS_ISO_8859_6",
  55        "CS_ISO_8859_7",
  56        "CS_ISO_8859_8",
  57        "CS_ISO_8859_9",
  58        "CS_UNICODE"
  59};
  60
  61static hashbin_t *iriap = NULL;
  62static void *service_handle;
  63
  64static void __iriap_close(struct iriap_cb *self);
  65static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode);
  66static void iriap_disconnect_indication(void *instance, void *sap,
  67                                        LM_REASON reason, struct sk_buff *skb);
  68static void iriap_connect_indication(void *instance, void *sap,
  69                                     struct qos_info *qos, __u32 max_sdu_size,
  70                                     __u8 max_header_size,
  71                                     struct sk_buff *skb);
  72static void iriap_connect_confirm(void *instance, void *sap,
  73                                  struct qos_info *qos,
  74                                  __u32 max_sdu_size, __u8 max_header_size,
  75                                  struct sk_buff *skb);
  76static int iriap_data_indication(void *instance, void *sap,
  77                                 struct sk_buff *skb);
  78
  79static void iriap_watchdog_timer_expired(void *data);
  80
  81static inline void iriap_start_watchdog_timer(struct iriap_cb *self,
  82                                              int timeout)
  83{
  84        irda_start_timer(&self->watchdog_timer, timeout, self,
  85                         iriap_watchdog_timer_expired);
  86}
  87
  88static struct lock_class_key irias_objects_key;
  89
  90/*
  91 * Function iriap_init (void)
  92 *
  93 *    Initializes the IrIAP layer, called by the module initialization code
  94 *    in irmod.c
  95 */
  96int __init iriap_init(void)
  97{
  98        struct ias_object *obj;
  99        struct iriap_cb *server;
 100        __u8 oct_seq[6];
 101        __u16 hints;
 102
 103        /* Allocate master array */
 104        iriap = hashbin_new(HB_LOCK);
 105        if (!iriap)
 106                return -ENOMEM;
 107
 108        /* Object repository - defined in irias_object.c */
 109        irias_objects = hashbin_new(HB_LOCK);
 110        if (!irias_objects) {
 111                net_warn_ratelimited("%s: Can't allocate irias_objects hashbin!\n",
 112                                     __func__);
 113                hashbin_delete(iriap, NULL);
 114                return -ENOMEM;
 115        }
 116
 117        lockdep_set_class_and_name(&irias_objects->hb_spinlock, &irias_objects_key,
 118                                   "irias_objects");
 119
 120        /*
 121         *  Register some default services for IrLMP
 122         */
 123        hints  = irlmp_service_to_hint(S_COMPUTER);
 124        service_handle = irlmp_register_service(hints);
 125
 126        /* Register the Device object with LM-IAS */
 127        obj = irias_new_object("Device", IAS_DEVICE_ID);
 128        irias_add_string_attrib(obj, "DeviceName", "Linux", IAS_KERNEL_ATTR);
 129
 130        oct_seq[0] = 0x01;  /* Version 1 */
 131        oct_seq[1] = 0x00;  /* IAS support bits */
 132        oct_seq[2] = 0x00;  /* LM-MUX support bits */
 133#ifdef CONFIG_IRDA_ULTRA
 134        oct_seq[2] |= 0x04; /* Connectionless Data support */
 135#endif
 136        irias_add_octseq_attrib(obj, "IrLMPSupport", oct_seq, 3,
 137                                IAS_KERNEL_ATTR);
 138        irias_insert_object(obj);
 139
 140        /*
 141         *  Register server support with IrLMP so we can accept incoming
 142         *  connections
 143         */
 144        server = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
 145        if (!server) {
 146                pr_debug("%s(), unable to open server\n", __func__);
 147                return -1;
 148        }
 149        iriap_register_lsap(server, LSAP_IAS, IAS_SERVER);
 150
 151        return 0;
 152}
 153
 154/*
 155 * Function iriap_cleanup (void)
 156 *
 157 *    Initializes the IrIAP layer, called by the module cleanup code in
 158 *    irmod.c
 159 */
 160void iriap_cleanup(void)
 161{
 162        irlmp_unregister_service(service_handle);
 163
 164        hashbin_delete(iriap, (FREE_FUNC) __iriap_close);
 165        hashbin_delete(irias_objects, (FREE_FUNC) __irias_delete_object);
 166}
 167
 168/*
 169 * Function iriap_open (void)
 170 *
 171 *    Opens an instance of the IrIAP layer, and registers with IrLMP
 172 */
 173struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv,
 174                            CONFIRM_CALLBACK callback)
 175{
 176        struct iriap_cb *self;
 177
 178        self = kzalloc(sizeof(*self), GFP_ATOMIC);
 179        if (!self)
 180                return NULL;
 181
 182        /*
 183         *  Initialize instance
 184         */
 185
 186        self->magic = IAS_MAGIC;
 187        self->mode = mode;
 188        if (mode == IAS_CLIENT) {
 189                if (iriap_register_lsap(self, slsap_sel, mode)) {
 190                        kfree(self);
 191                        return NULL;
 192                }
 193        }
 194
 195        self->confirm = callback;
 196        self->priv = priv;
 197
 198        /* iriap_getvaluebyclass_request() will construct packets before
 199         * we connect, so this must have a sane value... Jean II */
 200        self->max_header_size = LMP_MAX_HEADER;
 201
 202        init_timer(&self->watchdog_timer);
 203
 204        hashbin_insert(iriap, (irda_queue_t *) self, (long) self, NULL);
 205
 206        /* Initialize state machines */
 207        iriap_next_client_state(self, S_DISCONNECT);
 208        iriap_next_call_state(self, S_MAKE_CALL);
 209        iriap_next_server_state(self, R_DISCONNECT);
 210        iriap_next_r_connect_state(self, R_WAITING);
 211
 212        return self;
 213}
 214EXPORT_SYMBOL(iriap_open);
 215
 216/*
 217 * Function __iriap_close (self)
 218 *
 219 *    Removes (deallocates) the IrIAP instance
 220 *
 221 */
 222static void __iriap_close(struct iriap_cb *self)
 223{
 224        IRDA_ASSERT(self != NULL, return;);
 225        IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 226
 227        del_timer(&self->watchdog_timer);
 228
 229        if (self->request_skb)
 230                dev_kfree_skb(self->request_skb);
 231
 232        self->magic = 0;
 233
 234        kfree(self);
 235}
 236
 237/*
 238 * Function iriap_close (void)
 239 *
 240 *    Closes IrIAP and deregisters with IrLMP
 241 */
 242void iriap_close(struct iriap_cb *self)
 243{
 244        struct iriap_cb *entry;
 245
 246        IRDA_ASSERT(self != NULL, return;);
 247        IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 248
 249        if (self->lsap) {
 250                irlmp_close_lsap(self->lsap);
 251                self->lsap = NULL;
 252        }
 253
 254        entry = (struct iriap_cb *) hashbin_remove(iriap, (long) self, NULL);
 255        IRDA_ASSERT(entry == self, return;);
 256
 257        __iriap_close(self);
 258}
 259EXPORT_SYMBOL(iriap_close);
 260
 261static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode)
 262{
 263        notify_t notify;
 264
 265        irda_notify_init(&notify);
 266        notify.connect_confirm       = iriap_connect_confirm;
 267        notify.connect_indication    = iriap_connect_indication;
 268        notify.disconnect_indication = iriap_disconnect_indication;
 269        notify.data_indication       = iriap_data_indication;
 270        notify.instance = self;
 271        if (mode == IAS_CLIENT)
 272                strcpy(notify.name, "IrIAS cli");
 273        else
 274                strcpy(notify.name, "IrIAS srv");
 275
 276        self->lsap = irlmp_open_lsap(slsap_sel, &notify, 0);
 277        if (self->lsap == NULL) {
 278                net_err_ratelimited("%s: Unable to allocated LSAP!\n",
 279                                    __func__);
 280                return -1;
 281        }
 282        self->slsap_sel = self->lsap->slsap_sel;
 283
 284        return 0;
 285}
 286
 287/*
 288 * Function iriap_disconnect_indication (handle, reason)
 289 *
 290 *    Got disconnect, so clean up everything associated with this connection
 291 *
 292 */
 293static void iriap_disconnect_indication(void *instance, void *sap,
 294                                        LM_REASON reason,
 295                                        struct sk_buff *skb)
 296{
 297        struct iriap_cb *self;
 298
 299        pr_debug("%s(), reason=%s [%d]\n", __func__,
 300                 irlmp_reason_str(reason), reason);
 301
 302        self = instance;
 303
 304        IRDA_ASSERT(self != NULL, return;);
 305        IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 306
 307        IRDA_ASSERT(iriap != NULL, return;);
 308
 309        del_timer(&self->watchdog_timer);
 310
 311        /* Not needed */
 312        if (skb)
 313                dev_kfree_skb(skb);
 314
 315        if (self->mode == IAS_CLIENT) {
 316                pr_debug("%s(), disconnect as client\n", __func__);
 317
 318
 319                iriap_do_client_event(self, IAP_LM_DISCONNECT_INDICATION,
 320                                      NULL);
 321                /*
 322                 * Inform service user that the request failed by sending
 323                 * it a NULL value. Warning, the client might close us, so
 324                 * remember no to use self anymore after calling confirm
 325                 */
 326                if (self->confirm)
 327                        self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
 328        } else {
 329                pr_debug("%s(), disconnect as server\n", __func__);
 330                iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION,
 331                                      NULL);
 332                iriap_close(self);
 333        }
 334}
 335
 336/*
 337 * Function iriap_disconnect_request (handle)
 338 */
 339static void iriap_disconnect_request(struct iriap_cb *self)
 340{
 341        struct sk_buff *tx_skb;
 342
 343        IRDA_ASSERT(self != NULL, return;);
 344        IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 345
 346        tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
 347        if (tx_skb == NULL) {
 348                pr_debug("%s(), Could not allocate an sk_buff of length %d\n",
 349                         __func__, LMP_MAX_HEADER);
 350                return;
 351        }
 352
 353        /*
 354         *  Reserve space for MUX control and LAP header
 355         */
 356        skb_reserve(tx_skb, LMP_MAX_HEADER);
 357
 358        irlmp_disconnect_request(self->lsap, tx_skb);
 359}
 360
 361/*
 362 * Function iriap_getvaluebyclass (addr, name, attr)
 363 *
 364 *    Retrieve all values from attribute in all objects with given class
 365 *    name
 366 */
 367int iriap_getvaluebyclass_request(struct iriap_cb *self,
 368                                  __u32 saddr, __u32 daddr,
 369                                  char *name, char *attr)
 370{
 371        struct sk_buff *tx_skb;
 372        int name_len, attr_len, skb_len;
 373        __u8 *frame;
 374
 375        IRDA_ASSERT(self != NULL, return -1;);
 376        IRDA_ASSERT(self->magic == IAS_MAGIC, return -1;);
 377
 378        /* Client must supply the destination device address */
 379        if (!daddr)
 380                return -1;
 381
 382        self->daddr = daddr;
 383        self->saddr = saddr;
 384
 385        /*
 386         *  Save operation, so we know what the later indication is about
 387         */
 388        self->operation = GET_VALUE_BY_CLASS;
 389
 390        /* Give ourselves 10 secs to finish this operation */
 391        iriap_start_watchdog_timer(self, 10*HZ);
 392
 393        name_len = strlen(name);        /* Up to IAS_MAX_CLASSNAME = 60 */
 394        attr_len = strlen(attr);        /* Up to IAS_MAX_ATTRIBNAME = 60 */
 395
 396        skb_len = self->max_header_size+2+name_len+1+attr_len+4;
 397        tx_skb = alloc_skb(skb_len, GFP_ATOMIC);
 398        if (!tx_skb)
 399                return -ENOMEM;
 400
 401        /* Reserve space for MUX and LAP header */
 402        skb_reserve(tx_skb, self->max_header_size);
 403        skb_put(tx_skb, 3+name_len+attr_len);
 404        frame = tx_skb->data;
 405
 406        /* Build frame */
 407        frame[0] = IAP_LST | GET_VALUE_BY_CLASS;
 408        frame[1] = name_len;                       /* Insert length of name */
 409        memcpy(frame+2, name, name_len);           /* Insert name */
 410        frame[2+name_len] = attr_len;              /* Insert length of attr */
 411        memcpy(frame+3+name_len, attr, attr_len);  /* Insert attr */
 412
 413        iriap_do_client_event(self, IAP_CALL_REQUEST_GVBC, tx_skb);
 414
 415        /* Drop reference count - see state_s_disconnect(). */
 416        dev_kfree_skb(tx_skb);
 417
 418        return 0;
 419}
 420EXPORT_SYMBOL(iriap_getvaluebyclass_request);
 421
 422/*
 423 * Function iriap_getvaluebyclass_confirm (self, skb)
 424 *
 425 *    Got result from GetValueByClass command. Parse it and return result
 426 *    to service user.
 427 *
 428 */
 429static void iriap_getvaluebyclass_confirm(struct iriap_cb *self,
 430                                          struct sk_buff *skb)
 431{
 432        struct ias_value *value;
 433        int charset;
 434        __u32 value_len;
 435        __u32 tmp_cpu32;
 436        __u16 obj_id;
 437        __u16 len;
 438        __u8  type;
 439        __u8 *fp;
 440        int n;
 441
 442        IRDA_ASSERT(self != NULL, return;);
 443        IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 444        IRDA_ASSERT(skb != NULL, return;);
 445
 446        /* Initialize variables */
 447        fp = skb->data;
 448        n = 2;
 449
 450        /* Get length, MSB first */
 451        len = get_unaligned_be16(fp + n);
 452        n += 2;
 453
 454        pr_debug("%s(), len=%d\n", __func__, len);
 455
 456        /* Get object ID, MSB first */
 457        obj_id = get_unaligned_be16(fp + n);
 458        n += 2;
 459
 460        type = fp[n++];
 461        pr_debug("%s(), Value type = %d\n", __func__, type);
 462
 463        switch (type) {
 464        case IAS_INTEGER:
 465                memcpy(&tmp_cpu32, fp+n, 4); n += 4;
 466                be32_to_cpus(&tmp_cpu32);
 467                value = irias_new_integer_value(tmp_cpu32);
 468
 469                /*  Legal values restricted to 0x01-0x6f, page 15 irttp */
 470                pr_debug("%s(), lsap=%d\n", __func__, value->t.integer);
 471                break;
 472        case IAS_STRING:
 473                charset = fp[n++];
 474
 475                switch (charset) {
 476                case CS_ASCII:
 477                        break;
 478/*              case CS_ISO_8859_1: */
 479/*              case CS_ISO_8859_2: */
 480/*              case CS_ISO_8859_3: */
 481/*              case CS_ISO_8859_4: */
 482/*              case CS_ISO_8859_5: */
 483/*              case CS_ISO_8859_6: */
 484/*              case CS_ISO_8859_7: */
 485/*              case CS_ISO_8859_8: */
 486/*              case CS_ISO_8859_9: */
 487/*              case CS_UNICODE: */
 488                default:
 489                        pr_debug("%s(), charset [%d] %s, not supported\n",
 490                                 __func__, charset,
 491                                 charset < ARRAY_SIZE(ias_charset_types) ?
 492                                 ias_charset_types[charset] :
 493                                 "(unknown)");
 494
 495                        /* Aborting, close connection! */
 496                        iriap_disconnect_request(self);
 497                        return;
 498                        /* break; */
 499                }
 500                value_len = fp[n++];
 501                pr_debug("%s(), strlen=%d\n", __func__, value_len);
 502
 503                /* Make sure the string is null-terminated */
 504                if (n + value_len < skb->len)
 505                        fp[n + value_len] = 0x00;
 506                pr_debug("Got string %s\n", fp+n);
 507
 508                /* Will truncate to IAS_MAX_STRING bytes */
 509                value = irias_new_string_value(fp+n);
 510                break;
 511        case IAS_OCT_SEQ:
 512                value_len = get_unaligned_be16(fp + n);
 513                n += 2;
 514
 515                /* Will truncate to IAS_MAX_OCTET_STRING bytes */
 516                value = irias_new_octseq_value(fp+n, value_len);
 517                break;
 518        default:
 519                value = irias_new_missing_value();
 520                break;
 521        }
 522
 523        /* Finished, close connection! */
 524        iriap_disconnect_request(self);
 525
 526        /* Warning, the client might close us, so remember no to use self
 527         * anymore after calling confirm
 528         */
 529        if (self->confirm)
 530                self->confirm(IAS_SUCCESS, obj_id, value, self->priv);
 531        else {
 532                pr_debug("%s(), missing handler!\n", __func__);
 533                irias_delete_value(value);
 534        }
 535}
 536
 537/*
 538 * Function iriap_getvaluebyclass_response ()
 539 *
 540 *    Send answer back to remote LM-IAS
 541 *
 542 */
 543static void iriap_getvaluebyclass_response(struct iriap_cb *self,
 544                                           __u16 obj_id,
 545                                           __u8 ret_code,
 546                                           struct ias_value *value)
 547{
 548        struct sk_buff *tx_skb;
 549        int n;
 550        __be32 tmp_be32;
 551        __be16 tmp_be16;
 552        __u8 *fp;
 553
 554        IRDA_ASSERT(self != NULL, return;);
 555        IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 556        IRDA_ASSERT(value != NULL, return;);
 557        IRDA_ASSERT(value->len <= 1024, return;);
 558
 559        /* Initialize variables */
 560        n = 0;
 561
 562        /*
 563         *  We must adjust the size of the response after the length of the
 564         *  value. We add 32 bytes because of the 6 bytes for the frame and
 565         *  max 5 bytes for the value coding.
 566         */
 567        tx_skb = alloc_skb(value->len + self->max_header_size + 32,
 568                           GFP_ATOMIC);
 569        if (!tx_skb)
 570                return;
 571
 572        /* Reserve space for MUX and LAP header */
 573        skb_reserve(tx_skb, self->max_header_size);
 574        skb_put(tx_skb, 6);
 575
 576        fp = tx_skb->data;
 577
 578        /* Build frame */
 579        fp[n++] = GET_VALUE_BY_CLASS | IAP_LST;
 580        fp[n++] = ret_code;
 581
 582        /* Insert list length (MSB first) */
 583        tmp_be16 = htons(0x0001);
 584        memcpy(fp+n, &tmp_be16, 2);  n += 2;
 585
 586        /* Insert object identifier ( MSB first) */
 587        tmp_be16 = cpu_to_be16(obj_id);
 588        memcpy(fp+n, &tmp_be16, 2); n += 2;
 589
 590        switch (value->type) {
 591        case IAS_STRING:
 592                skb_put(tx_skb, 3 + value->len);
 593                fp[n++] = value->type;
 594                fp[n++] = 0; /* ASCII */
 595                fp[n++] = (__u8) value->len;
 596                memcpy(fp+n, value->t.string, value->len); n+=value->len;
 597                break;
 598        case IAS_INTEGER:
 599                skb_put(tx_skb, 5);
 600                fp[n++] = value->type;
 601
 602                tmp_be32 = cpu_to_be32(value->t.integer);
 603                memcpy(fp+n, &tmp_be32, 4); n += 4;
 604                break;
 605        case IAS_OCT_SEQ:
 606                skb_put(tx_skb, 3 + value->len);
 607                fp[n++] = value->type;
 608
 609                tmp_be16 = cpu_to_be16(value->len);
 610                memcpy(fp+n, &tmp_be16, 2); n += 2;
 611                memcpy(fp+n, value->t.oct_seq, value->len); n+=value->len;
 612                break;
 613        case IAS_MISSING:
 614                pr_debug("%s: sending IAS_MISSING\n", __func__);
 615                skb_put(tx_skb, 1);
 616                fp[n++] = value->type;
 617                break;
 618        default:
 619                pr_debug("%s(), type not implemented!\n", __func__);
 620                break;
 621        }
 622        iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, tx_skb);
 623
 624        /* Drop reference count - see state_r_execute(). */
 625        dev_kfree_skb(tx_skb);
 626}
 627
 628/*
 629 * Function iriap_getvaluebyclass_indication (self, skb)
 630 *
 631 *    getvaluebyclass is requested from peer LM-IAS
 632 *
 633 */
 634static void iriap_getvaluebyclass_indication(struct iriap_cb *self,
 635                                             struct sk_buff *skb)
 636{
 637        struct ias_object *obj;
 638        struct ias_attrib *attrib;
 639        int name_len;
 640        int attr_len;
 641        char name[IAS_MAX_CLASSNAME + 1];       /* 60 bytes */
 642        char attr[IAS_MAX_ATTRIBNAME + 1];      /* 60 bytes */
 643        __u8 *fp;
 644        int n;
 645
 646        IRDA_ASSERT(self != NULL, return;);
 647        IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 648        IRDA_ASSERT(skb != NULL, return;);
 649
 650        fp = skb->data;
 651        n = 1;
 652
 653        name_len = fp[n++];
 654
 655        IRDA_ASSERT(name_len < IAS_MAX_CLASSNAME + 1, return;);
 656
 657        memcpy(name, fp+n, name_len); n+=name_len;
 658        name[name_len] = '\0';
 659
 660        attr_len = fp[n++];
 661
 662        IRDA_ASSERT(attr_len < IAS_MAX_ATTRIBNAME + 1, return;);
 663
 664        memcpy(attr, fp+n, attr_len); n+=attr_len;
 665        attr[attr_len] = '\0';
 666
 667        pr_debug("LM-IAS: Looking up %s: %s\n", name, attr);
 668        obj = irias_find_object(name);
 669
 670        if (obj == NULL) {
 671                pr_debug("LM-IAS: Object %s not found\n", name);
 672                iriap_getvaluebyclass_response(self, 0x1235, IAS_CLASS_UNKNOWN,
 673                                               &irias_missing);
 674                return;
 675        }
 676        pr_debug("LM-IAS: found %s, id=%d\n", obj->name, obj->id);
 677
 678        attrib = irias_find_attrib(obj, attr);
 679        if (attrib == NULL) {
 680                pr_debug("LM-IAS: Attribute %s not found\n", attr);
 681                iriap_getvaluebyclass_response(self, obj->id,
 682                                               IAS_ATTRIB_UNKNOWN,
 683                                               &irias_missing);
 684                return;
 685        }
 686
 687        /* We have a match; send the value.  */
 688        iriap_getvaluebyclass_response(self, obj->id, IAS_SUCCESS,
 689                                       attrib->value);
 690}
 691
 692/*
 693 * Function iriap_send_ack (void)
 694 *
 695 *    Currently not used
 696 *
 697 */
 698void iriap_send_ack(struct iriap_cb *self)
 699{
 700        struct sk_buff *tx_skb;
 701        __u8 *frame;
 702
 703        IRDA_ASSERT(self != NULL, return;);
 704        IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 705
 706        tx_skb = alloc_skb(LMP_MAX_HEADER + 1, GFP_ATOMIC);
 707        if (!tx_skb)
 708                return;
 709
 710        /* Reserve space for MUX and LAP header */
 711        skb_reserve(tx_skb, self->max_header_size);
 712        skb_put(tx_skb, 1);
 713        frame = tx_skb->data;
 714
 715        /* Build frame */
 716        frame[0] = IAP_LST | IAP_ACK | self->operation;
 717
 718        irlmp_data_request(self->lsap, tx_skb);
 719}
 720
 721void iriap_connect_request(struct iriap_cb *self)
 722{
 723        int ret;
 724
 725        IRDA_ASSERT(self != NULL, return;);
 726        IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 727
 728        ret = irlmp_connect_request(self->lsap, LSAP_IAS,
 729                                    self->saddr, self->daddr,
 730                                    NULL, NULL);
 731        if (ret < 0) {
 732                pr_debug("%s(), connect failed!\n", __func__);
 733                self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
 734        }
 735}
 736
 737/*
 738 * Function iriap_connect_confirm (handle, skb)
 739 *
 740 *    LSAP connection confirmed!
 741 *
 742 */
 743static void iriap_connect_confirm(void *instance, void *sap,
 744                                  struct qos_info *qos, __u32 max_seg_size,
 745                                  __u8 max_header_size,
 746                                  struct sk_buff *skb)
 747{
 748        struct iriap_cb *self;
 749
 750        self = instance;
 751
 752        IRDA_ASSERT(self != NULL, return;);
 753        IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 754        IRDA_ASSERT(skb != NULL, return;);
 755
 756        self->max_data_size = max_seg_size;
 757        self->max_header_size = max_header_size;
 758
 759        del_timer(&self->watchdog_timer);
 760
 761        iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, skb);
 762
 763        /* Drop reference count - see state_s_make_call(). */
 764        dev_kfree_skb(skb);
 765}
 766
 767/*
 768 * Function iriap_connect_indication ( handle, skb)
 769 *
 770 *    Remote LM-IAS is requesting connection
 771 *
 772 */
 773static void iriap_connect_indication(void *instance, void *sap,
 774                                     struct qos_info *qos, __u32 max_seg_size,
 775                                     __u8 max_header_size,
 776                                     struct sk_buff *skb)
 777{
 778        struct iriap_cb *self, *new;
 779
 780        self = instance;
 781
 782        IRDA_ASSERT(skb != NULL, return;);
 783        IRDA_ASSERT(self != NULL, goto out;);
 784        IRDA_ASSERT(self->magic == IAS_MAGIC, goto out;);
 785
 786        /* Start new server */
 787        new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
 788        if (!new) {
 789                pr_debug("%s(), open failed\n", __func__);
 790                goto out;
 791        }
 792
 793        /* Now attach up the new "socket" */
 794        new->lsap = irlmp_dup(self->lsap, new);
 795        if (!new->lsap) {
 796                pr_debug("%s(), dup failed!\n", __func__);
 797                goto out;
 798        }
 799
 800        new->max_data_size = max_seg_size;
 801        new->max_header_size = max_header_size;
 802
 803        /* Clean up the original one to keep it in listen state */
 804        irlmp_listen(self->lsap);
 805
 806        iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, skb);
 807
 808out:
 809        /* Drop reference count - see state_r_disconnect(). */
 810        dev_kfree_skb(skb);
 811}
 812
 813/*
 814 * Function iriap_data_indication (handle, skb)
 815 *
 816 *    Receives data from connection identified by handle from IrLMP
 817 *
 818 */
 819static int iriap_data_indication(void *instance, void *sap,
 820                                 struct sk_buff *skb)
 821{
 822        struct iriap_cb *self;
 823        __u8  *frame;
 824        __u8  opcode;
 825
 826        self = instance;
 827
 828        IRDA_ASSERT(skb != NULL, return 0;);
 829        IRDA_ASSERT(self != NULL, goto out;);
 830        IRDA_ASSERT(self->magic == IAS_MAGIC, goto out;);
 831
 832        frame = skb->data;
 833
 834        if (self->mode == IAS_SERVER) {
 835                /* Call server */
 836                pr_debug("%s(), Calling server!\n", __func__);
 837                iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb);
 838                goto out;
 839        }
 840        opcode = frame[0];
 841        if (~opcode & IAP_LST) {
 842                net_warn_ratelimited("%s:, IrIAS multiframe commands or results is not implemented yet!\n",
 843                                     __func__);
 844                goto out;
 845        }
 846
 847        /* Check for ack frames since they don't contain any data */
 848        if (opcode & IAP_ACK) {
 849                pr_debug("%s() Got ack frame!\n", __func__);
 850                goto out;
 851        }
 852
 853        opcode &= ~IAP_LST; /* Mask away LST bit */
 854
 855        switch (opcode) {
 856        case GET_INFO_BASE:
 857                pr_debug("IrLMP GetInfoBaseDetails not implemented!\n");
 858                break;
 859        case GET_VALUE_BY_CLASS:
 860                iriap_do_call_event(self, IAP_RECV_F_LST, NULL);
 861
 862                switch (frame[1]) {
 863                case IAS_SUCCESS:
 864                        iriap_getvaluebyclass_confirm(self, skb);
 865                        break;
 866                case IAS_CLASS_UNKNOWN:
 867                        pr_debug("%s(), No such class!\n", __func__);
 868                        /* Finished, close connection! */
 869                        iriap_disconnect_request(self);
 870
 871                        /*
 872                         * Warning, the client might close us, so remember
 873                         * no to use self anymore after calling confirm
 874                         */
 875                        if (self->confirm)
 876                                self->confirm(IAS_CLASS_UNKNOWN, 0, NULL,
 877                                              self->priv);
 878                        break;
 879                case IAS_ATTRIB_UNKNOWN:
 880                        pr_debug("%s(), No such attribute!\n", __func__);
 881                        /* Finished, close connection! */
 882                        iriap_disconnect_request(self);
 883
 884                        /*
 885                         * Warning, the client might close us, so remember
 886                         * no to use self anymore after calling confirm
 887                         */
 888                        if (self->confirm)
 889                                self->confirm(IAS_ATTRIB_UNKNOWN, 0, NULL,
 890                                              self->priv);
 891                        break;
 892                }
 893                break;
 894        default:
 895                pr_debug("%s(), Unknown op-code: %02x\n", __func__,
 896                         opcode);
 897                break;
 898        }
 899
 900out:
 901        /* Cleanup - sub-calls will have done skb_get() as needed. */
 902        dev_kfree_skb(skb);
 903        return 0;
 904}
 905
 906/*
 907 * Function iriap_call_indication (self, skb)
 908 *
 909 *    Received call to server from peer LM-IAS
 910 *
 911 */
 912void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb)
 913{
 914        __u8 *fp;
 915        __u8 opcode;
 916
 917        IRDA_ASSERT(self != NULL, return;);
 918        IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 919        IRDA_ASSERT(skb != NULL, return;);
 920
 921        fp = skb->data;
 922
 923        opcode = fp[0];
 924        if (~opcode & 0x80) {
 925                net_warn_ratelimited("%s: IrIAS multiframe commands or results is not implemented yet!\n",
 926                                     __func__);
 927                return;
 928        }
 929        opcode &= 0x7f; /* Mask away LST bit */
 930
 931        switch (opcode) {
 932        case GET_INFO_BASE:
 933                net_warn_ratelimited("%s: GetInfoBaseDetails not implemented yet!\n",
 934                                     __func__);
 935                break;
 936        case GET_VALUE_BY_CLASS:
 937                iriap_getvaluebyclass_indication(self, skb);
 938                break;
 939        }
 940        /* skb will be cleaned up in iriap_data_indication */
 941}
 942
 943/*
 944 * Function iriap_watchdog_timer_expired (data)
 945 *
 946 *    Query has taken too long time, so abort
 947 *
 948 */
 949static void iriap_watchdog_timer_expired(void *data)
 950{
 951        struct iriap_cb *self = (struct iriap_cb *) data;
 952
 953        IRDA_ASSERT(self != NULL, return;);
 954        IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
 955
 956        /* iriap_close(self); */
 957}
 958
 959#ifdef CONFIG_PROC_FS
 960
 961static const char *const ias_value_types[] = {
 962        "IAS_MISSING",
 963        "IAS_INTEGER",
 964        "IAS_OCT_SEQ",
 965        "IAS_STRING"
 966};
 967
 968static inline struct ias_object *irias_seq_idx(loff_t pos)
 969{
 970        struct ias_object *obj;
 971
 972        for (obj = (struct ias_object *) hashbin_get_first(irias_objects);
 973             obj; obj = (struct ias_object *) hashbin_get_next(irias_objects)) {
 974                if (pos-- == 0)
 975                        break;
 976        }
 977
 978        return obj;
 979}
 980
 981static void *irias_seq_start(struct seq_file *seq, loff_t *pos)
 982{
 983        spin_lock_irq(&irias_objects->hb_spinlock);
 984
 985        return *pos ? irias_seq_idx(*pos - 1) : SEQ_START_TOKEN;
 986}
 987
 988static void *irias_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 989{
 990        ++*pos;
 991
 992        return (v == SEQ_START_TOKEN)
 993                ? (void *) hashbin_get_first(irias_objects)
 994                : (void *) hashbin_get_next(irias_objects);
 995}
 996
 997static void irias_seq_stop(struct seq_file *seq, void *v)
 998{
 999        spin_unlock_irq(&irias_objects->hb_spinlock);
1000}
1001
1002static int irias_seq_show(struct seq_file *seq, void *v)
1003{
1004        if (v == SEQ_START_TOKEN)
1005                seq_puts(seq, "LM-IAS Objects:\n");
1006        else {
1007                struct ias_object *obj = v;
1008                struct ias_attrib *attrib;
1009
1010                IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -EINVAL;);
1011
1012                seq_printf(seq, "name: %s, id=%d\n",
1013                           obj->name, obj->id);
1014
1015                /* Careful for priority inversions here !
1016                 * All other uses of attrib spinlock are independent of
1017                 * the object spinlock, so we are safe. Jean II */
1018                spin_lock(&obj->attribs->hb_spinlock);
1019
1020                /* List all attributes for this object */
1021                for (attrib = (struct ias_attrib *) hashbin_get_first(obj->attribs);
1022                     attrib != NULL;
1023                     attrib = (struct ias_attrib *) hashbin_get_next(obj->attribs)) {
1024
1025                        IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC,
1026                                    goto outloop; );
1027
1028                        seq_printf(seq, " - Attribute name: \"%s\", ",
1029                                   attrib->name);
1030                        seq_printf(seq, "value[%s]: ",
1031                                   ias_value_types[attrib->value->type]);
1032
1033                        switch (attrib->value->type) {
1034                        case IAS_INTEGER:
1035                                seq_printf(seq, "%d\n",
1036                                           attrib->value->t.integer);
1037                                break;
1038                        case IAS_STRING:
1039                                seq_printf(seq, "\"%s\"\n",
1040                                           attrib->value->t.string);
1041                                break;
1042                        case IAS_OCT_SEQ:
1043                                seq_printf(seq, "octet sequence (%d bytes)\n",
1044                                           attrib->value->len);
1045                                break;
1046                        case IAS_MISSING:
1047                                seq_puts(seq, "missing\n");
1048                                break;
1049                        default:
1050                                seq_printf(seq, "type %d?\n",
1051                                           attrib->value->type);
1052                        }
1053                        seq_putc(seq, '\n');
1054
1055                }
1056        IRDA_ASSERT_LABEL(outloop:)
1057                spin_unlock(&obj->attribs->hb_spinlock);
1058        }
1059
1060        return 0;
1061}
1062
1063static const struct seq_operations irias_seq_ops = {
1064        .start  = irias_seq_start,
1065        .next   = irias_seq_next,
1066        .stop   = irias_seq_stop,
1067        .show   = irias_seq_show,
1068};
1069
1070static int irias_seq_open(struct inode *inode, struct file *file)
1071{
1072        IRDA_ASSERT( irias_objects != NULL, return -EINVAL;);
1073
1074        return seq_open(file, &irias_seq_ops);
1075}
1076
1077const struct file_operations irias_seq_fops = {
1078        .owner          = THIS_MODULE,
1079        .open           = irias_seq_open,
1080        .read           = seq_read,
1081        .llseek         = seq_lseek,
1082        .release        = seq_release,
1083};
1084
1085#endif /* PROC_FS */
1086