TTY: add tty_port_tty_hangup helper
[linux-3.10.git] / net / irda / iriap_event.c
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
34 static void state_s_disconnect   (struct iriap_cb *self, IRIAP_EVENT event,
35                                   struct sk_buff *skb);
36 static void state_s_connecting   (struct iriap_cb *self, IRIAP_EVENT event,
37                                   struct sk_buff *skb);
38 static void state_s_call         (struct iriap_cb *self, IRIAP_EVENT event,
39                                   struct sk_buff *skb);
40
41 static void state_s_make_call    (struct iriap_cb *self, IRIAP_EVENT event,
42                                   struct sk_buff *skb);
43 static void state_s_calling      (struct iriap_cb *self, IRIAP_EVENT event,
44                                   struct sk_buff *skb);
45 static void state_s_outstanding  (struct iriap_cb *self, IRIAP_EVENT event,
46                                   struct sk_buff *skb);
47 static void state_s_replying     (struct iriap_cb *self, IRIAP_EVENT event,
48                                   struct sk_buff *skb);
49 static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event,
50                                   struct sk_buff *skb);
51 static void state_s_wait_active  (struct iriap_cb *self, IRIAP_EVENT event,
52                                   struct sk_buff *skb);
53
54 static void state_r_disconnect   (struct iriap_cb *self, IRIAP_EVENT event,
55                                   struct sk_buff *skb);
56 static void state_r_call         (struct iriap_cb *self, IRIAP_EVENT event,
57                                   struct sk_buff *skb);
58 static void state_r_waiting      (struct iriap_cb *self, IRIAP_EVENT event,
59                                   struct sk_buff *skb);
60 static void state_r_wait_active  (struct iriap_cb *self, IRIAP_EVENT event,
61                                   struct sk_buff *skb);
62 static void state_r_receiving    (struct iriap_cb *self, IRIAP_EVENT event,
63                                   struct sk_buff *skb);
64 static void state_r_execute      (struct iriap_cb *self, IRIAP_EVENT event,
65                                   struct sk_buff *skb);
66 static void state_r_returning    (struct iriap_cb *self, IRIAP_EVENT event,
67                                   struct sk_buff *skb);
68
69 static 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
96 void 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
104 void 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
112 void 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
120 void 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
128 void 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
137 void 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
146 void 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
155 void 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  */
171 static 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  */
201 static 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  */
234 static 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  */
257 static 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  */
285 static 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  */
297 static 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  */
320 static 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  */
332 static 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  */
345 static 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  */
363 static 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  */
399 static 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  */
423 static 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
429 static 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  */
441 static 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  */
464 static 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
493 static 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 }