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