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_ASSERT(self != NULL, return -1;);
96 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
99 case IRLAN_DISCOVERY_INDICATION:
100 if (self->client.iriap) {
101 net_warn_ratelimited("%s(), busy with a previous query\n",
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");
114 case IRLAN_WATCHDOG_TIMEOUT:
115 pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
118 pr_debug("%s(), Unknown event %d\n", __func__ , event);
128 * Function irlan_client_state_query (event, skb, info)
130 * QUERY, We have queryed the remote IAS and is ready to connect
131 * to provider, just waiting for the confirm.
134 static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
137 IRDA_ASSERT(self != NULL, return -1;);
138 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
141 case IRLAN_IAS_PROVIDER_AVAIL:
142 IRDA_ASSERT(self->dtsap_sel_ctrl != 0, return -1;);
144 self->client.open_retries = 0;
146 irttp_connect_request(self->client.tsap_ctrl,
147 self->dtsap_sel_ctrl,
148 self->saddr, self->daddr, NULL,
150 irlan_next_client_state(self, IRLAN_CONN);
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);
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);
161 case IRLAN_LMP_DISCONNECT:
162 case IRLAN_LAP_DISCONNECT:
163 irlan_next_client_state(self, IRLAN_IDLE);
165 case IRLAN_WATCHDOG_TIMEOUT:
166 pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
169 pr_debug("%s(), Unknown event %d\n", __func__ , event);
179 * Function irlan_client_state_conn (event, skb, info)
181 * CONN, We have connected to a provider but has not issued any
185 static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event,
188 IRDA_ASSERT(self != NULL, return -1;);
191 case IRLAN_CONNECT_COMPLETE:
192 /* Send getinfo cmd */
193 irlan_get_provider_info(self);
194 irlan_next_client_state(self, IRLAN_INFO);
196 case IRLAN_LMP_DISCONNECT:
197 case IRLAN_LAP_DISCONNECT:
198 irlan_next_client_state(self, IRLAN_IDLE);
200 case IRLAN_WATCHDOG_TIMEOUT:
201 pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
204 pr_debug("%s(), Unknown event %d\n", __func__ , event);
214 * Function irlan_client_state_info (self, event, skb, info)
216 * INFO, We have issued a GetInfo command and is awaiting a reply.
218 static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event,
221 IRDA_ASSERT(self != NULL, return -1;);
224 case IRLAN_DATA_INDICATION:
225 IRDA_ASSERT(skb != NULL, return -1;);
227 irlan_client_parse_response(self, skb);
229 irlan_next_client_state(self, IRLAN_MEDIA);
231 irlan_get_media_char(self);
234 case IRLAN_LMP_DISCONNECT:
235 case IRLAN_LAP_DISCONNECT:
236 irlan_next_client_state(self, IRLAN_IDLE);
238 case IRLAN_WATCHDOG_TIMEOUT:
239 pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
242 pr_debug("%s(), Unknown event %d\n", __func__ , event);
252 * Function irlan_client_state_media (self, event, skb, info)
254 * MEDIA, The irlan_client has issued a GetMedia command and is awaiting a
258 static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
261 IRDA_ASSERT(self != NULL, return -1;);
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);
269 case IRLAN_LMP_DISCONNECT:
270 case IRLAN_LAP_DISCONNECT:
271 irlan_next_client_state(self, IRLAN_IDLE);
273 case IRLAN_WATCHDOG_TIMEOUT:
274 pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
277 pr_debug("%s(), Unknown event %d\n", __func__ , event);
287 * Function irlan_client_state_open (self, event, skb, info)
289 * OPEN, The irlan_client has issued a OpenData command and is awaiting a
293 static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event,
298 IRDA_ASSERT(self != NULL, return -1;);
301 case IRLAN_DATA_INDICATION:
302 irlan_client_parse_response(self, skb);
305 * Check if we have got the remote TSAP for data
308 IRDA_ASSERT(self->dtsap_sel_data != 0, return -1;);
310 /* Check which access type we are dealing with */
311 switch (self->client.access_type) {
313 if (self->provider.state == IRLAN_OPEN) {
315 irlan_next_client_state(self, IRLAN_ARB);
316 irlan_do_client_event(self, IRLAN_CHECK_CON_ARB,
320 irlan_next_client_state(self, IRLAN_WAIT);
325 qos.link_disc_time.bits = 0x01; /* 3 secs */
327 irttp_connect_request(self->tsap_data,
328 self->dtsap_sel_data,
329 self->saddr, self->daddr, &qos,
332 irlan_next_client_state(self, IRLAN_DATA);
335 pr_debug("%s(), unknown access type!\n", __func__);
339 case IRLAN_LMP_DISCONNECT:
340 case IRLAN_LAP_DISCONNECT:
341 irlan_next_client_state(self, IRLAN_IDLE);
343 case IRLAN_WATCHDOG_TIMEOUT:
344 pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
347 pr_debug("%s(), Unknown event %d\n", __func__ , event);
358 * Function irlan_client_state_wait (self, event, skb, info)
360 * WAIT, The irlan_client is waiting for the local provider to enter the
361 * provider OPEN state.
364 static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event,
367 IRDA_ASSERT(self != NULL, return -1;);
370 case IRLAN_PROVIDER_SIGNAL:
371 irlan_next_client_state(self, IRLAN_ARB);
372 irlan_do_client_event(self, IRLAN_CHECK_CON_ARB, NULL);
374 case IRLAN_LMP_DISCONNECT:
375 case IRLAN_LAP_DISCONNECT:
376 irlan_next_client_state(self, IRLAN_IDLE);
378 case IRLAN_WATCHDOG_TIMEOUT:
379 pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
382 pr_debug("%s(), Unknown event %d\n", __func__ , event);
391 static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event,
396 IRDA_ASSERT(self != NULL, return -1;);
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)
406 qos.link_disc_time.bits = 0x01; /* 3 secs */
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,
413 } else if (self->client.recv_arb_val >
414 self->provider.send_arb_val)
416 pr_debug("%s(), lost the battle :-(\n", __func__);
419 case IRLAN_DATA_CONNECT_INDICATION:
420 irlan_next_client_state(self, IRLAN_DATA);
422 case IRLAN_LMP_DISCONNECT:
423 case IRLAN_LAP_DISCONNECT:
424 irlan_next_client_state(self, IRLAN_IDLE);
426 case IRLAN_WATCHDOG_TIMEOUT:
427 pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__);
430 pr_debug("%s(), Unknown event %d\n", __func__ , event);
440 * Function irlan_client_state_data (self, event, skb, info)
442 * DATA, The data channel is connected, allowing data transfers between
443 * the local and remote machines.
446 static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event,
449 IRDA_ASSERT(self != NULL, return -1;);
450 IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
453 case IRLAN_DATA_INDICATION:
454 irlan_client_parse_response(self, skb);
456 case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
457 case IRLAN_LAP_DISCONNECT:
458 irlan_next_client_state(self, IRLAN_IDLE);
461 pr_debug("%s(), Unknown event %d\n", __func__ , event);
471 * Function irlan_client_state_close (self, event, skb, info)
476 static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,
486 * Function irlan_client_state_sync (self, event, skb, info)
491 static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event,