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