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 pr_debug("%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 pr_debug("%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 pr_debug("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 pr_debug("%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 pr_debug("%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 pr_debug("%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 pr_debug("%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 pr_debug("%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 pr_debug("%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 return; 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 pr_debug("%s(), unknown event %d\n", __func__, 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 switch (event) { 401 case IAP_LM_DISCONNECT_INDICATION: 402 /* Abort call */ 403 iriap_next_server_state(self, R_DISCONNECT); 404 iriap_next_r_connect_state(self, R_WAITING); 405 break; 406 default: 407 pr_debug("%s(), unknown event!\n", __func__); 408 break; 409 } 410} 411 412/* 413 * R-Connect FSM 414 */ 415 416/* 417 * Function state_r_waiting (self, event, skb) 418 */ 419static void state_r_waiting(struct iriap_cb *self, IRIAP_EVENT event, 420 struct sk_buff *skb) 421{ 422 pr_debug("%s(), Not implemented\n", __func__); 423} 424 425static void state_r_wait_active(struct iriap_cb *self, IRIAP_EVENT event, 426 struct sk_buff *skb) 427{ 428 pr_debug("%s(), Not implemented\n", __func__); 429} 430 431/* 432 * Function state_r_receiving (self, event, skb) 433 * 434 * We are receiving a command 435 * 436 */ 437static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event, 438 struct sk_buff *skb) 439{ 440 switch (event) { 441 case IAP_RECV_F_LST: 442 iriap_next_r_connect_state(self, R_EXECUTE); 443 444 iriap_call_indication(self, skb); 445 break; 446 default: 447 pr_debug("%s(), unknown event!\n", __func__); 448 break; 449 } 450} 451 452/* 453 * Function state_r_execute (self, event, skb) 454 * 455 * The server is processing the request 456 * 457 */ 458static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event, 459 struct sk_buff *skb) 460{ 461 IRDA_ASSERT(skb != NULL, return;); 462 IRDA_ASSERT(self != NULL, return;); 463 IRDA_ASSERT(self->magic == IAS_MAGIC, return;); 464 465 switch (event) { 466 case IAP_CALL_RESPONSE: 467 /* 468 * Since we don't implement the Waiting state, we return 469 * to state Receiving instead, DB. 470 */ 471 iriap_next_r_connect_state(self, R_RECEIVING); 472 473 /* Don't forget to refcount it - see 474 * iriap_getvaluebyclass_response(). */ 475 skb_get(skb); 476 477 irlmp_data_request(self->lsap, skb); 478 break; 479 default: 480 pr_debug("%s(), unknown event!\n", __func__); 481 break; 482 } 483} 484 485static void state_r_returning(struct iriap_cb *self, IRIAP_EVENT event, 486 struct sk_buff *skb) 487{ 488 pr_debug("%s(), event=%d\n", __func__, event); 489 490 switch (event) { 491 case IAP_RECV_F_LST: 492 break; 493 default: 494 break; 495 } 496} 497