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