1 /*********************************************************************
3 * Filename: irlan_client_event.c
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>
12 * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
13 * All Rights Reserved.
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.
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.
24 ********************************************************************/
26 #include <linux/skbuff.h>
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>
35 #include <net/irda/irlan_common.h>
36 #include <net/irda/irlan_client.h>
37 #include <net/irda/irlan_event.h>
39 static int irlan_client_state_idle (struct irlan_cb
*self
, IRLAN_EVENT event
,
41 static int irlan_client_state_query(struct irlan_cb
*self
, IRLAN_EVENT event
,
43 static int irlan_client_state_conn (struct irlan_cb
*self
, IRLAN_EVENT event
,
45 static int irlan_client_state_info (struct irlan_cb
*self
, IRLAN_EVENT event
,
47 static int irlan_client_state_media(struct irlan_cb
*self
, IRLAN_EVENT event
,
49 static int irlan_client_state_open (struct irlan_cb
*self
, IRLAN_EVENT event
,
51 static int irlan_client_state_wait (struct irlan_cb
*self
, IRLAN_EVENT event
,
53 static int irlan_client_state_arb (struct irlan_cb
*self
, IRLAN_EVENT event
,
55 static int irlan_client_state_data (struct irlan_cb
*self
, IRLAN_EVENT event
,
57 static int irlan_client_state_close(struct irlan_cb
*self
, IRLAN_EVENT event
,
59 static int irlan_client_state_sync (struct irlan_cb
*self
, IRLAN_EVENT event
,
62 static int (*state
[])(struct irlan_cb
*, IRLAN_EVENT event
, struct sk_buff
*) =
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
77 void irlan_do_client_event(struct irlan_cb
*self
, IRLAN_EVENT event
,
80 IRDA_ASSERT(self
!= NULL
, return;);
81 IRDA_ASSERT(self
->magic
== IRLAN_MAGIC
, return;);
83 (*state
[ self
->client
.state
]) (self
, event
, skb
);
87 * Function irlan_client_state_idle (event, skb, info)
89 * IDLE, We are waiting for an indication that there is a provider
92 static int irlan_client_state_idle(struct irlan_cb
*self
, IRLAN_EVENT event
,
95 IRDA_DEBUG(4, "%s()\n", __func__
);
97 IRDA_ASSERT(self
!= NULL
, return -1;);
98 IRDA_ASSERT(self
->magic
== IRLAN_MAGIC
, return -1;);
101 case IRLAN_DISCOVERY_INDICATION
:
102 if (self
->client
.iriap
) {
103 IRDA_WARNING("%s(), busy with a previous query\n",
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");
116 case IRLAN_WATCHDOG_TIMEOUT
:
117 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__
);
120 IRDA_DEBUG(4, "%s(), Unknown event %d\n", __func__
, event
);
130 * Function irlan_client_state_query (event, skb, info)
132 * QUERY, We have queryed the remote IAS and is ready to connect
133 * to provider, just waiting for the confirm.
136 static int irlan_client_state_query(struct irlan_cb
*self
, IRLAN_EVENT event
,
139 IRDA_DEBUG(4, "%s()\n", __func__
);
141 IRDA_ASSERT(self
!= NULL
, return -1;);
142 IRDA_ASSERT(self
->magic
== IRLAN_MAGIC
, return -1;);
145 case IRLAN_IAS_PROVIDER_AVAIL
:
146 IRDA_ASSERT(self
->dtsap_sel_ctrl
!= 0, return -1;);
148 self
->client
.open_retries
= 0;
150 irttp_connect_request(self
->client
.tsap_ctrl
,
151 self
->dtsap_sel_ctrl
,
152 self
->saddr
, self
->daddr
, NULL
,
154 irlan_next_client_state(self
, IRLAN_CONN
);
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
);
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
);
165 case IRLAN_LMP_DISCONNECT
:
166 case IRLAN_LAP_DISCONNECT
:
167 irlan_next_client_state(self
, IRLAN_IDLE
);
169 case IRLAN_WATCHDOG_TIMEOUT
:
170 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__
);
173 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__
, event
);
183 * Function irlan_client_state_conn (event, skb, info)
185 * CONN, We have connected to a provider but has not issued any
189 static int irlan_client_state_conn(struct irlan_cb
*self
, IRLAN_EVENT event
,
192 IRDA_DEBUG(4, "%s()\n", __func__
);
194 IRDA_ASSERT(self
!= NULL
, return -1;);
197 case IRLAN_CONNECT_COMPLETE
:
198 /* Send getinfo cmd */
199 irlan_get_provider_info(self
);
200 irlan_next_client_state(self
, IRLAN_INFO
);
202 case IRLAN_LMP_DISCONNECT
:
203 case IRLAN_LAP_DISCONNECT
:
204 irlan_next_client_state(self
, IRLAN_IDLE
);
206 case IRLAN_WATCHDOG_TIMEOUT
:
207 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__
);
210 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__
, event
);
220 * Function irlan_client_state_info (self, event, skb, info)
222 * INFO, We have issued a GetInfo command and is awaiting a reply.
224 static int irlan_client_state_info(struct irlan_cb
*self
, IRLAN_EVENT event
,
227 IRDA_DEBUG(4, "%s()\n", __func__
);
229 IRDA_ASSERT(self
!= NULL
, return -1;);
232 case IRLAN_DATA_INDICATION
:
233 IRDA_ASSERT(skb
!= NULL
, return -1;);
235 irlan_client_parse_response(self
, skb
);
237 irlan_next_client_state(self
, IRLAN_MEDIA
);
239 irlan_get_media_char(self
);
242 case IRLAN_LMP_DISCONNECT
:
243 case IRLAN_LAP_DISCONNECT
:
244 irlan_next_client_state(self
, IRLAN_IDLE
);
246 case IRLAN_WATCHDOG_TIMEOUT
:
247 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__
);
250 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__
, event
);
260 * Function irlan_client_state_media (self, event, skb, info)
262 * MEDIA, The irlan_client has issued a GetMedia command and is awaiting a
266 static int irlan_client_state_media(struct irlan_cb
*self
, IRLAN_EVENT event
,
269 IRDA_DEBUG(4, "%s()\n", __func__
);
271 IRDA_ASSERT(self
!= NULL
, return -1;);
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
);
279 case IRLAN_LMP_DISCONNECT
:
280 case IRLAN_LAP_DISCONNECT
:
281 irlan_next_client_state(self
, IRLAN_IDLE
);
283 case IRLAN_WATCHDOG_TIMEOUT
:
284 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__
);
287 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__
, event
);
297 * Function irlan_client_state_open (self, event, skb, info)
299 * OPEN, The irlan_client has issued a OpenData command and is awaiting a
303 static int irlan_client_state_open(struct irlan_cb
*self
, IRLAN_EVENT event
,
308 IRDA_DEBUG(4, "%s()\n", __func__
);
310 IRDA_ASSERT(self
!= NULL
, return -1;);
313 case IRLAN_DATA_INDICATION
:
314 irlan_client_parse_response(self
, skb
);
317 * Check if we have got the remote TSAP for data
320 IRDA_ASSERT(self
->dtsap_sel_data
!= 0, return -1;);
322 /* Check which access type we are dealing with */
323 switch (self
->client
.access_type
) {
325 if (self
->provider
.state
== IRLAN_OPEN
) {
327 irlan_next_client_state(self
, IRLAN_ARB
);
328 irlan_do_client_event(self
, IRLAN_CHECK_CON_ARB
,
332 irlan_next_client_state(self
, IRLAN_WAIT
);
337 qos
.link_disc_time
.bits
= 0x01; /* 3 secs */
339 irttp_connect_request(self
->tsap_data
,
340 self
->dtsap_sel_data
,
341 self
->saddr
, self
->daddr
, &qos
,
344 irlan_next_client_state(self
, IRLAN_DATA
);
347 IRDA_DEBUG(2, "%s(), unknown access type!\n", __func__
);
351 case IRLAN_LMP_DISCONNECT
:
352 case IRLAN_LAP_DISCONNECT
:
353 irlan_next_client_state(self
, IRLAN_IDLE
);
355 case IRLAN_WATCHDOG_TIMEOUT
:
356 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__
);
359 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__
, event
);
370 * Function irlan_client_state_wait (self, event, skb, info)
372 * WAIT, The irlan_client is waiting for the local provider to enter the
373 * provider OPEN state.
376 static int irlan_client_state_wait(struct irlan_cb
*self
, IRLAN_EVENT event
,
379 IRDA_DEBUG(4, "%s()\n", __func__
);
381 IRDA_ASSERT(self
!= NULL
, return -1;);
384 case IRLAN_PROVIDER_SIGNAL
:
385 irlan_next_client_state(self
, IRLAN_ARB
);
386 irlan_do_client_event(self
, IRLAN_CHECK_CON_ARB
, NULL
);
388 case IRLAN_LMP_DISCONNECT
:
389 case IRLAN_LAP_DISCONNECT
:
390 irlan_next_client_state(self
, IRLAN_IDLE
);
392 case IRLAN_WATCHDOG_TIMEOUT
:
393 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__
);
396 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__
, event
);
405 static int irlan_client_state_arb(struct irlan_cb
*self
, IRLAN_EVENT event
,
410 IRDA_DEBUG(2, "%s()\n", __func__
);
412 IRDA_ASSERT(self
!= NULL
, return -1;);
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
)
422 qos
.link_disc_time
.bits
= 0x01; /* 3 secs */
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
,
429 } else if (self
->client
.recv_arb_val
>
430 self
->provider
.send_arb_val
)
432 IRDA_DEBUG(2, "%s(), lost the battle :-(\n", __func__
);
435 case IRLAN_DATA_CONNECT_INDICATION
:
436 irlan_next_client_state(self
, IRLAN_DATA
);
438 case IRLAN_LMP_DISCONNECT
:
439 case IRLAN_LAP_DISCONNECT
:
440 irlan_next_client_state(self
, IRLAN_IDLE
);
442 case IRLAN_WATCHDOG_TIMEOUT
:
443 IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__
);
446 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__
, event
);
456 * Function irlan_client_state_data (self, event, skb, info)
458 * DATA, The data channel is connected, allowing data transfers between
459 * the local and remote machines.
462 static int irlan_client_state_data(struct irlan_cb
*self
, IRLAN_EVENT event
,
465 IRDA_DEBUG(4, "%s()\n", __func__
);
467 IRDA_ASSERT(self
!= NULL
, return -1;);
468 IRDA_ASSERT(self
->magic
== IRLAN_MAGIC
, return -1;);
471 case IRLAN_DATA_INDICATION
:
472 irlan_client_parse_response(self
, skb
);
474 case IRLAN_LMP_DISCONNECT
: /* FALLTHROUGH */
475 case IRLAN_LAP_DISCONNECT
:
476 irlan_next_client_state(self
, IRLAN_IDLE
);
479 IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__
, event
);
489 * Function irlan_client_state_close (self, event, skb, info)
494 static int irlan_client_state_close(struct irlan_cb
*self
, IRLAN_EVENT event
,
497 IRDA_DEBUG(2, "%s()\n", __func__
);
506 * Function irlan_client_state_sync (self, event, skb, info)
511 static int irlan_client_state_sync(struct irlan_cb
*self
, IRLAN_EVENT event
,
514 IRDA_DEBUG(2, "%s()\n", __func__
);