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_DEBUG(4, "%s()\n", __FUNCTION__ ); 96 97 IRDA_ASSERT(self != NULL, return -1;); 98 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); 99 100 switch (event) { 101 case IRLAN_DISCOVERY_INDICATION: 102 if (self->client.iriap) { 103 IRDA_WARNING("%s(), busy with a previous query\n", 104 __FUNCTION__); 105 return -EBUSY; 106 } 107 108 self->client.iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, 109 irlan_client_get_value_confirm); 110 /* Get some values from peer IAS */ 111 irlan_next_client_state(self, IRLAN_QUERY); 112 iriap_getvaluebyclass_request(self->client.iriap, 113 self->saddr, self->daddr, 114 "IrLAN", "IrDA:TinyTP:LsapSel"); 115 break; 116 case IRLAN_WATCHDOG_TIMEOUT: 117 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); 118 break; 119 default: 120 IRDA_DEBUG(4, "%s(), Unknown event %d\n", __FUNCTION__ , event); 121 break; 122 } 123 if (skb) 124 dev_kfree_skb(skb); 125 126 return 0; 127} 128 129/* 130 * Function irlan_client_state_query (event, skb, info) 131 * 132 * QUERY, We have queryed the remote IAS and is ready to connect 133 * to provider, just waiting for the confirm. 134 * 135 */ 136static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event, 137 struct sk_buff *skb) 138{ 139 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); 140 141 IRDA_ASSERT(self != NULL, return -1;); 142 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); 143 144 switch(event) { 145 case IRLAN_IAS_PROVIDER_AVAIL: 146 IRDA_ASSERT(self->dtsap_sel_ctrl != 0, return -1;); 147 148 self->client.open_retries = 0; 149 150 irttp_connect_request(self->client.tsap_ctrl, 151 self->dtsap_sel_ctrl, 152 self->saddr, self->daddr, NULL, 153 IRLAN_MTU, NULL); 154 irlan_next_client_state(self, IRLAN_CONN); 155 break; 156 case IRLAN_IAS_PROVIDER_NOT_AVAIL: 157 IRDA_DEBUG(2, "%s(), IAS_PROVIDER_NOT_AVAIL\n", __FUNCTION__ ); 158 irlan_next_client_state(self, IRLAN_IDLE); 159 160 /* Give the client a kick! */ 161 if ((self->provider.access_type == ACCESS_PEER) && 162 (self->provider.state != IRLAN_IDLE)) 163 irlan_client_wakeup(self, self->saddr, self->daddr); 164 break; 165 case IRLAN_LMP_DISCONNECT: 166 case IRLAN_LAP_DISCONNECT: 167 irlan_next_client_state(self, IRLAN_IDLE); 168 break; 169 case IRLAN_WATCHDOG_TIMEOUT: 170 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); 171 break; 172 default: 173 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); 174 break; 175 } 176 if (skb) 177 dev_kfree_skb(skb); 178 179 return 0; 180} 181 182/* 183 * Function irlan_client_state_conn (event, skb, info) 184 * 185 * CONN, We have connected to a provider but has not issued any 186 * commands yet. 187 * 188 */ 189static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event, 190 struct sk_buff *skb) 191{ 192 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); 193 194 IRDA_ASSERT(self != NULL, return -1;); 195 196 switch (event) { 197 case IRLAN_CONNECT_COMPLETE: 198 /* Send getinfo cmd */ 199 irlan_get_provider_info(self); 200 irlan_next_client_state(self, IRLAN_INFO); 201 break; 202 case IRLAN_LMP_DISCONNECT: 203 case IRLAN_LAP_DISCONNECT: 204 irlan_next_client_state(self, IRLAN_IDLE); 205 break; 206 case IRLAN_WATCHDOG_TIMEOUT: 207 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); 208 break; 209 default: 210 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); 211 break; 212 } 213 if (skb) 214 dev_kfree_skb(skb); 215 216 return 0; 217} 218 219/* 220 * Function irlan_client_state_info (self, event, skb, info) 221 * 222 * INFO, We have issued a GetInfo command and is awaiting a reply. 223 */ 224static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event, 225 struct sk_buff *skb) 226{ 227 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); 228 229 IRDA_ASSERT(self != NULL, return -1;); 230 231 switch (event) { 232 case IRLAN_DATA_INDICATION: 233 IRDA_ASSERT(skb != NULL, return -1;); 234 235 irlan_client_parse_response(self, skb); 236 237 irlan_next_client_state(self, IRLAN_MEDIA); 238 239 irlan_get_media_char(self); 240 break; 241 242 case IRLAN_LMP_DISCONNECT: 243 case IRLAN_LAP_DISCONNECT: 244 irlan_next_client_state(self, IRLAN_IDLE); 245 break; 246 case IRLAN_WATCHDOG_TIMEOUT: 247 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); 248 break; 249 default: 250 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); 251 break; 252 } 253 if (skb) 254 dev_kfree_skb(skb); 255 256 return 0; 257} 258 259/* 260 * Function irlan_client_state_media (self, event, skb, info) 261 * 262 * MEDIA, The irlan_client has issued a GetMedia command and is awaiting a 263 * reply. 264 * 265 */ 266static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event, 267 struct sk_buff *skb) 268{ 269 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); 270 271 IRDA_ASSERT(self != NULL, return -1;); 272 273 switch(event) { 274 case IRLAN_DATA_INDICATION: 275 irlan_client_parse_response(self, skb); 276 irlan_open_data_channel(self); 277 irlan_next_client_state(self, IRLAN_OPEN); 278 break; 279 case IRLAN_LMP_DISCONNECT: 280 case IRLAN_LAP_DISCONNECT: 281 irlan_next_client_state(self, IRLAN_IDLE); 282 break; 283 case IRLAN_WATCHDOG_TIMEOUT: 284 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); 285 break; 286 default: 287 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); 288 break; 289 } 290 if (skb) 291 dev_kfree_skb(skb); 292 293 return 0; 294} 295 296/* 297 * Function irlan_client_state_open (self, event, skb, info) 298 * 299 * OPEN, The irlan_client has issued a OpenData command and is awaiting a 300 * reply 301 * 302 */ 303static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event, 304 struct sk_buff *skb) 305{ 306 struct qos_info qos; 307 308 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); 309 310 IRDA_ASSERT(self != NULL, return -1;); 311 312 switch(event) { 313 case IRLAN_DATA_INDICATION: 314 irlan_client_parse_response(self, skb); 315 316 /* 317 * Check if we have got the remote TSAP for data 318 * communications 319 */ 320 IRDA_ASSERT(self->dtsap_sel_data != 0, return -1;); 321 322 /* Check which access type we are dealing with */ 323 switch (self->client.access_type) { 324 case ACCESS_PEER: 325 if (self->provider.state == IRLAN_OPEN) { 326 327 irlan_next_client_state(self, IRLAN_ARB); 328 irlan_do_client_event(self, IRLAN_CHECK_CON_ARB, 329 NULL); 330 } else { 331 332 irlan_next_client_state(self, IRLAN_WAIT); 333 } 334 break; 335 case ACCESS_DIRECT: 336 case ACCESS_HOSTED: 337 qos.link_disc_time.bits = 0x01; /* 3 secs */ 338 339 irttp_connect_request(self->tsap_data, 340 self->dtsap_sel_data, 341 self->saddr, self->daddr, &qos, 342 IRLAN_MTU, NULL); 343 344 irlan_next_client_state(self, IRLAN_DATA); 345 break; 346 default: 347 IRDA_DEBUG(2, "%s(), unknown access type!\n", __FUNCTION__ ); 348 break; 349 } 350 break; 351 case IRLAN_LMP_DISCONNECT: 352 case IRLAN_LAP_DISCONNECT: 353 irlan_next_client_state(self, IRLAN_IDLE); 354 break; 355 case IRLAN_WATCHDOG_TIMEOUT: 356 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); 357 break; 358 default: 359 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); 360 break; 361 } 362 363 if (skb) 364 dev_kfree_skb(skb); 365 366 return 0; 367} 368 369/* 370 * Function irlan_client_state_wait (self, event, skb, info) 371 * 372 * WAIT, The irlan_client is waiting for the local provider to enter the 373 * provider OPEN state. 374 * 375 */ 376static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event, 377 struct sk_buff *skb) 378{ 379 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); 380 381 IRDA_ASSERT(self != NULL, return -1;); 382 383 switch(event) { 384 case IRLAN_PROVIDER_SIGNAL: 385 irlan_next_client_state(self, IRLAN_ARB); 386 irlan_do_client_event(self, IRLAN_CHECK_CON_ARB, NULL); 387 break; 388 case IRLAN_LMP_DISCONNECT: 389 case IRLAN_LAP_DISCONNECT: 390 irlan_next_client_state(self, IRLAN_IDLE); 391 break; 392 case IRLAN_WATCHDOG_TIMEOUT: 393 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); 394 break; 395 default: 396 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); 397 break; 398 } 399 if (skb) 400 dev_kfree_skb(skb); 401 402 return 0; 403} 404 405static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event, 406 struct sk_buff *skb) 407{ 408 struct qos_info qos; 409 410 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); 411 412 IRDA_ASSERT(self != NULL, return -1;); 413 414 switch(event) { 415 case IRLAN_CHECK_CON_ARB: 416 if (self->client.recv_arb_val == self->provider.send_arb_val) { 417 irlan_next_client_state(self, IRLAN_CLOSE); 418 irlan_close_data_channel(self); 419 } else if (self->client.recv_arb_val < 420 self->provider.send_arb_val) 421 { 422 qos.link_disc_time.bits = 0x01; /* 3 secs */ 423 424 irlan_next_client_state(self, IRLAN_DATA); 425 irttp_connect_request(self->tsap_data, 426 self->dtsap_sel_data, 427 self->saddr, self->daddr, &qos, 428 IRLAN_MTU, NULL); 429 } else if (self->client.recv_arb_val > 430 self->provider.send_arb_val) 431 { 432 IRDA_DEBUG(2, "%s(), lost the battle :-(\n", __FUNCTION__ ); 433 } 434 break; 435 case IRLAN_DATA_CONNECT_INDICATION: 436 irlan_next_client_state(self, IRLAN_DATA); 437 break; 438 case IRLAN_LMP_DISCONNECT: 439 case IRLAN_LAP_DISCONNECT: 440 irlan_next_client_state(self, IRLAN_IDLE); 441 break; 442 case IRLAN_WATCHDOG_TIMEOUT: 443 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); 444 break; 445 default: 446 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); 447 break; 448 } 449 if (skb) 450 dev_kfree_skb(skb); 451 452 return 0; 453} 454 455/* 456 * Function irlan_client_state_data (self, event, skb, info) 457 * 458 * DATA, The data channel is connected, allowing data transfers between 459 * the local and remote machines. 460 * 461 */ 462static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event, 463 struct sk_buff *skb) 464{ 465 IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); 466 467 IRDA_ASSERT(self != NULL, return -1;); 468 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); 469 470 switch(event) { 471 case IRLAN_DATA_INDICATION: 472 irlan_client_parse_response(self, skb); 473 break; 474 case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */ 475 case IRLAN_LAP_DISCONNECT: 476 irlan_next_client_state(self, IRLAN_IDLE); 477 break; 478 default: 479 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); 480 break; 481 } 482 if (skb) 483 dev_kfree_skb(skb); 484 485 return 0; 486} 487 488/* 489 * Function irlan_client_state_close (self, event, skb, info) 490 * 491 * 492 * 493 */ 494static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event, 495 struct sk_buff *skb) 496{ 497 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); 498 499 if (skb) 500 dev_kfree_skb(skb); 501 502 return 0; 503} 504 505/* 506 * Function irlan_client_state_sync (self, event, skb, info) 507 * 508 * 509 * 510 */ 511static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event, 512 struct sk_buff *skb) 513{ 514 IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); 515 516 if (skb) 517 dev_kfree_skb(skb); 518 519 return 0; 520} 521