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