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_DEBUG(4, "%s()\n", __func__ );
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 				     __func__);
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", __func__ );
118 		break;
119 	default:
120 		IRDA_DEBUG(4, "%s(), Unknown event %d\n", __func__ , 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  */
irlan_client_state_query(struct irlan_cb * self,IRLAN_EVENT event,struct sk_buff * skb)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", __func__ );
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", __func__ );
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", __func__ );
171 		break;
172 	default:
173 		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , 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  */
irlan_client_state_conn(struct irlan_cb * self,IRLAN_EVENT event,struct sk_buff * skb)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", __func__ );
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", __func__ );
208 		break;
209 	default:
210 		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , 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  */
irlan_client_state_info(struct irlan_cb * self,IRLAN_EVENT event,struct sk_buff * skb)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", __func__ );
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", __func__ );
248 		break;
249 	default:
250 		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , 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  */
irlan_client_state_media(struct irlan_cb * self,IRLAN_EVENT event,struct sk_buff * skb)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", __func__ );
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", __func__ );
285 		break;
286 	default:
287 		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , 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  */
irlan_client_state_open(struct irlan_cb * self,IRLAN_EVENT event,struct sk_buff * skb)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", __func__ );
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", __func__ );
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", __func__ );
357 		break;
358 	default:
359 		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , 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  */
irlan_client_state_wait(struct irlan_cb * self,IRLAN_EVENT event,struct sk_buff * skb)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", __func__ );
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", __func__ );
394 		break;
395 	default:
396 		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
397 		break;
398 	}
399 	if (skb)
400 		dev_kfree_skb(skb);
401 
402 	return 0;
403 }
404 
irlan_client_state_arb(struct irlan_cb * self,IRLAN_EVENT event,struct sk_buff * skb)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", __func__ );
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", __func__ );
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", __func__ );
444 		break;
445 	default:
446 		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , 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  */
irlan_client_state_data(struct irlan_cb * self,IRLAN_EVENT event,struct sk_buff * skb)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", __func__ );
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", __func__ , 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  */
irlan_client_state_close(struct irlan_cb * self,IRLAN_EVENT event,struct sk_buff * skb)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", __func__ );
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  */
irlan_client_state_sync(struct irlan_cb * self,IRLAN_EVENT event,struct sk_buff * skb)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", __func__ );
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