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