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