linux/net/irda/irlmp_event.c
<<
>>
Prefs
   1/*********************************************************************
   2 *
   3 * Filename:      irlmp_event.c
   4 * Version:       0.8
   5 * Description:   An IrDA LMP event driver for Linux
   6 * Status:        Experimental.
   7 * Author:        Dag Brattli <dagb@cs.uit.no>
   8 * Created at:    Mon Aug  4 20:40:53 1997
   9 * Modified at:   Tue Dec 14 23:04:16 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/kernel.h>
  28
  29#include <net/irda/irda.h>
  30#include <net/irda/timer.h>
  31#include <net/irda/irlap.h>
  32#include <net/irda/irlmp.h>
  33#include <net/irda/irlmp_frame.h>
  34#include <net/irda/irlmp_event.h>
  35
  36const char *const irlmp_state[] = {
  37        "LAP_STANDBY",
  38        "LAP_U_CONNECT",
  39        "LAP_ACTIVE",
  40};
  41
  42const char *const irlsap_state[] = {
  43        "LSAP_DISCONNECTED",
  44        "LSAP_CONNECT",
  45        "LSAP_CONNECT_PEND",
  46        "LSAP_DATA_TRANSFER_READY",
  47        "LSAP_SETUP",
  48        "LSAP_SETUP_PEND",
  49};
  50
  51#ifdef CONFIG_IRDA_DEBUG
  52static const char *const irlmp_event[] = {
  53        "LM_CONNECT_REQUEST",
  54        "LM_CONNECT_CONFIRM",
  55        "LM_CONNECT_RESPONSE",
  56        "LM_CONNECT_INDICATION",
  57
  58        "LM_DISCONNECT_INDICATION",
  59        "LM_DISCONNECT_REQUEST",
  60
  61        "LM_DATA_REQUEST",
  62        "LM_UDATA_REQUEST",
  63        "LM_DATA_INDICATION",
  64        "LM_UDATA_INDICATION",
  65
  66        "LM_WATCHDOG_TIMEOUT",
  67
  68        /* IrLAP events */
  69        "LM_LAP_CONNECT_REQUEST",
  70        "LM_LAP_CONNECT_INDICATION",
  71        "LM_LAP_CONNECT_CONFIRM",
  72        "LM_LAP_DISCONNECT_INDICATION",
  73        "LM_LAP_DISCONNECT_REQUEST",
  74        "LM_LAP_DISCOVERY_REQUEST",
  75        "LM_LAP_DISCOVERY_CONFIRM",
  76        "LM_LAP_IDLE_TIMEOUT",
  77};
  78#endif  /* CONFIG_IRDA_DEBUG */
  79
  80/* LAP Connection control proto declarations */
  81static void irlmp_state_standby  (struct lap_cb *, IRLMP_EVENT,
  82                                  struct sk_buff *);
  83static void irlmp_state_u_connect(struct lap_cb *, IRLMP_EVENT,
  84                                  struct sk_buff *);
  85static void irlmp_state_active   (struct lap_cb *, IRLMP_EVENT,
  86                                  struct sk_buff *);
  87
  88/* LSAP Connection control proto declarations */
  89static int irlmp_state_disconnected(struct lsap_cb *, IRLMP_EVENT,
  90                                    struct sk_buff *);
  91static int irlmp_state_connect     (struct lsap_cb *, IRLMP_EVENT,
  92                                    struct sk_buff *);
  93static int irlmp_state_connect_pend(struct lsap_cb *, IRLMP_EVENT,
  94                                    struct sk_buff *);
  95static int irlmp_state_dtr         (struct lsap_cb *, IRLMP_EVENT,
  96                                    struct sk_buff *);
  97static int irlmp_state_setup       (struct lsap_cb *, IRLMP_EVENT,
  98                                    struct sk_buff *);
  99static int irlmp_state_setup_pend  (struct lsap_cb *, IRLMP_EVENT,
 100                                    struct sk_buff *);
 101
 102static void (*lap_state[]) (struct lap_cb *, IRLMP_EVENT, struct sk_buff *) =
 103{
 104        irlmp_state_standby,
 105        irlmp_state_u_connect,
 106        irlmp_state_active,
 107};
 108
 109static int (*lsap_state[])( struct lsap_cb *, IRLMP_EVENT, struct sk_buff *) =
 110{
 111        irlmp_state_disconnected,
 112        irlmp_state_connect,
 113        irlmp_state_connect_pend,
 114        irlmp_state_dtr,
 115        irlmp_state_setup,
 116        irlmp_state_setup_pend
 117};
 118
 119static inline void irlmp_next_lap_state(struct lap_cb *self,
 120                                        IRLMP_STATE state)
 121{
 122        /*
 123        IRDA_DEBUG(4, "%s(), LMP LAP = %s\n", __func__, irlmp_state[state]);
 124        */
 125        self->lap_state = state;
 126}
 127
 128static inline void irlmp_next_lsap_state(struct lsap_cb *self,
 129                                         LSAP_STATE state)
 130{
 131        /*
 132        IRDA_ASSERT(self != NULL, return;);
 133        IRDA_DEBUG(4, "%s(), LMP LSAP = %s\n", __func__, irlsap_state[state]);
 134        */
 135        self->lsap_state = state;
 136}
 137
 138/* Do connection control events */
 139int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event,
 140                        struct sk_buff *skb)
 141{
 142        IRDA_ASSERT(self != NULL, return -1;);
 143        IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 144
 145        IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n",
 146                __func__, irlmp_event[event], irlsap_state[ self->lsap_state]);
 147
 148        return (*lsap_state[self->lsap_state]) (self, event, skb);
 149}
 150
 151/*
 152 * Function do_lap_event (event, skb, info)
 153 *
 154 *    Do IrLAP control events
 155 *
 156 */
 157void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event,
 158                        struct sk_buff *skb)
 159{
 160        IRDA_ASSERT(self != NULL, return;);
 161        IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 162
 163        IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n", __func__,
 164                   irlmp_event[event],
 165                   irlmp_state[self->lap_state]);
 166
 167        (*lap_state[self->lap_state]) (self, event, skb);
 168}
 169
 170void irlmp_discovery_timer_expired(void *data)
 171{
 172        IRDA_DEBUG(4, "%s()\n", __func__);
 173
 174        /* We always cleanup the log (active & passive discovery) */
 175        irlmp_do_expiry();
 176
 177        irlmp_do_discovery(sysctl_discovery_slots);
 178
 179        /* Restart timer */
 180        irlmp_start_discovery_timer(irlmp, sysctl_discovery_timeout * HZ);
 181}
 182
 183void irlmp_watchdog_timer_expired(void *data)
 184{
 185        struct lsap_cb *self = (struct lsap_cb *) data;
 186
 187        IRDA_DEBUG(2, "%s()\n", __func__);
 188
 189        IRDA_ASSERT(self != NULL, return;);
 190        IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
 191
 192        irlmp_do_lsap_event(self, LM_WATCHDOG_TIMEOUT, NULL);
 193}
 194
 195void irlmp_idle_timer_expired(void *data)
 196{
 197        struct lap_cb *self = (struct lap_cb *) data;
 198
 199        IRDA_DEBUG(2, "%s()\n", __func__);
 200
 201        IRDA_ASSERT(self != NULL, return;);
 202        IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 203
 204        irlmp_do_lap_event(self, LM_LAP_IDLE_TIMEOUT, NULL);
 205}
 206
 207/*
 208 * Send an event on all LSAPs attached to this LAP.
 209 */
 210static inline void
 211irlmp_do_all_lsap_event(hashbin_t *     lsap_hashbin,
 212                        IRLMP_EVENT     event)
 213{
 214        struct lsap_cb *lsap;
 215        struct lsap_cb *lsap_next;
 216
 217        /* Note : this function use the new hashbin_find_next()
 218         * function, instead of the old hashbin_get_next().
 219         * This make sure that we are always pointing one lsap
 220         * ahead, so that if the current lsap is removed as the
 221         * result of sending the event, we don't care.
 222         * Also, as we store the context ourselves, if an enumeration
 223         * of the same lsap hashbin happens as the result of sending the
 224         * event, we don't care.
 225         * The only problem is if the next lsap is removed. In that case,
 226         * hashbin_find_next() will return NULL and we will abort the
 227         * enumeration. - Jean II */
 228
 229        /* Also : we don't accept any skb in input. We can *NOT* pass
 230         * the same skb to multiple clients safely, we would need to
 231         * skb_clone() it. - Jean II */
 232
 233        lsap = (struct lsap_cb *) hashbin_get_first(lsap_hashbin);
 234
 235        while (NULL != hashbin_find_next(lsap_hashbin,
 236                                         (long) lsap,
 237                                         NULL,
 238                                         (void *) &lsap_next) ) {
 239                irlmp_do_lsap_event(lsap, event, NULL);
 240                lsap = lsap_next;
 241        }
 242}
 243
 244/*********************************************************************
 245 *
 246 *    LAP connection control states
 247 *
 248 ********************************************************************/
 249
 250/*
 251 * Function irlmp_state_standby (event, skb, info)
 252 *
 253 *    STANDBY, The IrLAP connection does not exist.
 254 *
 255 */
 256static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event,
 257                                struct sk_buff *skb)
 258{
 259        IRDA_DEBUG(4, "%s()\n", __func__);
 260        IRDA_ASSERT(self->irlap != NULL, return;);
 261
 262        switch (event) {
 263        case LM_LAP_DISCOVERY_REQUEST:
 264                /* irlmp_next_station_state( LMP_DISCOVER); */
 265
 266                irlap_discovery_request(self->irlap, &irlmp->discovery_cmd);
 267                break;
 268        case LM_LAP_CONNECT_INDICATION:
 269                /*  It's important to switch state first, to avoid IrLMP to
 270                 *  think that the link is free since IrLMP may then start
 271                 *  discovery before the connection is properly set up. DB.
 272                 */
 273                irlmp_next_lap_state(self, LAP_ACTIVE);
 274
 275                /* Just accept connection TODO, this should be fixed */
 276                irlap_connect_response(self->irlap, skb);
 277                break;
 278        case LM_LAP_CONNECT_REQUEST:
 279                IRDA_DEBUG(4, "%s() LS_CONNECT_REQUEST\n", __func__);
 280
 281                irlmp_next_lap_state(self, LAP_U_CONNECT);
 282
 283                /* FIXME: need to set users requested QoS */
 284                irlap_connect_request(self->irlap, self->daddr, NULL, 0);
 285                break;
 286        case LM_LAP_DISCONNECT_INDICATION:
 287                IRDA_DEBUG(4, "%s(), Error LM_LAP_DISCONNECT_INDICATION\n",
 288                           __func__);
 289
 290                irlmp_next_lap_state(self, LAP_STANDBY);
 291                break;
 292        default:
 293                IRDA_DEBUG(0, "%s(), Unknown event %s\n",
 294                           __func__, irlmp_event[event]);
 295                break;
 296        }
 297}
 298
 299/*
 300 * Function irlmp_state_u_connect (event, skb, info)
 301 *
 302 *    U_CONNECT, The layer above has tried to open an LSAP connection but
 303 *    since the IrLAP connection does not exist, we must first start an
 304 *    IrLAP connection. We are now waiting response from IrLAP.
 305 * */
 306static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,
 307                                  struct sk_buff *skb)
 308{
 309        IRDA_DEBUG(2, "%s(), event=%s\n", __func__, irlmp_event[event]);
 310
 311        switch (event) {
 312        case LM_LAP_CONNECT_INDICATION:
 313                /*  It's important to switch state first, to avoid IrLMP to
 314                 *  think that the link is free since IrLMP may then start
 315                 *  discovery before the connection is properly set up. DB.
 316                 */
 317                irlmp_next_lap_state(self, LAP_ACTIVE);
 318
 319                /* Just accept connection TODO, this should be fixed */
 320                irlap_connect_response(self->irlap, skb);
 321
 322                /* Tell LSAPs that they can start sending data */
 323                irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM);
 324
 325                /* Note : by the time we get there (LAP retries and co),
 326                 * the lsaps may already have gone. This avoid getting stuck
 327                 * forever in LAP_ACTIVE state - Jean II */
 328                if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
 329                        IRDA_DEBUG(0, "%s() NO LSAPs !\n",  __func__);
 330                        irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
 331                }
 332                break;
 333        case LM_LAP_CONNECT_REQUEST:
 334                /* Already trying to connect */
 335                break;
 336        case LM_LAP_CONNECT_CONFIRM:
 337                /* For all lsap_ce E Associated do LS_Connect_confirm */
 338                irlmp_next_lap_state(self, LAP_ACTIVE);
 339
 340                /* Tell LSAPs that they can start sending data */
 341                irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM);
 342
 343                /* Note : by the time we get there (LAP retries and co),
 344                 * the lsaps may already have gone. This avoid getting stuck
 345                 * forever in LAP_ACTIVE state - Jean II */
 346                if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
 347                        IRDA_DEBUG(0, "%s() NO LSAPs !\n",  __func__);
 348                        irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
 349                }
 350                break;
 351        case LM_LAP_DISCONNECT_INDICATION:
 352                IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_INDICATION\n",  __func__);
 353                irlmp_next_lap_state(self, LAP_STANDBY);
 354
 355                /* Send disconnect event to all LSAPs using this link */
 356                irlmp_do_all_lsap_event(self->lsaps,
 357                                        LM_LAP_DISCONNECT_INDICATION);
 358                break;
 359        case LM_LAP_DISCONNECT_REQUEST:
 360                IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_REQUEST\n",  __func__);
 361
 362                /* One of the LSAP did timeout or was closed, if it was
 363                 * the last one, try to get out of here - Jean II */
 364                if (HASHBIN_GET_SIZE(self->lsaps) <= 1) {
 365                        irlap_disconnect_request(self->irlap);
 366                }
 367                break;
 368        default:
 369                IRDA_DEBUG(0, "%s(), Unknown event %s\n",
 370                         __func__, irlmp_event[event]);
 371                break;
 372        }
 373}
 374
 375/*
 376 * Function irlmp_state_active (event, skb, info)
 377 *
 378 *    ACTIVE, IrLAP connection is active
 379 *
 380 */
 381static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
 382                               struct sk_buff *skb)
 383{
 384        IRDA_DEBUG(4, "%s()\n", __func__);
 385
 386        switch (event) {
 387        case LM_LAP_CONNECT_REQUEST:
 388                IRDA_DEBUG(4, "%s(), LS_CONNECT_REQUEST\n", __func__);
 389
 390                /*
 391                 * IrLAP may have a pending disconnect. We tried to close
 392                 * IrLAP, but it was postponed because the link was
 393                 * busy or we were still sending packets. As we now
 394                 * need it, make sure it stays on. Jean II
 395                 */
 396                irlap_clear_disconnect(self->irlap);
 397
 398                /*
 399                 *  LAP connection already active, just bounce back! Since we
 400                 *  don't know which LSAP that tried to do this, we have to
 401                 *  notify all LSAPs using this LAP, but that should be safe to
 402                 *  do anyway.
 403                 */
 404                irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM);
 405
 406                /* Needed by connect indication */
 407                irlmp_do_all_lsap_event(irlmp->unconnected_lsaps,
 408                                        LM_LAP_CONNECT_CONFIRM);
 409                /* Keep state */
 410                break;
 411        case LM_LAP_DISCONNECT_REQUEST:
 412                /*
 413                 *  Need to find out if we should close IrLAP or not. If there
 414                 *  is only one LSAP connection left on this link, that LSAP
 415                 *  must be the one that tries to close IrLAP. It will be
 416                 *  removed later and moved to the list of unconnected LSAPs
 417                 */
 418                if (HASHBIN_GET_SIZE(self->lsaps) > 0) {
 419                        /* Timer value is checked in irsysctl - Jean II */
 420                        irlmp_start_idle_timer(self, sysctl_lap_keepalive_time * HZ / 1000);
 421                } else {
 422                        /* No more connections, so close IrLAP */
 423
 424                        /* We don't want to change state just yet, because
 425                         * we want to reflect accurately the real state of
 426                         * the LAP, not the state we wish it was in,
 427                         * so that we don't lose LM_LAP_CONNECT_REQUEST.
 428                         * In some cases, IrLAP won't close the LAP
 429                         * immediately. For example, it might still be
 430                         * retrying packets or waiting for the pf bit.
 431                         * As the LAP always send a DISCONNECT_INDICATION
 432                         * in PCLOSE or SCLOSE, just change state on that.
 433                         * Jean II */
 434                        irlap_disconnect_request(self->irlap);
 435                }
 436                break;
 437        case LM_LAP_IDLE_TIMEOUT:
 438                if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
 439                        /* Same reasoning as above - keep state */
 440                        irlap_disconnect_request(self->irlap);
 441                }
 442                break;
 443        case LM_LAP_DISCONNECT_INDICATION:
 444                irlmp_next_lap_state(self, LAP_STANDBY);
 445
 446                /* In some case, at this point our side has already closed
 447                 * all lsaps, and we are waiting for the idle_timer to
 448                 * expire. If another device reconnect immediately, the
 449                 * idle timer will expire in the midle of the connection
 450                 * initialisation, screwing up things a lot...
 451                 * Therefore, we must stop the timer... */
 452                irlmp_stop_idle_timer(self);
 453
 454                /*
 455                 *  Inform all connected LSAP's using this link
 456                 */
 457                irlmp_do_all_lsap_event(self->lsaps,
 458                                        LM_LAP_DISCONNECT_INDICATION);
 459
 460                /* Force an expiry of the discovery log.
 461                 * Now that the LAP is free, the system may attempt to
 462                 * connect to another device. Unfortunately, our entries
 463                 * are stale. There is a small window (<3s) before the
 464                 * normal discovery will run and where irlmp_connect_request()
 465                 * can get the wrong info, so make sure things get
 466                 * cleaned *NOW* ;-) - Jean II */
 467                irlmp_do_expiry();
 468                break;
 469        default:
 470                IRDA_DEBUG(0, "%s(), Unknown event %s\n",
 471                         __func__, irlmp_event[event]);
 472                break;
 473        }
 474}
 475
 476/*********************************************************************
 477 *
 478 *    LSAP connection control states
 479 *
 480 ********************************************************************/
 481
 482/*
 483 * Function irlmp_state_disconnected (event, skb, info)
 484 *
 485 *    DISCONNECTED
 486 *
 487 */
 488static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
 489                                    struct sk_buff *skb)
 490{
 491        int ret = 0;
 492
 493        IRDA_DEBUG(4, "%s()\n", __func__);
 494
 495        IRDA_ASSERT(self != NULL, return -1;);
 496        IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 497
 498        switch (event) {
 499#ifdef CONFIG_IRDA_ULTRA
 500        case LM_UDATA_INDICATION:
 501                /* This is most bizarre. Those packets are  aka unreliable
 502                 * connected, aka IrLPT or SOCK_DGRAM/IRDAPROTO_UNITDATA.
 503                 * Why do we pass them as Ultra ??? Jean II */
 504                irlmp_connless_data_indication(self, skb);
 505                break;
 506#endif /* CONFIG_IRDA_ULTRA */
 507        case LM_CONNECT_REQUEST:
 508                IRDA_DEBUG(4, "%s(), LM_CONNECT_REQUEST\n", __func__);
 509
 510                if (self->conn_skb) {
 511                        IRDA_WARNING("%s: busy with another request!\n",
 512                                     __func__);
 513                        return -EBUSY;
 514                }
 515                /* Don't forget to refcount it (see irlmp_connect_request()) */
 516                skb_get(skb);
 517                self->conn_skb = skb;
 518
 519                irlmp_next_lsap_state(self, LSAP_SETUP_PEND);
 520
 521                /* Start watchdog timer (5 secs for now) */
 522                irlmp_start_watchdog_timer(self, 5*HZ);
 523
 524                irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
 525                break;
 526        case LM_CONNECT_INDICATION:
 527                if (self->conn_skb) {
 528                        IRDA_WARNING("%s: busy with another request!\n",
 529                                     __func__);
 530                        return -EBUSY;
 531                }
 532                /* Don't forget to refcount it (see irlap_driver_rcv()) */
 533                skb_get(skb);
 534                self->conn_skb = skb;
 535
 536                irlmp_next_lsap_state(self, LSAP_CONNECT_PEND);
 537
 538                /* Start watchdog timer
 539                 * This is not mentionned in the spec, but there is a rare
 540                 * race condition that can get the socket stuck.
 541                 * If we receive this event while our LAP is closing down,
 542                 * the LM_LAP_CONNECT_REQUEST get lost and we get stuck in
 543                 * CONNECT_PEND state forever.
 544                 * The other cause of getting stuck down there is if the
 545                 * higher layer never reply to the CONNECT_INDICATION.
 546                 * Anyway, it make sense to make sure that we always have
 547                 * a backup plan. 1 second is plenty (should be immediate).
 548                 * Jean II */
 549                irlmp_start_watchdog_timer(self, 1*HZ);
 550
 551                irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
 552                break;
 553        default:
 554                IRDA_DEBUG(1, "%s(), Unknown event %s on LSAP %#02x\n",
 555                           __func__, irlmp_event[event], self->slsap_sel);
 556                break;
 557        }
 558        return ret;
 559}
 560
 561/*
 562 * Function irlmp_state_connect (self, event, skb)
 563 *
 564 *    CONNECT
 565 *
 566 */
 567static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event,
 568                                struct sk_buff *skb)
 569{
 570        struct lsap_cb *lsap;
 571        int ret = 0;
 572
 573        IRDA_DEBUG(4, "%s()\n", __func__);
 574
 575        IRDA_ASSERT(self != NULL, return -1;);
 576        IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 577
 578        switch (event) {
 579        case LM_CONNECT_RESPONSE:
 580                /*
 581                 *  Bind this LSAP to the IrLAP link where the connect was
 582                 *  received
 583                 */
 584                lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self,
 585                                      NULL);
 586
 587                IRDA_ASSERT(lsap == self, return -1;);
 588                IRDA_ASSERT(self->lap != NULL, return -1;);
 589                IRDA_ASSERT(self->lap->lsaps != NULL, return -1;);
 590
 591                hashbin_insert(self->lap->lsaps, (irda_queue_t *) self,
 592                               (long) self, NULL);
 593
 594                set_bit(0, &self->connected);   /* TRUE */
 595
 596                irlmp_send_lcf_pdu(self->lap, self->dlsap_sel,
 597                                   self->slsap_sel, CONNECT_CNF, skb);
 598
 599                del_timer(&self->watchdog_timer);
 600
 601                irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY);
 602                break;
 603        case LM_WATCHDOG_TIMEOUT:
 604                /* May happen, who knows...
 605                 * Jean II */
 606                IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n",  __func__);
 607
 608                /* Disconnect, get out... - Jean II */
 609                self->lap = NULL;
 610                self->dlsap_sel = LSAP_ANY;
 611                irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 612                break;
 613        default:
 614                /* LM_LAP_DISCONNECT_INDICATION : Should never happen, we
 615                 * are *not* yet bound to the IrLAP link. Jean II */
 616                IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
 617                           __func__, irlmp_event[event], self->slsap_sel);
 618                break;
 619        }
 620        return ret;
 621}
 622
 623/*
 624 * Function irlmp_state_connect_pend (event, skb, info)
 625 *
 626 *    CONNECT_PEND
 627 *
 628 */
 629static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
 630                                    struct sk_buff *skb)
 631{
 632        struct sk_buff *tx_skb;
 633        int ret = 0;
 634
 635        IRDA_DEBUG(4, "%s()\n", __func__);
 636
 637        IRDA_ASSERT(self != NULL, return -1;);
 638        IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 639
 640        switch (event) {
 641        case LM_CONNECT_REQUEST:
 642                /* Keep state */
 643                break;
 644        case LM_CONNECT_RESPONSE:
 645                IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, "
 646                           "no indication issued yet\n",  __func__);
 647                /* Keep state */
 648                break;
 649        case LM_DISCONNECT_REQUEST:
 650                IRDA_DEBUG(0, "%s(), LM_DISCONNECT_REQUEST, "
 651                           "not yet bound to IrLAP connection\n",  __func__);
 652                /* Keep state */
 653                break;
 654        case LM_LAP_CONNECT_CONFIRM:
 655                IRDA_DEBUG(4, "%s(), LS_CONNECT_CONFIRM\n",  __func__);
 656                irlmp_next_lsap_state(self, LSAP_CONNECT);
 657
 658                tx_skb = self->conn_skb;
 659                self->conn_skb = NULL;
 660
 661                irlmp_connect_indication(self, tx_skb);
 662                /* Drop reference count - see irlmp_connect_indication(). */
 663                dev_kfree_skb(tx_skb);
 664                break;
 665        case LM_WATCHDOG_TIMEOUT:
 666                /* Will happen in some rare cases because of a race condition.
 667                 * Just make sure we don't stay there forever...
 668                 * Jean II */
 669                IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n",  __func__);
 670
 671                /* Go back to disconnected mode, keep the socket waiting */
 672                self->lap = NULL;
 673                self->dlsap_sel = LSAP_ANY;
 674                if(self->conn_skb)
 675                        dev_kfree_skb(self->conn_skb);
 676                self->conn_skb = NULL;
 677                irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 678                break;
 679        default:
 680                /* LM_LAP_DISCONNECT_INDICATION : Should never happen, we
 681                 * are *not* yet bound to the IrLAP link. Jean II */
 682                IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
 683                           __func__, irlmp_event[event], self->slsap_sel);
 684                break;
 685        }
 686        return ret;
 687}
 688
 689/*
 690 * Function irlmp_state_dtr (self, event, skb)
 691 *
 692 *    DATA_TRANSFER_READY
 693 *
 694 */
 695static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event,
 696                           struct sk_buff *skb)
 697{
 698        LM_REASON reason;
 699        int ret = 0;
 700
 701        IRDA_DEBUG(4, "%s()\n", __func__);
 702
 703        IRDA_ASSERT(self != NULL, return -1;);
 704        IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 705        IRDA_ASSERT(self->lap != NULL, return -1;);
 706
 707        switch (event) {
 708        case LM_DATA_REQUEST: /* Optimize for the common case */
 709                irlmp_send_data_pdu(self->lap, self->dlsap_sel,
 710                                    self->slsap_sel, FALSE, skb);
 711                break;
 712        case LM_DATA_INDICATION: /* Optimize for the common case */
 713                irlmp_data_indication(self, skb);
 714                break;
 715        case LM_UDATA_REQUEST:
 716                IRDA_ASSERT(skb != NULL, return -1;);
 717                irlmp_send_data_pdu(self->lap, self->dlsap_sel,
 718                                    self->slsap_sel, TRUE, skb);
 719                break;
 720        case LM_UDATA_INDICATION:
 721                irlmp_udata_indication(self, skb);
 722                break;
 723        case LM_CONNECT_REQUEST:
 724                IRDA_DEBUG(0, "%s(), LM_CONNECT_REQUEST, "
 725                           "error, LSAP already connected\n", __func__);
 726                /* Keep state */
 727                break;
 728        case LM_CONNECT_RESPONSE:
 729                IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, "
 730                           "error, LSAP already connected\n", __func__);
 731                /* Keep state */
 732                break;
 733        case LM_DISCONNECT_REQUEST:
 734                irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, self->slsap_sel,
 735                                   DISCONNECT, skb);
 736                irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 737                /* Called only from irlmp_disconnect_request(), will
 738                 * unbind from LAP over there. Jean II */
 739
 740                /* Try to close the LAP connection if its still there */
 741                if (self->lap) {
 742                        IRDA_DEBUG(4, "%s(), trying to close IrLAP\n",
 743                                   __func__);
 744                        irlmp_do_lap_event(self->lap,
 745                                           LM_LAP_DISCONNECT_REQUEST,
 746                                           NULL);
 747                }
 748                break;
 749        case LM_LAP_DISCONNECT_INDICATION:
 750                irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 751
 752                reason = irlmp_convert_lap_reason(self->lap->reason);
 753
 754                irlmp_disconnect_indication(self, reason, NULL);
 755                break;
 756        case LM_DISCONNECT_INDICATION:
 757                irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 758
 759                IRDA_ASSERT(self->lap != NULL, return -1;);
 760                IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
 761
 762                IRDA_ASSERT(skb != NULL, return -1;);
 763                IRDA_ASSERT(skb->len > 3, return -1;);
 764                reason = skb->data[3];
 765
 766                 /* Try to close the LAP connection */
 767                IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __func__);
 768                irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
 769
 770                irlmp_disconnect_indication(self, reason, skb);
 771                break;
 772        default:
 773                IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
 774                           __func__, irlmp_event[event], self->slsap_sel);
 775                break;
 776        }
 777        return ret;
 778}
 779
 780/*
 781 * Function irlmp_state_setup (event, skb, info)
 782 *
 783 *    SETUP, Station Control has set up the underlying IrLAP connection.
 784 *    An LSAP connection request has been transmitted to the peer
 785 *    LSAP-Connection Control FSM and we are awaiting reply.
 786 */
 787static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event,
 788                             struct sk_buff *skb)
 789{
 790        LM_REASON reason;
 791        int ret = 0;
 792
 793        IRDA_ASSERT(self != NULL, return -1;);
 794        IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 795
 796        IRDA_DEBUG(4, "%s()\n", __func__);
 797
 798        switch (event) {
 799        case LM_CONNECT_CONFIRM:
 800                irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY);
 801
 802                del_timer(&self->watchdog_timer);
 803
 804                irlmp_connect_confirm(self, skb);
 805                break;
 806        case LM_DISCONNECT_INDICATION:
 807                irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 808
 809                IRDA_ASSERT(self->lap != NULL, return -1;);
 810                IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
 811
 812                IRDA_ASSERT(skb != NULL, return -1;);
 813                IRDA_ASSERT(skb->len > 3, return -1;);
 814                reason = skb->data[3];
 815
 816                 /* Try to close the LAP connection */
 817                IRDA_DEBUG(4, "%s(), trying to close IrLAP\n",  __func__);
 818                irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
 819
 820                irlmp_disconnect_indication(self, reason, skb);
 821                break;
 822        case LM_LAP_DISCONNECT_INDICATION:
 823                irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 824
 825                del_timer(&self->watchdog_timer);
 826
 827                IRDA_ASSERT(self->lap != NULL, return -1;);
 828                IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
 829
 830                reason = irlmp_convert_lap_reason(self->lap->reason);
 831
 832                irlmp_disconnect_indication(self, reason, skb);
 833                break;
 834        case LM_WATCHDOG_TIMEOUT:
 835                IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __func__);
 836
 837                IRDA_ASSERT(self->lap != NULL, return -1;);
 838                irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
 839                irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 840
 841                irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL);
 842                break;
 843        default:
 844                IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
 845                           __func__, irlmp_event[event], self->slsap_sel);
 846                break;
 847        }
 848        return ret;
 849}
 850
 851/*
 852 * Function irlmp_state_setup_pend (event, skb, info)
 853 *
 854 *    SETUP_PEND, An LM_CONNECT_REQUEST has been received from the service
 855 *    user to set up an LSAP connection. A request has been sent to the
 856 *    LAP FSM to set up the underlying IrLAP connection, and we
 857 *    are awaiting confirm.
 858 */
 859static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event,
 860                                  struct sk_buff *skb)
 861{
 862        struct sk_buff *tx_skb;
 863        LM_REASON reason;
 864        int ret = 0;
 865
 866        IRDA_DEBUG(4, "%s()\n", __func__);
 867
 868        IRDA_ASSERT(self != NULL, return -1;);
 869        IRDA_ASSERT(irlmp != NULL, return -1;);
 870
 871        switch (event) {
 872        case LM_LAP_CONNECT_CONFIRM:
 873                IRDA_ASSERT(self->conn_skb != NULL, return -1;);
 874
 875                tx_skb = self->conn_skb;
 876                self->conn_skb = NULL;
 877
 878                irlmp_send_lcf_pdu(self->lap, self->dlsap_sel,
 879                                   self->slsap_sel, CONNECT_CMD, tx_skb);
 880                /* Drop reference count - see irlap_data_request(). */
 881                dev_kfree_skb(tx_skb);
 882
 883                irlmp_next_lsap_state(self, LSAP_SETUP);
 884                break;
 885        case LM_WATCHDOG_TIMEOUT:
 886                IRDA_DEBUG(0, "%s() : WATCHDOG_TIMEOUT !\n",  __func__);
 887
 888                IRDA_ASSERT(self->lap != NULL, return -1;);
 889                irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
 890                irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 891
 892                irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL);
 893                break;
 894        case LM_LAP_DISCONNECT_INDICATION: /* LS_Disconnect.indication */
 895                del_timer( &self->watchdog_timer);
 896
 897                irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 898
 899                reason = irlmp_convert_lap_reason(self->lap->reason);
 900
 901                irlmp_disconnect_indication(self, reason, NULL);
 902                break;
 903        default:
 904                IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
 905                           __func__, irlmp_event[event], self->slsap_sel);
 906                break;
 907        }
 908        return ret;
 909}
 910
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.