1/********************************************************************* 2 * 3 * Filename: iriap_event.c 4 * Version: 0.1 5 * Description: IAP Finite State Machine 6 * Status: Experimental. 7 * Author: Dag Brattli <dagb@cs.uit.no> 8 * Created at: Thu Aug 21 00:02:07 1997 9 * Modified at: Wed Mar 1 11:28:34 2000 10 * Modified by: Dag Brattli <dagb@cs.uit.no> 11 * 12 * Copyright (c) 1997, 1999-2000 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 <net/irda/irda.h> 27#include <net/irda/irlmp.h> 28#include <net/irda/iriap.h> 29#include <net/irda/iriap_event.h> 30 31static void state_s_disconnect (struct iriap_cb *self, IRIAP_EVENT event, 32 struct sk_buff *skb); 33static void state_s_connecting (struct iriap_cb *self, IRIAP_EVENT event, 34 struct sk_buff *skb); 35static void state_s_call (struct iriap_cb *self, IRIAP_EVENT event, 36 struct sk_buff *skb); 37 38static void state_s_make_call (struct iriap_cb *self, IRIAP_EVENT event, 39 struct sk_buff *skb); 40static void state_s_calling (struct iriap_cb *self, IRIAP_EVENT event, 41 struct sk_buff *skb); 42static void state_s_outstanding (struct iriap_cb *self, IRIAP_EVENT event, 43 struct sk_buff *skb); 44static void state_s_replying (struct iriap_cb *self, IRIAP_EVENT event, 45 struct sk_buff *skb); 46static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event, 47 struct sk_buff *skb); 48static void state_s_wait_active (struct iriap_cb *self, IRIAP_EVENT event, 49 struct sk_buff *skb); 50 51static void state_r_disconnect (struct iriap_cb *self, IRIAP_EVENT event, 52 struct sk_buff *skb); 53static void state_r_call (struct iriap_cb *self, IRIAP_EVENT event, 54 struct sk_buff *skb); 55static void state_r_waiting (struct iriap_cb *self, IRIAP_EVENT event, 56 struct sk_buff *skb); 57static void state_r_wait_active (struct iriap_cb *self, IRIAP_EVENT event, 58 struct sk_buff *skb); 59static void state_r_receiving (struct iriap_cb *self, IRIAP_EVENT event, 60 struct sk_buff *skb); 61static void state_r_execute (struct iriap_cb *self, IRIAP_EVENT event, 62 struct sk_buff *skb); 63static void state_r_returning (struct iriap_cb *self, IRIAP_EVENT event, 64 struct sk_buff *skb); 65 66static void (*iriap_state[])(struct iriap_cb *self, IRIAP_EVENT event, 67 struct sk_buff *skb) = { 68 /* Client FSM */ 69 state_s_disconnect, 70 state_s_connecting, 71 state_s_call, 72 73 /* S-Call FSM */ 74 state_s_make_call, 75 state_s_calling, 76 state_s_outstanding, 77 state_s_replying, 78 state_s_wait_for_call, 79 state_s_wait_active, 80 81 /* Server FSM */ 82 state_r_disconnect, 83 state_r_call, 84 85 /* R-Connect FSM */ 86 state_r_waiting, 87 state_r_wait_active, 88 state_r_receiving, 89 state_r_execute, 90 state_r_returning, 91}; 92 93void iriap_next_client_state(struct iriap_cb *self, IRIAP_STATE state) 94{ 95 ASSERT(self != NULL, return;); 96 ASSERT(self->magic == IAS_MAGIC, return;); 97 98 self->client_state = state; 99} 100 101void iriap_next_call_state(struct iriap_cb *self, IRIAP_STATE state) 102{ 103 ASSERT(self != NULL, return;); 104 ASSERT(self->magic == IAS_MAGIC, return;); 105 106 self->call_state = state; 107} 108 109void iriap_next_server_state(struct iriap_cb *self, IRIAP_STATE state) 110{ 111 ASSERT(self != NULL, return;); 112 ASSERT(self->magic == IAS_MAGIC, return;); 113 114 self->server_state = state; 115} 116 117void iriap_next_r_connect_state(struct iriap_cb *self, IRIAP_STATE state) 118{ 119 ASSERT(self != NULL, return;); 120 ASSERT(self->magic == IAS_MAGIC, return;); 121 122 self->r_connect_state = state; 123} 124 125void iriap_do_client_event(struct iriap_cb *self, IRIAP_EVENT event, 126 struct sk_buff *skb) 127{ 128 ASSERT(self != NULL, return;); 129 ASSERT(self->magic == IAS_MAGIC, return;); 130 131 (*iriap_state[ self->client_state]) (self, event, skb); 132} 133 134void iriap_do_call_event(struct iriap_cb *self, IRIAP_EVENT event, 135 struct sk_buff *skb) 136{ 137 ASSERT(self != NULL, return;); 138 ASSERT(self->magic == IAS_MAGIC, return;); 139 140 (*iriap_state[ self->call_state]) (self, event, skb); 141} 142 143void iriap_do_server_event(struct iriap_cb *self, IRIAP_EVENT event, 144 struct sk_buff *skb) 145{ 146 ASSERT(self != NULL, return;); 147 ASSERT(self->magic == IAS_MAGIC, return;); 148 149 (*iriap_state[ self->server_state]) (self, event, skb); 150} 151 152void iriap_do_r_connect_event(struct iriap_cb *self, IRIAP_EVENT event, 153 struct sk_buff *skb) 154{ 155 ASSERT(self != NULL, return;); 156 ASSERT(self->magic == IAS_MAGIC, return;); 157 158 (*iriap_state[ self->r_connect_state]) (self, event, skb); 159} 160 161 162/* 163 * Function state_s_disconnect (event, skb) 164 * 165 * S-Disconnect, The device has no LSAP connection to a particular 166 * remote device. 167 */ 168static void state_s_disconnect(struct iriap_cb *self, IRIAP_EVENT event, 169 struct sk_buff *skb) 170{ 171 ASSERT(self != NULL, return;); 172 ASSERT(self->magic == IAS_MAGIC, return;); 173 174 switch (event) { 175 case IAP_CALL_REQUEST_GVBC: 176 iriap_next_client_state(self, S_CONNECTING); 177 ASSERT(self->skb == NULL, return;); 178 self->skb = skb; 179 iriap_connect_request(self); 180 break; 181 case IAP_LM_DISCONNECT_INDICATION: 182 break; 183 default: 184 IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event); 185 break; 186 } 187} 188 189/* 190 * Function state_s_connecting (self, event, skb) 191 * 192 * S-Connecting 193 * 194 */ 195static void state_s_connecting(struct iriap_cb *self, IRIAP_EVENT event, 196 struct sk_buff *skb) 197{ 198 ASSERT(self != NULL, return;); 199 ASSERT(self->magic == IAS_MAGIC, return;); 200 201 switch (event) { 202 case IAP_LM_CONNECT_CONFIRM: 203 /* 204 * Jump to S-Call FSM 205 */ 206 iriap_do_call_event(self, IAP_CALL_REQUEST, skb); 207 /* iriap_call_request(self, 0,0,0); */ 208 iriap_next_client_state(self, S_CALL); 209 break; 210 case IAP_LM_DISCONNECT_INDICATION: 211 /* Abort calls */ 212 iriap_next_call_state(self, S_MAKE_CALL); 213 iriap_next_client_state(self, S_DISCONNECT); 214 break; 215 default: 216 IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event); 217 break; 218 } 219} 220 221/* 222 * Function state_s_call (self, event, skb) 223 * 224 * S-Call, The device can process calls to a specific remote 225 * device. Whenever the LSAP connection is disconnected, this state 226 * catches that event and clears up 227 */ 228static void state_s_call(struct iriap_cb *self, IRIAP_EVENT event, 229 struct sk_buff *skb) 230{ 231 ASSERT(self != NULL, return;); 232 233 switch (event) { 234 case IAP_LM_DISCONNECT_INDICATION: 235 /* Abort calls */ 236 iriap_next_call_state(self, S_MAKE_CALL); 237 iriap_next_client_state(self, S_DISCONNECT); 238 break; 239 default: 240 IRDA_DEBUG(0, "state_s_call: Unknown event %d\n", event); 241 break; 242 } 243} 244 245/* 246 * Function state_s_make_call (event, skb) 247 * 248 * S-Make-Call 249 * 250 */ 251static void state_s_make_call(struct iriap_cb *self, IRIAP_EVENT event, 252 struct sk_buff *skb) 253{ 254 ASSERT(self != NULL, return;); 255 256 switch (event) { 257 case IAP_CALL_REQUEST: 258 skb = self->skb; 259 self->skb = NULL; 260 261 irlmp_data_request(self->lsap, skb); 262 iriap_next_call_state(self, S_OUTSTANDING); 263 break; 264 default: 265 IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event); 266 if (skb) 267 dev_kfree_skb(skb); 268 break; 269 } 270} 271 272/* 273 * Function state_s_calling (event, skb) 274 * 275 * S-Calling 276 * 277 */ 278static void state_s_calling(struct iriap_cb *self, IRIAP_EVENT event, 279 struct sk_buff *skb) 280{ 281 IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); 282} 283 284/* 285 * Function state_s_outstanding (event, skb) 286 * 287 * S-Outstanding, The device is waiting for a response to a command 288 * 289 */ 290static void state_s_outstanding(struct iriap_cb *self, IRIAP_EVENT event, 291 struct sk_buff *skb) 292{ 293 ASSERT(self != NULL, return;); 294 295 switch (event) { 296 case IAP_RECV_F_LST: 297 /*iriap_send_ack(self);*/ 298 /*LM_Idle_request(idle); */ 299 300 iriap_next_call_state(self, S_WAIT_FOR_CALL); 301 break; 302 default: 303 IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event); 304 break; 305 } 306} 307 308/* 309 * Function state_s_replying (event, skb) 310 * 311 * S-Replying, The device is collecting a multiple part response 312 */ 313static void state_s_replying(struct iriap_cb *self, IRIAP_EVENT event, 314 struct sk_buff *skb) 315{ 316 IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); 317} 318 319/* 320 * Function state_s_wait_for_call (event, skb) 321 * 322 * S-Wait-for-Call 323 * 324 */ 325static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event, 326 struct sk_buff *skb) 327{ 328 IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); 329} 330 331 332/* 333 * Function state_s_wait_active (event, skb) 334 * 335 * S-Wait-Active 336 * 337 */ 338static void state_s_wait_active(struct iriap_cb *self, IRIAP_EVENT event, 339 struct sk_buff *skb) 340{ 341 IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); 342} 343 344/************************************************************************** 345 * 346 * Server FSM 347 * 348 **************************************************************************/ 349 350/* 351 * Function state_r_disconnect (self, event, skb) 352 * 353 * LM-IAS server is disconnected (not processing any requests!) 354 * 355 */ 356static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event, 357 struct sk_buff *skb) 358{ 359 struct sk_buff *tx_skb; 360 361 switch (event) { 362 case IAP_LM_CONNECT_INDICATION: 363 tx_skb = dev_alloc_skb(64); 364 if (tx_skb == NULL) { 365 WARNING("%s(), unable to malloc!\n", __FUNCTION__); 366 return; 367 } 368 369 /* Reserve space for MUX_CONTROL and LAP header */ 370 skb_reserve(tx_skb, LMP_MAX_HEADER); 371 372 irlmp_connect_response(self->lsap, tx_skb); 373 /*LM_Idle_request(idle); */ 374 375 iriap_next_server_state(self, R_CALL); 376 377 /* 378 * Jump to R-Connect FSM, we skip R-Waiting since we do not 379 * care about LM_Idle_request()! 380 */ 381 iriap_next_r_connect_state(self, R_RECEIVING); 382 383 if (skb) 384 dev_kfree_skb(skb); 385 386 break; 387 default: 388 IRDA_DEBUG(0, "%s(), unknown event %d\n", __FUNCTION__, event); 389 break; 390 } 391} 392 393/* 394 * Function state_r_call (self, event, skb) 395 * 396 * 397 * 398 */ 399static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event, 400 struct sk_buff *skb) 401{ 402 IRDA_DEBUG(4, "%s()\n", __FUNCTION__); 403 404 switch (event) { 405 case IAP_LM_DISCONNECT_INDICATION: 406 /* Abort call */ 407 iriap_next_server_state(self, R_DISCONNECT); 408 iriap_next_r_connect_state(self, R_WAITING); 409 break; 410 default: 411 IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__); 412 break; 413 } 414} 415 416/* 417 * R-Connect FSM 418*/ 419 420/* 421 * Function state_r_waiting (self, event, skb) 422 * 423 * 424 * 425 */ 426static void state_r_waiting(struct iriap_cb *self, IRIAP_EVENT event, 427 struct sk_buff *skb) 428{ 429 IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); 430} 431 432static void state_r_wait_active(struct iriap_cb *self, IRIAP_EVENT event, 433 struct sk_buff *skb) 434{ 435 IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); 436} 437 438/* 439 * Function state_r_receiving (self, event, skb) 440 * 441 * We are receiving a command 442 * 443 */ 444static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event, 445 struct sk_buff *skb) 446{ 447 IRDA_DEBUG(4, "%s()\n", __FUNCTION__); 448 449 switch (event) { 450 case IAP_RECV_F_LST: 451 iriap_next_r_connect_state(self, R_EXECUTE); 452 453 iriap_call_indication(self, skb); 454 break; 455 default: 456 IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__); 457 break; 458 } 459 460} 461 462/* 463 * Function state_r_execute (self, event, skb) 464 * 465 * The server is processing the request 466 * 467 */ 468static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event, 469 struct sk_buff *skb) 470{ 471 IRDA_DEBUG(4, "%s()\n", __FUNCTION__); 472 473 ASSERT(skb != NULL, return;); 474 475 if (!self || self->magic != IAS_MAGIC) { 476 IRDA_DEBUG(0, "%s(), bad pointer self\n", __FUNCTION__); 477 return; 478 } 479 480 switch (event) { 481 case IAP_CALL_RESPONSE: 482 /* 483 * Since we don't implement the Waiting state, we return 484 * to state Receiving instead, DB. 485 */ 486 iriap_next_r_connect_state(self, R_RECEIVING); 487 488 irlmp_data_request(self->lsap, skb); 489 break; 490 default: 491 IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__); 492 break; 493 } 494} 495 496static void state_r_returning(struct iriap_cb *self, IRIAP_EVENT event, 497 struct sk_buff *skb) 498{ 499 IRDA_DEBUG(0, "%s(), event=%d\n", __FUNCTION__, event); 500 501 switch (event) { 502 case IAP_RECV_F_LST: 503 504 break; 505 default: 506 break; 507 } 508} 509 510 511 512