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