linux/net/irda/irlan/irlan_client_event.c
<<
>>
Prefs
   1/*********************************************************************
   2 *
   3 * Filename:      irlan_client_event.c
   4 * Version:       0.9
   5 * Description:   IrLAN client state machine
   6 * Status:        Experimental.
   7 * Author:        Dag Brattli <dagb@cs.uit.no>
   8 * Created at:    Sun Aug 31 20:14:37 1997
   9 * Modified at:   Sun Dec 26 21:52:24 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 *
  15 *     This program is free software; you can redistribute it and/or
  16 *     modify it under the terms of the GNU General Public License as
  17 *     published by the Free Software Foundation; either version 2 of
  18 *     the License, or (at your option) any later version.
  19 *
  20 *     Neither Dag Brattli nor University of Tromsø admit liability nor
  21 *     provide warranty for any of this software. This material is
  22 *     provided "AS-IS" and at no charge.
  23 *
  24 ********************************************************************/
  25
  26#include <linux/skbuff.h>
  27
  28#include <net/irda/irda.h>
  29#include <net/irda/timer.h>
  30#include <net/irda/irmod.h>
  31#include <net/irda/iriap.h>
  32#include <net/irda/irlmp.h>
  33#include <net/irda/irttp.h>
  34
  35#include <net/irda/irlan_common.h>
  36#include <net/irda/irlan_client.h>
  37#include <net/irda/irlan_event.h>
  38
  39static int irlan_client_state_idle (struct irlan_cb *self, IRLAN_EVENT event,
  40                                    struct sk_buff *skb);
  41static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
  42                                    struct sk_buff *skb);
  43static int irlan_client_state_conn (struct irlan_cb *self, IRLAN_EVENT event,
  44                                    struct sk_buff *skb);
  45static int irlan_client_state_info (struct irlan_cb *self, IRLAN_EVENT event,
  46                                    struct sk_buff *skb);
  47static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
  48                                    struct sk_buff *skb);
  49static int irlan_client_state_open (struct irlan_cb *self, IRLAN_EVENT event,
  50                                    struct sk_buff *skb);
  51static int irlan_client_state_wait (struct irlan_cb *self, IRLAN_EVENT event,
  52                                    struct sk_buff *skb);
  53static int irlan_client_state_arb  (struct irlan_cb *self, IRLAN_EVENT event,
  54                                    struct sk_buff *skb);
  55static int irlan_client_state_data (struct irlan_cb *self, IRLAN_EVENT event,
  56                                    struct sk_buff *skb);
  57static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,
  58                                    struct sk_buff *skb);
  59static int irlan_client_state_sync (struct irlan_cb *self, IRLAN_EVENT event,
  60                                    struct sk_buff *skb);
  61
  62static int (*state[])(struct irlan_cb *, IRLAN_EVENT event, struct sk_buff *) =
  63{
  64        irlan_client_state_idle,
  65        irlan_client_state_query,
  66        irlan_client_state_conn,
  67        irlan_client_state_info,
  68        irlan_client_state_media,
  69        irlan_client_state_open,
  70        irlan_client_state_wait,
  71        irlan_client_state_arb,
  72        irlan_client_state_data,
  73        irlan_client_state_close,
  74        irlan_client_state_sync
  75};
  76
  77void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event,
  78                           struct sk_buff *skb)
  79{
  80        IRDA_ASSERT(self != NULL, return;);
  81        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
  82
  83        (*state[ self->client.state]) (self, event, skb);
  84}
  85
  86/*
  87 * Function irlan_client_state_idle (event, skb, info)
  88 *
  89 *    IDLE, We are waiting for an indication that there is a provider
  90 *    available.
  91 */
  92static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
  93                                   struct sk_buff *skb)
  94{
  95        IRDA_ASSERT(self != NULL, return -1;);
  96        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
  97
  98        switch (event) {
  99        case IRLAN_DISCOVERY_INDICATION:
 100                if (self->client.iriap) {
 101                        net_warn_ratelimited("%s(), busy with a previous query\n",
 102                                             __func__);
 103                        return -EBUSY;
 104                }
 105
 106                self->client.iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
 107                                                irlan_client_get_value_confirm);
 108                /* Get some values from peer IAS */
 109                irlan_next_client_state(self, IRLAN_QUERY);
 110                iriap_getvaluebyclass_request(self->client.iriap,
 111                                              self->saddr, self->daddr,
 112                                              "IrLAN", "IrDA:TinyTP:LsapSel");
 113                break;
 114        case IRLAN_WATCHDOG_TIMEOUT:
 115                pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
 116                break;
 117        default:
 118                pr_debug("%s(), Unknown event %d\n", __func__ , event);
 119                break;
 120        }
 121        if (skb)
 122                dev_kfree_skb(skb);
 123
 124        return 0;
 125}
 126
 127/*
 128 * Function irlan_client_state_query (event, skb, info)
 129 *
 130 *    QUERY, We have queryed the remote IAS and is ready to connect
 131 *    to provider, just waiting for the confirm.
 132 *
 133 */
 134static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
 135                                    struct sk_buff *skb)
 136{
 137        IRDA_ASSERT(self != NULL, return -1;);
 138        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
 139
 140        switch(event) {
 141        case IRLAN_IAS_PROVIDER_AVAIL:
 142                IRDA_ASSERT(self->dtsap_sel_ctrl != 0, return -1;);
 143
 144                self->client.open_retries = 0;
 145
 146                irttp_connect_request(self->client.tsap_ctrl,
 147                                      self->dtsap_sel_ctrl,
 148                                      self->saddr, self->daddr, NULL,
 149                                      IRLAN_MTU, NULL);
 150                irlan_next_client_state(self, IRLAN_CONN);
 151                break;
 152        case IRLAN_IAS_PROVIDER_NOT_AVAIL:
 153                pr_debug("%s(), IAS_PROVIDER_NOT_AVAIL\n", __func__);
 154                irlan_next_client_state(self, IRLAN_IDLE);
 155
 156                /* Give the client a kick! */
 157                if ((self->provider.access_type == ACCESS_PEER) &&
 158                    (self->provider.state != IRLAN_IDLE))
 159                        irlan_client_wakeup(self, self->saddr, self->daddr);
 160                break;
 161        case IRLAN_LMP_DISCONNECT:
 162        case IRLAN_LAP_DISCONNECT:
 163                irlan_next_client_state(self, IRLAN_IDLE);
 164                break;
 165        case IRLAN_WATCHDOG_TIMEOUT:
 166                pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
 167                break;
 168        default:
 169                pr_debug("%s(), Unknown event %d\n", __func__ , event);
 170                break;
 171        }
 172        if (skb)
 173                dev_kfree_skb(skb);
 174
 175        return 0;
 176}
 177
 178/*
 179 * Function irlan_client_state_conn (event, skb, info)
 180 *
 181 *    CONN, We have connected to a provider but has not issued any
 182 *    commands yet.
 183 *
 184 */
 185static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event,
 186                                   struct sk_buff *skb)
 187{
 188        IRDA_ASSERT(self != NULL, return -1;);
 189
 190        switch (event) {
 191        case IRLAN_CONNECT_COMPLETE:
 192                /* Send getinfo cmd */
 193                irlan_get_provider_info(self);
 194                irlan_next_client_state(self, IRLAN_INFO);
 195                break;
 196        case IRLAN_LMP_DISCONNECT:
 197        case IRLAN_LAP_DISCONNECT:
 198                irlan_next_client_state(self, IRLAN_IDLE);
 199                break;
 200        case IRLAN_WATCHDOG_TIMEOUT:
 201                pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
 202                break;
 203        default:
 204                pr_debug("%s(), Unknown event %d\n", __func__ , event);
 205                break;
 206        }
 207        if (skb)
 208                dev_kfree_skb(skb);
 209
 210        return 0;
 211}
 212
 213/*
 214 * Function irlan_client_state_info (self, event, skb, info)
 215 *
 216 *    INFO, We have issued a GetInfo command and is awaiting a reply.
 217 */
 218static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event,
 219                                   struct sk_buff *skb)
 220{
 221        IRDA_ASSERT(self != NULL, return -1;);
 222
 223        switch (event) {
 224        case IRLAN_DATA_INDICATION:
 225                IRDA_ASSERT(skb != NULL, return -1;);
 226
 227                irlan_client_parse_response(self, skb);
 228
 229                irlan_next_client_state(self, IRLAN_MEDIA);
 230
 231                irlan_get_media_char(self);
 232                break;
 233
 234        case IRLAN_LMP_DISCONNECT:
 235        case IRLAN_LAP_DISCONNECT:
 236                irlan_next_client_state(self, IRLAN_IDLE);
 237                break;
 238        case IRLAN_WATCHDOG_TIMEOUT:
 239                pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
 240                break;
 241        default:
 242                pr_debug("%s(), Unknown event %d\n", __func__ , event);
 243                break;
 244        }
 245        if (skb)
 246                dev_kfree_skb(skb);
 247
 248        return 0;
 249}
 250
 251/*
 252 * Function irlan_client_state_media (self, event, skb, info)
 253 *
 254 *    MEDIA, The irlan_client has issued a GetMedia command and is awaiting a
 255 *    reply.
 256 *
 257 */
 258static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
 259                                    struct sk_buff *skb)
 260{
 261        IRDA_ASSERT(self != NULL, return -1;);
 262
 263        switch(event) {
 264        case IRLAN_DATA_INDICATION:
 265                irlan_client_parse_response(self, skb);
 266                irlan_open_data_channel(self);
 267                irlan_next_client_state(self, IRLAN_OPEN);
 268                break;
 269        case IRLAN_LMP_DISCONNECT:
 270        case IRLAN_LAP_DISCONNECT:
 271                irlan_next_client_state(self, IRLAN_IDLE);
 272                break;
 273        case IRLAN_WATCHDOG_TIMEOUT:
 274                pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
 275                break;
 276        default:
 277                pr_debug("%s(), Unknown event %d\n", __func__ , event);
 278                break;
 279        }
 280        if (skb)
 281                dev_kfree_skb(skb);
 282
 283        return 0;
 284}
 285
 286/*
 287 * Function irlan_client_state_open (self, event, skb, info)
 288 *
 289 *    OPEN, The irlan_client has issued a OpenData command and is awaiting a
 290 *    reply
 291 *
 292 */
 293static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event,
 294                                   struct sk_buff *skb)
 295{
 296        struct qos_info qos;
 297
 298        IRDA_ASSERT(self != NULL, return -1;);
 299
 300        switch(event) {
 301        case IRLAN_DATA_INDICATION:
 302                irlan_client_parse_response(self, skb);
 303
 304                /*
 305                 *  Check if we have got the remote TSAP for data
 306                 *  communications
 307                 */
 308                IRDA_ASSERT(self->dtsap_sel_data != 0, return -1;);
 309
 310                /* Check which access type we are dealing with */
 311                switch (self->client.access_type) {
 312                case ACCESS_PEER:
 313                    if (self->provider.state == IRLAN_OPEN) {
 314
 315                            irlan_next_client_state(self, IRLAN_ARB);
 316                            irlan_do_client_event(self, IRLAN_CHECK_CON_ARB,
 317                                                  NULL);
 318                    } else {
 319
 320                            irlan_next_client_state(self, IRLAN_WAIT);
 321                    }
 322                    break;
 323                case ACCESS_DIRECT:
 324                case ACCESS_HOSTED:
 325                        qos.link_disc_time.bits = 0x01; /* 3 secs */
 326
 327                        irttp_connect_request(self->tsap_data,
 328                                              self->dtsap_sel_data,
 329                                              self->saddr, self->daddr, &qos,
 330                                              IRLAN_MTU, NULL);
 331
 332                        irlan_next_client_state(self, IRLAN_DATA);
 333                        break;
 334                default:
 335                        pr_debug("%s(), unknown access type!\n", __func__);
 336                        break;
 337                }
 338                break;
 339        case IRLAN_LMP_DISCONNECT:
 340        case IRLAN_LAP_DISCONNECT:
 341                irlan_next_client_state(self, IRLAN_IDLE);
 342                break;
 343        case IRLAN_WATCHDOG_TIMEOUT:
 344                pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
 345                break;
 346        default:
 347                pr_debug("%s(), Unknown event %d\n", __func__ , event);
 348                break;
 349        }
 350
 351        if (skb)
 352                dev_kfree_skb(skb);
 353
 354        return 0;
 355}
 356
 357/*
 358 * Function irlan_client_state_wait (self, event, skb, info)
 359 *
 360 *    WAIT, The irlan_client is waiting for the local provider to enter the
 361 *    provider OPEN state.
 362 *
 363 */
 364static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event,
 365                                   struct sk_buff *skb)
 366{
 367        IRDA_ASSERT(self != NULL, return -1;);
 368
 369        switch(event) {
 370        case IRLAN_PROVIDER_SIGNAL:
 371                irlan_next_client_state(self, IRLAN_ARB);
 372                irlan_do_client_event(self, IRLAN_CHECK_CON_ARB, NULL);
 373                break;
 374        case IRLAN_LMP_DISCONNECT:
 375        case IRLAN_LAP_DISCONNECT:
 376                irlan_next_client_state(self, IRLAN_IDLE);
 377                break;
 378        case IRLAN_WATCHDOG_TIMEOUT:
 379                pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
 380                break;
 381        default:
 382                pr_debug("%s(), Unknown event %d\n", __func__ , event);
 383                break;
 384        }
 385        if (skb)
 386                dev_kfree_skb(skb);
 387
 388        return 0;
 389}
 390
 391static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event,
 392                                  struct sk_buff *skb)
 393{
 394        struct qos_info qos;
 395
 396        IRDA_ASSERT(self != NULL, return -1;);
 397
 398        switch(event) {
 399        case IRLAN_CHECK_CON_ARB:
 400                if (self->client.recv_arb_val == self->provider.send_arb_val) {
 401                        irlan_next_client_state(self, IRLAN_CLOSE);
 402                        irlan_close_data_channel(self);
 403                } else if (self->client.recv_arb_val <
 404                           self->provider.send_arb_val)
 405                {
 406                        qos.link_disc_time.bits = 0x01; /* 3 secs */
 407
 408                        irlan_next_client_state(self, IRLAN_DATA);
 409                        irttp_connect_request(self->tsap_data,
 410                                              self->dtsap_sel_data,
 411                                              self->saddr, self->daddr, &qos,
 412                                              IRLAN_MTU, NULL);
 413                } else if (self->client.recv_arb_val >
 414                           self->provider.send_arb_val)
 415                {
 416                        pr_debug("%s(), lost the battle :-(\n", __func__);
 417                }
 418                break;
 419        case IRLAN_DATA_CONNECT_INDICATION:
 420                irlan_next_client_state(self, IRLAN_DATA);
 421                break;
 422        case IRLAN_LMP_DISCONNECT:
 423        case IRLAN_LAP_DISCONNECT:
 424                irlan_next_client_state(self, IRLAN_IDLE);
 425                break;
 426        case IRLAN_WATCHDOG_TIMEOUT:
 427                pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
 428                break;
 429        default:
 430                pr_debug("%s(), Unknown event %d\n", __func__ , event);
 431                break;
 432        }
 433        if (skb)
 434                dev_kfree_skb(skb);
 435
 436        return 0;
 437}
 438
 439/*
 440 * Function irlan_client_state_data (self, event, skb, info)
 441 *
 442 *    DATA, The data channel is connected, allowing data transfers between
 443 *    the local and remote machines.
 444 *
 445 */
 446static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event,
 447                                   struct sk_buff *skb)
 448{
 449        IRDA_ASSERT(self != NULL, return -1;);
 450        IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
 451
 452        switch(event) {
 453        case IRLAN_DATA_INDICATION:
 454                irlan_client_parse_response(self, skb);
 455                break;
 456        case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
 457        case IRLAN_LAP_DISCONNECT:
 458                irlan_next_client_state(self, IRLAN_IDLE);
 459                break;
 460        default:
 461                pr_debug("%s(), Unknown event %d\n", __func__ , event);
 462                break;
 463        }
 464        if (skb)
 465                dev_kfree_skb(skb);
 466
 467        return 0;
 468}
 469
 470/*
 471 * Function irlan_client_state_close (self, event, skb, info)
 472 *
 473 *
 474 *
 475 */
 476static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,
 477                                    struct sk_buff *skb)
 478{
 479        if (skb)
 480                dev_kfree_skb(skb);
 481
 482        return 0;
 483}
 484
 485/*
 486 * Function irlan_client_state_sync (self, event, skb, info)
 487 *
 488 *
 489 *
 490 */
 491static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event,
 492                                   struct sk_buff *skb)
 493{
 494        if (skb)
 495                dev_kfree_skb(skb);
 496
 497        return 0;
 498}
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512