Merge git://oss.sgi.com:8090/xfs/xfs-2.6
[linux-drm-fsl-dcu.git] / net / irda / irlan / irlan_client_event.c
1 /*********************************************************************
2  *
3  * Filename:      irlan_client_event.c
4  * Version:       0.9
5  * Description:   IrLAN client state machine
6  * Status:        Experimental.
7  * Author:        Dag Brattli <dagb@cs.uit.no>
8  * Created at:    Sun Aug 31 20:14:37 1997
9  * Modified at:   Sun Dec 26 21:52:24 1999
10  * Modified by:   Dag Brattli <dagb@cs.uit.no>
11  *
12  *     Copyright (c) 1998-1999 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 <linux/skbuff.h>
27
28 #include <net/irda/irda.h>
29 #include <net/irda/timer.h>
30 #include <net/irda/irmod.h>
31 #include <net/irda/iriap.h>
32 #include <net/irda/irlmp.h>
33 #include <net/irda/irttp.h>
34
35 #include <net/irda/irlan_common.h>
36 #include <net/irda/irlan_client.h>
37 #include <net/irda/irlan_event.h>
38
39 static int irlan_client_state_idle (struct irlan_cb *self, IRLAN_EVENT event,
40                                     struct sk_buff *skb);
41 static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
42                                     struct sk_buff *skb);
43 static int irlan_client_state_conn (struct irlan_cb *self, IRLAN_EVENT event,
44                                     struct sk_buff *skb);
45 static int irlan_client_state_info (struct irlan_cb *self, IRLAN_EVENT event,
46                                     struct sk_buff *skb);
47 static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
48                                     struct sk_buff *skb);
49 static int irlan_client_state_open (struct irlan_cb *self, IRLAN_EVENT event,
50                                     struct sk_buff *skb);
51 static int irlan_client_state_wait (struct irlan_cb *self, IRLAN_EVENT event,
52                                     struct sk_buff *skb);
53 static int irlan_client_state_arb  (struct irlan_cb *self, IRLAN_EVENT event,
54                                     struct sk_buff *skb);
55 static int irlan_client_state_data (struct irlan_cb *self, IRLAN_EVENT event,
56                                     struct sk_buff *skb);
57 static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,
58                                     struct sk_buff *skb);
59 static int irlan_client_state_sync (struct irlan_cb *self, IRLAN_EVENT event,
60                                     struct sk_buff *skb);
61
62 static int (*state[])(struct irlan_cb *, IRLAN_EVENT event, struct sk_buff *) =
63 {
64         irlan_client_state_idle,
65         irlan_client_state_query,
66         irlan_client_state_conn,
67         irlan_client_state_info,
68         irlan_client_state_media,
69         irlan_client_state_open,
70         irlan_client_state_wait,
71         irlan_client_state_arb,
72         irlan_client_state_data,
73         irlan_client_state_close,
74         irlan_client_state_sync
75 };
76
77 void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event,
78                            struct sk_buff *skb)
79 {
80         IRDA_ASSERT(self != NULL, return;);
81         IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
82
83         (*state[ self->client.state]) (self, event, skb);
84 }
85
86 /*
87  * Function irlan_client_state_idle (event, skb, info)
88  *
89  *    IDLE, We are waiting for an indication that there is a provider
90  *    available.
91  */
92 static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
93                                    struct sk_buff *skb)
94 {
95         IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
96
97         IRDA_ASSERT(self != NULL, return -1;);
98         IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
99
100         switch (event) {
101         case IRLAN_DISCOVERY_INDICATION:
102                 if (self->client.iriap) {
103                         IRDA_WARNING("%s(), busy with a previous query\n",
104                                      __FUNCTION__);
105                         return -EBUSY;
106                 }
107
108                 self->client.iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
109                                                 irlan_client_get_value_confirm);
110                 /* Get some values from peer IAS */
111                 irlan_next_client_state(self, IRLAN_QUERY);
112                 iriap_getvaluebyclass_request(self->client.iriap,
113                                               self->saddr, self->daddr,
114                                               "IrLAN", "IrDA:TinyTP:LsapSel");
115                 break;
116         case IRLAN_WATCHDOG_TIMEOUT:
117                 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
118                 break;
119         default:
120                 IRDA_DEBUG(4, "%s(), Unknown event %d\n", __FUNCTION__ , event);
121                 break;
122         }
123         if (skb)
124                 dev_kfree_skb(skb);
125
126         return 0;
127 }
128
129 /*
130  * Function irlan_client_state_query (event, skb, info)
131  *
132  *    QUERY, We have queryed the remote IAS and is ready to connect
133  *    to provider, just waiting for the confirm.
134  *
135  */
136 static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
137                                     struct sk_buff *skb)
138 {
139         IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
140
141         IRDA_ASSERT(self != NULL, return -1;);
142         IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
143
144         switch(event) {
145         case IRLAN_IAS_PROVIDER_AVAIL:
146                 IRDA_ASSERT(self->dtsap_sel_ctrl != 0, return -1;);
147
148                 self->client.open_retries = 0;
149
150                 irttp_connect_request(self->client.tsap_ctrl,
151                                       self->dtsap_sel_ctrl,
152                                       self->saddr, self->daddr, NULL,
153                                       IRLAN_MTU, NULL);
154                 irlan_next_client_state(self, IRLAN_CONN);
155                 break;
156         case IRLAN_IAS_PROVIDER_NOT_AVAIL:
157                 IRDA_DEBUG(2, "%s(), IAS_PROVIDER_NOT_AVAIL\n", __FUNCTION__ );
158                 irlan_next_client_state(self, IRLAN_IDLE);
159
160                 /* Give the client a kick! */
161                 if ((self->provider.access_type == ACCESS_PEER) &&
162                     (self->provider.state != IRLAN_IDLE))
163                         irlan_client_wakeup(self, self->saddr, self->daddr);
164                 break;
165         case IRLAN_LMP_DISCONNECT:
166         case IRLAN_LAP_DISCONNECT:
167                 irlan_next_client_state(self, IRLAN_IDLE);
168                 break;
169         case IRLAN_WATCHDOG_TIMEOUT:
170                 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
171                 break;
172         default:
173                 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
174                 break;
175         }
176         if (skb)
177                 dev_kfree_skb(skb);
178
179         return 0;
180 }
181
182 /*
183  * Function irlan_client_state_conn (event, skb, info)
184  *
185  *    CONN, We have connected to a provider but has not issued any
186  *    commands yet.
187  *
188  */
189 static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event,
190                                    struct sk_buff *skb)
191 {
192         IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
193
194         IRDA_ASSERT(self != NULL, return -1;);
195
196         switch (event) {
197         case IRLAN_CONNECT_COMPLETE:
198                 /* Send getinfo cmd */
199                 irlan_get_provider_info(self);
200                 irlan_next_client_state(self, IRLAN_INFO);
201                 break;
202         case IRLAN_LMP_DISCONNECT:
203         case IRLAN_LAP_DISCONNECT:
204                 irlan_next_client_state(self, IRLAN_IDLE);
205                 break;
206         case IRLAN_WATCHDOG_TIMEOUT:
207                 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
208                 break;
209         default:
210                 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
211                 break;
212         }
213         if (skb)
214                 dev_kfree_skb(skb);
215
216         return 0;
217 }
218
219 /*
220  * Function irlan_client_state_info (self, event, skb, info)
221  *
222  *    INFO, We have issued a GetInfo command and is awaiting a reply.
223  */
224 static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event,
225                                    struct sk_buff *skb)
226 {
227         IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
228
229         IRDA_ASSERT(self != NULL, return -1;);
230
231         switch (event) {
232         case IRLAN_DATA_INDICATION:
233                 IRDA_ASSERT(skb != NULL, return -1;);
234
235                 irlan_client_parse_response(self, skb);
236
237                 irlan_next_client_state(self, IRLAN_MEDIA);
238
239                 irlan_get_media_char(self);
240                 break;
241
242         case IRLAN_LMP_DISCONNECT:
243         case IRLAN_LAP_DISCONNECT:
244                 irlan_next_client_state(self, IRLAN_IDLE);
245                 break;
246         case IRLAN_WATCHDOG_TIMEOUT:
247                 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
248                 break;
249         default:
250                 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
251                 break;
252         }
253         if (skb)
254                 dev_kfree_skb(skb);
255
256         return 0;
257 }
258
259 /*
260  * Function irlan_client_state_media (self, event, skb, info)
261  *
262  *    MEDIA, The irlan_client has issued a GetMedia command and is awaiting a
263  *    reply.
264  *
265  */
266 static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
267                                     struct sk_buff *skb)
268 {
269         IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
270
271         IRDA_ASSERT(self != NULL, return -1;);
272
273         switch(event) {
274         case IRLAN_DATA_INDICATION:
275                 irlan_client_parse_response(self, skb);
276                 irlan_open_data_channel(self);
277                 irlan_next_client_state(self, IRLAN_OPEN);
278                 break;
279         case IRLAN_LMP_DISCONNECT:
280         case IRLAN_LAP_DISCONNECT:
281                 irlan_next_client_state(self, IRLAN_IDLE);
282                 break;
283         case IRLAN_WATCHDOG_TIMEOUT:
284                 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
285                 break;
286         default:
287                 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
288                 break;
289         }
290         if (skb)
291                 dev_kfree_skb(skb);
292
293         return 0;
294 }
295
296 /*
297  * Function irlan_client_state_open (self, event, skb, info)
298  *
299  *    OPEN, The irlan_client has issued a OpenData command and is awaiting a
300  *    reply
301  *
302  */
303 static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event,
304                                    struct sk_buff *skb)
305 {
306         struct qos_info qos;
307
308         IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
309
310         IRDA_ASSERT(self != NULL, return -1;);
311
312         switch(event) {
313         case IRLAN_DATA_INDICATION:
314                 irlan_client_parse_response(self, skb);
315
316                 /*
317                  *  Check if we have got the remote TSAP for data
318                  *  communications
319                  */
320                 IRDA_ASSERT(self->dtsap_sel_data != 0, return -1;);
321
322                 /* Check which access type we are dealing with */
323                 switch (self->client.access_type) {
324                 case ACCESS_PEER:
325                     if (self->provider.state == IRLAN_OPEN) {
326
327                             irlan_next_client_state(self, IRLAN_ARB);
328                             irlan_do_client_event(self, IRLAN_CHECK_CON_ARB,
329                                                   NULL);
330                     } else {
331
332                             irlan_next_client_state(self, IRLAN_WAIT);
333                     }
334                     break;
335                 case ACCESS_DIRECT:
336                 case ACCESS_HOSTED:
337                         qos.link_disc_time.bits = 0x01; /* 3 secs */
338
339                         irttp_connect_request(self->tsap_data,
340                                               self->dtsap_sel_data,
341                                               self->saddr, self->daddr, &qos,
342                                               IRLAN_MTU, NULL);
343
344                         irlan_next_client_state(self, IRLAN_DATA);
345                         break;
346                 default:
347                         IRDA_DEBUG(2, "%s(), unknown access type!\n", __FUNCTION__ );
348                         break;
349                 }
350                 break;
351         case IRLAN_LMP_DISCONNECT:
352         case IRLAN_LAP_DISCONNECT:
353                 irlan_next_client_state(self, IRLAN_IDLE);
354                 break;
355         case IRLAN_WATCHDOG_TIMEOUT:
356                 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
357                 break;
358         default:
359                 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
360                 break;
361         }
362
363         if (skb)
364                 dev_kfree_skb(skb);
365
366         return 0;
367 }
368
369 /*
370  * Function irlan_client_state_wait (self, event, skb, info)
371  *
372  *    WAIT, The irlan_client is waiting for the local provider to enter the
373  *    provider OPEN state.
374  *
375  */
376 static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event,
377                                    struct sk_buff *skb)
378 {
379         IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
380
381         IRDA_ASSERT(self != NULL, return -1;);
382
383         switch(event) {
384         case IRLAN_PROVIDER_SIGNAL:
385                 irlan_next_client_state(self, IRLAN_ARB);
386                 irlan_do_client_event(self, IRLAN_CHECK_CON_ARB, NULL);
387                 break;
388         case IRLAN_LMP_DISCONNECT:
389         case IRLAN_LAP_DISCONNECT:
390                 irlan_next_client_state(self, IRLAN_IDLE);
391                 break;
392         case IRLAN_WATCHDOG_TIMEOUT:
393                 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
394                 break;
395         default:
396                 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
397                 break;
398         }
399         if (skb)
400                 dev_kfree_skb(skb);
401
402         return 0;
403 }
404
405 static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event,
406                                   struct sk_buff *skb)
407 {
408         struct qos_info qos;
409
410         IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
411
412         IRDA_ASSERT(self != NULL, return -1;);
413
414         switch(event) {
415         case IRLAN_CHECK_CON_ARB:
416                 if (self->client.recv_arb_val == self->provider.send_arb_val) {
417                         irlan_next_client_state(self, IRLAN_CLOSE);
418                         irlan_close_data_channel(self);
419                 } else if (self->client.recv_arb_val <
420                            self->provider.send_arb_val)
421                 {
422                         qos.link_disc_time.bits = 0x01; /* 3 secs */
423
424                         irlan_next_client_state(self, IRLAN_DATA);
425                         irttp_connect_request(self->tsap_data,
426                                               self->dtsap_sel_data,
427                                               self->saddr, self->daddr, &qos,
428                                               IRLAN_MTU, NULL);
429                 } else if (self->client.recv_arb_val >
430                            self->provider.send_arb_val)
431                 {
432                         IRDA_DEBUG(2, "%s(), lost the battle :-(\n", __FUNCTION__ );
433                 }
434                 break;
435         case IRLAN_DATA_CONNECT_INDICATION:
436                 irlan_next_client_state(self, IRLAN_DATA);
437                 break;
438         case IRLAN_LMP_DISCONNECT:
439         case IRLAN_LAP_DISCONNECT:
440                 irlan_next_client_state(self, IRLAN_IDLE);
441                 break;
442         case IRLAN_WATCHDOG_TIMEOUT:
443                 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
444                 break;
445         default:
446                 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
447                 break;
448         }
449         if (skb)
450                 dev_kfree_skb(skb);
451
452         return 0;
453 }
454
455 /*
456  * Function irlan_client_state_data (self, event, skb, info)
457  *
458  *    DATA, The data channel is connected, allowing data transfers between
459  *    the local and remote machines.
460  *
461  */
462 static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event,
463                                    struct sk_buff *skb)
464 {
465         IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
466
467         IRDA_ASSERT(self != NULL, return -1;);
468         IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
469
470         switch(event) {
471         case IRLAN_DATA_INDICATION:
472                 irlan_client_parse_response(self, skb);
473                 break;
474         case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
475         case IRLAN_LAP_DISCONNECT:
476                 irlan_next_client_state(self, IRLAN_IDLE);
477                 break;
478         default:
479                 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
480                 break;
481         }
482         if (skb)
483                 dev_kfree_skb(skb);
484
485         return 0;
486 }
487
488 /*
489  * Function irlan_client_state_close (self, event, skb, info)
490  *
491  *
492  *
493  */
494 static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,
495                                     struct sk_buff *skb)
496 {
497         IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
498
499         if (skb)
500                 dev_kfree_skb(skb);
501
502         return 0;
503 }
504
505 /*
506  * Function irlan_client_state_sync (self, event, skb, info)
507  *
508  *
509  *
510  */
511 static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event,
512                                    struct sk_buff *skb)
513 {
514         IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
515
516         if (skb)
517                 dev_kfree_skb(skb);
518
519         return 0;
520 }
521
522
523
524
525
526
527
528
529
530
531
532
533