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