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