File: /usr/src/linux/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, __FUNCTION__ "()\n");
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(__FUNCTION__ 
104     				"(), busy with a previous query\n");
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, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
118     		break;
119     	default:
120     		IRDA_DEBUG(4, __FUNCTION__ "(), Unknown event %d\n", 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, __FUNCTION__ "()\n");
140     
141     	ASSERT(self != NULL, return -1;);
142     	ASSERT(self->magic == IRLAN_MAGIC, return -1;);
143     	
144     	switch(event) {
145     	case IRLAN_IAS_PROVIDER_AVAIL:
146     		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, __FUNCTION__ "(), IAS_PROVIDER_NOT_AVAIL\n");
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, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
171     		break;
172     	default:
173     		IRDA_DEBUG(2, __FUNCTION__"(), Unknown event %d\n", 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, __FUNCTION__ "()\n");
193     	
194     	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, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
208     		break;
209     	default:
210     		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", 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, __FUNCTION__ "()\n");
228     
229     	ASSERT(self != NULL, return -1;);
230     	
231     	switch (event) {
232     	case IRLAN_DATA_INDICATION:
233     		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, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
248     		break;
249     	default:
250     		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", 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, __FUNCTION__ "()\n");
270     	
271     	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, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
285     		break;
286     	default:
287     		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", 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, __FUNCTION__ "()\n");
309     	
310     	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     	  	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, __FUNCTION__ "(), unknown access type!\n");
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, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
357     		break;
358     	default:
359     		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", 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, __FUNCTION__ "()\n");
380     	
381     	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, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
394     		break;
395     	default:
396     		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", 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, __FUNCTION__ "()\n");
411     
412     	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, __FUNCTION__ "(), lost the battle :-(\n");
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, __FUNCTION__ "(), IRLAN_WATCHDOG_TIMEOUT\n");
444     		break;
445     	default:
446     		IRDA_DEBUG(2, __FUNCTION__ "(), Unknown event %d\n", 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, __FUNCTION__ "()\n");
466     
467     	ASSERT(self != NULL, return -1;);
468     	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, __FUNCTION__ "(), Unknown event %d\n", 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, __FUNCTION__ "()\n");
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, __FUNCTION__ "()\n");
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     
534