linux/net/irda/irlan/irlan_provider.c
<<
>>
Prefs
   1/*********************************************************************
   2 *
   3 * Filename:      irlan_provider.c
   4 * Version:       0.9
   5 * Description:   IrDA LAN Access Protocol Implementation
   6 * Status:        Experimental.
   7 * Author:        Dag Brattli <dagb@cs.uit.no>
   8 * Created at:    Sun Aug 31 20:14:37 1997
   9 * Modified at:   Sat Oct 30 12:52:10 1999
  10 * Modified by:   Dag Brattli <dagb@cs.uit.no>
  11 * Sources:       skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
  12 *                slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk>
  13 *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  14 *
  15 *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
  16 *     All Rights Reserved.
  17 *
  18 *     This program is free software; you can redistribute it and/or
  19 *     modify it under the terms of the GNU General Public License as
  20 *     published by the Free Software Foundation; either version 2 of
  21 *     the License, or (at your option) any later version.
  22 *
  23 *     Neither Dag Brattli nor University of Tromsø admit liability nor
  24 *     provide warranty for any of this software. This material is
  25 *     provided "AS-IS" and at no charge.
  26 *
  27 ********************************************************************/
  28
  29#include <linux/kernel.h>
  30#include <linux/string.h>
  31#include <linux/errno.h>
  32#include <linux/netdevice.h>
  33#include <linux/etherdevice.h>
  34#include <linux/init.h>
  35#include <linux/random.h>
  36#include <linux/bitops.h>
  37#include <linux/slab.h>
  38
  39#include <asm/byteorder.h>
  40
  41#include <net/irda/irda.h>
  42#include <net/irda/irttp.h>
  43#include <net/irda/irlmp.h>
  44#include <net/irda/irias_object.h>
  45#include <net/irda/iriap.h>
  46#include <net/irda/timer.h>
  47
  48#include <net/irda/irlan_common.h>
  49#include <net/irda/irlan_eth.h>
  50#include <net/irda/irlan_event.h>
  51#include <net/irda/irlan_provider.h>
  52#include <net/irda/irlan_filter.h>
  53#include <net/irda/irlan_client.h>
  54
  55static void irlan_provider_connect_indication(void *instance, void *sap,
  56                                              struct qos_info *qos,
  57                                              __u32 max_sdu_size,
  58                                              __u8 max_header_size,
  59                                              struct sk_buff *skb);
  60
  61/*
  62 * Function irlan_provider_control_data_indication (handle, skb)
  63 *
  64 *    This function gets the data that is received on the control channel
  65 *
  66 */
  67static int irlan_provider_data_indication(void *instance, void *sap,
  68                                          struct sk_buff *skb)
  69{
  70        struct irlan_cb *self;
  71        __u8 code;
  72
  73        IRDA_DEBUG(4, "%s()\n", __func__ );
  74
  75        self = instance;
  76
  77        IRDA_ASSERT(self != NULL, return -1;);
  78        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
  79
  80        IRDA_ASSERT(skb != NULL, return -1;);
  81
  82        code = skb->data[0];
  83        switch(code) {
  84        case CMD_GET_PROVIDER_INFO:
  85                IRDA_DEBUG(4, "Got GET_PROVIDER_INFO command!\n");
  86                irlan_do_provider_event(self, IRLAN_GET_INFO_CMD, skb);
  87                break;
  88
  89        case CMD_GET_MEDIA_CHAR:
  90                IRDA_DEBUG(4, "Got GET_MEDIA_CHAR command!\n");
  91                irlan_do_provider_event(self, IRLAN_GET_MEDIA_CMD, skb);
  92                break;
  93        case CMD_OPEN_DATA_CHANNEL:
  94                IRDA_DEBUG(4, "Got OPEN_DATA_CHANNEL command!\n");
  95                irlan_do_provider_event(self, IRLAN_OPEN_DATA_CMD, skb);
  96                break;
  97        case CMD_FILTER_OPERATION:
  98                IRDA_DEBUG(4, "Got FILTER_OPERATION command!\n");
  99                irlan_do_provider_event(self, IRLAN_FILTER_CONFIG_CMD, skb);
 100                break;
 101        case CMD_RECONNECT_DATA_CHAN:
 102                IRDA_DEBUG(2, "%s(), Got RECONNECT_DATA_CHAN command\n", __func__ );
 103                IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __func__ );
 104                break;
 105        case CMD_CLOSE_DATA_CHAN:
 106                IRDA_DEBUG(2, "Got CLOSE_DATA_CHAN command!\n");
 107                IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __func__ );
 108                break;
 109        default:
 110                IRDA_DEBUG(2, "%s(), Unknown command!\n", __func__ );
 111                break;
 112        }
 113        return 0;
 114}
 115
 116/*
 117 * Function irlan_provider_connect_indication (handle, skb, priv)
 118 *
 119 *    Got connection from peer IrLAN client
 120 *
 121 */
 122static void irlan_provider_connect_indication(void *instance, void *sap,
 123                                              struct qos_info *qos,
 124                                              __u32 max_sdu_size,
 125                                              __u8 max_header_size,
 126                                              struct sk_buff *skb)
 127{
 128        struct irlan_cb *self;
 129        struct tsap_cb *tsap;
 130
 131        IRDA_DEBUG(0, "%s()\n", __func__ );
 132
 133        self = instance;
 134        tsap = sap;
 135
 136        IRDA_ASSERT(self != NULL, return;);
 137        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 138
 139        IRDA_ASSERT(tsap == self->provider.tsap_ctrl,return;);
 140        IRDA_ASSERT(self->provider.state == IRLAN_IDLE, return;);
 141
 142        self->provider.max_sdu_size = max_sdu_size;
 143        self->provider.max_header_size = max_header_size;
 144
 145        irlan_do_provider_event(self, IRLAN_CONNECT_INDICATION, NULL);
 146
 147        /*
 148         * If we are in peer mode, the client may not have got the discovery
 149         * indication it needs to make progress. If the client is still in
 150         * IDLE state, we must kick it.
 151         */
 152        if ((self->provider.access_type == ACCESS_PEER) &&
 153            (self->client.state == IRLAN_IDLE))
 154        {
 155                irlan_client_wakeup(self, self->saddr, self->daddr);
 156        }
 157}
 158
 159/*
 160 * Function irlan_provider_connect_response (handle)
 161 *
 162 *    Accept incoming connection
 163 *
 164 */
 165void irlan_provider_connect_response(struct irlan_cb *self,
 166                                     struct tsap_cb *tsap)
 167{
 168        IRDA_ASSERT(self != NULL, return;);
 169        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 170
 171        /* Just accept */
 172        irttp_connect_response(tsap, IRLAN_MTU, NULL);
 173}
 174
 175static void irlan_provider_disconnect_indication(void *instance, void *sap,
 176                                                 LM_REASON reason,
 177                                                 struct sk_buff *userdata)
 178{
 179        struct irlan_cb *self;
 180        struct tsap_cb *tsap;
 181
 182        IRDA_DEBUG(4, "%s(), reason=%d\n", __func__ , reason);
 183
 184        self = instance;
 185        tsap = sap;
 186
 187        IRDA_ASSERT(self != NULL, return;);
 188        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 189        IRDA_ASSERT(tsap != NULL, return;);
 190        IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
 191
 192        IRDA_ASSERT(tsap == self->provider.tsap_ctrl, return;);
 193
 194        irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
 195}
 196
 197/*
 198 * Function irlan_parse_open_data_cmd (self, skb)
 199 *
 200 *
 201 *
 202 */
 203int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb)
 204{
 205        int ret;
 206
 207        ret = irlan_provider_parse_command(self, CMD_OPEN_DATA_CHANNEL, skb);
 208
 209        /* Open data channel */
 210        irlan_open_data_tsap(self);
 211
 212        return ret;
 213}
 214
 215/*
 216 * Function parse_command (skb)
 217 *
 218 *    Extract all parameters from received buffer, then feed them to
 219 *    check_params for parsing
 220 *
 221 */
 222int irlan_provider_parse_command(struct irlan_cb *self, int cmd,
 223                                 struct sk_buff *skb)
 224{
 225        __u8 *frame;
 226        __u8 *ptr;
 227        int count;
 228        __u16 val_len;
 229        int i;
 230        char *name;
 231        char *value;
 232        int ret = RSP_SUCCESS;
 233
 234        IRDA_ASSERT(skb != NULL, return -RSP_PROTOCOL_ERROR;);
 235
 236        IRDA_DEBUG(4, "%s(), skb->len=%d\n", __func__ , (int)skb->len);
 237
 238        IRDA_ASSERT(self != NULL, return -RSP_PROTOCOL_ERROR;);
 239        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -RSP_PROTOCOL_ERROR;);
 240
 241        if (!skb)
 242                return -RSP_PROTOCOL_ERROR;
 243
 244        frame = skb->data;
 245
 246        name = kmalloc(255, GFP_ATOMIC);
 247        if (!name)
 248                return -RSP_INSUFFICIENT_RESOURCES;
 249        value = kmalloc(1016, GFP_ATOMIC);
 250        if (!value) {
 251                kfree(name);
 252                return -RSP_INSUFFICIENT_RESOURCES;
 253        }
 254
 255        /* How many parameters? */
 256        count = frame[1];
 257
 258        IRDA_DEBUG(4, "Got %d parameters\n", count);
 259
 260        ptr = frame+2;
 261
 262        /* For all parameters */
 263        for (i=0; i<count;i++) {
 264                ret = irlan_extract_param(ptr, name, value, &val_len);
 265                if (ret < 0) {
 266                        IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __func__ );
 267                        break;
 268                }
 269                ptr+=ret;
 270                ret = RSP_SUCCESS;
 271                irlan_check_command_param(self, name, value);
 272        }
 273        /* Cleanup */
 274        kfree(name);
 275        kfree(value);
 276
 277        return ret;
 278}
 279
 280/*
 281 * Function irlan_provider_send_reply (self, info)
 282 *
 283 *    Send reply to query to peer IrLAN layer
 284 *
 285 */
 286void irlan_provider_send_reply(struct irlan_cb *self, int command,
 287                               int ret_code)
 288{
 289        struct sk_buff *skb;
 290
 291        IRDA_DEBUG(4, "%s()\n", __func__ );
 292
 293        IRDA_ASSERT(self != NULL, return;);
 294        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 295
 296        skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
 297                        /* Bigger param length comes from CMD_GET_MEDIA_CHAR */
 298                        IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") +
 299                        IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "BROADCAST") +
 300                        IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "MULTICAST") +
 301                        IRLAN_STRING_PARAMETER_LEN("ACCESS_TYPE", "HOSTED"),
 302                        GFP_ATOMIC);
 303
 304        if (!skb)
 305                return;
 306
 307        /* Reserve space for TTP, LMP, and LAP header */
 308        skb_reserve(skb, self->provider.max_header_size);
 309        skb_put(skb, 2);
 310
 311        switch (command) {
 312        case CMD_GET_PROVIDER_INFO:
 313                skb->data[0] = 0x00; /* Success */
 314                skb->data[1] = 0x02; /* 2 parameters */
 315                switch (self->media) {
 316                case MEDIA_802_3:
 317                        irlan_insert_string_param(skb, "MEDIA", "802.3");
 318                        break;
 319                case MEDIA_802_5:
 320                        irlan_insert_string_param(skb, "MEDIA", "802.5");
 321                        break;
 322                default:
 323                        IRDA_DEBUG(2, "%s(), unknown media type!\n", __func__ );
 324                        break;
 325                }
 326                irlan_insert_short_param(skb, "IRLAN_VER", 0x0101);
 327                break;
 328
 329        case CMD_GET_MEDIA_CHAR:
 330                skb->data[0] = 0x00; /* Success */
 331                skb->data[1] = 0x05; /* 5 parameters */
 332                irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
 333                irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST");
 334                irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST");
 335
 336                switch (self->provider.access_type) {
 337                case ACCESS_DIRECT:
 338                        irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT");
 339                        break;
 340                case ACCESS_PEER:
 341                        irlan_insert_string_param(skb, "ACCESS_TYPE", "PEER");
 342                        break;
 343                case ACCESS_HOSTED:
 344                        irlan_insert_string_param(skb, "ACCESS_TYPE", "HOSTED");
 345                        break;
 346                default:
 347                        IRDA_DEBUG(2, "%s(), Unknown access type\n", __func__ );
 348                        break;
 349                }
 350                irlan_insert_short_param(skb, "MAX_FRAME", 0x05ee);
 351                break;
 352        case CMD_OPEN_DATA_CHANNEL:
 353                skb->data[0] = 0x00; /* Success */
 354                if (self->provider.send_arb_val) {
 355                        skb->data[1] = 0x03; /* 3 parameters */
 356                        irlan_insert_short_param(skb, "CON_ARB",
 357                                                 self->provider.send_arb_val);
 358                } else
 359                        skb->data[1] = 0x02; /* 2 parameters */
 360                irlan_insert_byte_param(skb, "DATA_CHAN", self->stsap_sel_data);
 361                irlan_insert_string_param(skb, "RECONNECT_KEY", "LINUX RULES!");
 362                break;
 363        case CMD_FILTER_OPERATION:
 364                irlan_filter_request(self, skb);
 365                break;
 366        default:
 367                IRDA_DEBUG(2, "%s(), Unknown command!\n", __func__ );
 368                break;
 369        }
 370
 371        irttp_data_request(self->provider.tsap_ctrl, skb);
 372}
 373
 374/*
 375 * Function irlan_provider_register(void)
 376 *
 377 *    Register provider support so we can accept incoming connections.
 378 *
 379 */
 380int irlan_provider_open_ctrl_tsap(struct irlan_cb *self)
 381{
 382        struct tsap_cb *tsap;
 383        notify_t notify;
 384
 385        IRDA_DEBUG(4, "%s()\n", __func__ );
 386
 387        IRDA_ASSERT(self != NULL, return -1;);
 388        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
 389
 390        /* Check if already open */
 391        if (self->provider.tsap_ctrl)
 392                return -1;
 393
 394        /*
 395         *  First register well known control TSAP
 396         */
 397        irda_notify_init(&notify);
 398        notify.data_indication       = irlan_provider_data_indication;
 399        notify.connect_indication    = irlan_provider_connect_indication;
 400        notify.disconnect_indication = irlan_provider_disconnect_indication;
 401        notify.instance = self;
 402        strlcpy(notify.name, "IrLAN ctrl (p)", sizeof(notify.name));
 403
 404        tsap = irttp_open_tsap(LSAP_ANY, 1, &notify);
 405        if (!tsap) {
 406                IRDA_DEBUG(2, "%s(), Got no tsap!\n", __func__ );
 407                return -1;
 408        }
 409        self->provider.tsap_ctrl = tsap;
 410
 411        /* Register with LM-IAS */
 412        irlan_ias_register(self, tsap->stsap_sel);
 413
 414        return 0;
 415}
 416
 417