1/*********************************************************************
2 *
3 * Filename:      irlan_provider_event.c
4 * Version:       0.9
5 * Description:   IrLAN provider 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:   Sat Oct 30 12:52:41 1999
10 * Modified by:   Dag Brattli <dagb@cs.uit.no>
11 *
12 *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
13 *
14 *     This program is free software; you can redistribute it and/or
15 *     modify it under the terms of the GNU General Public License as
16 *     published by the Free Software Foundation; either version 2 of
17 *     the License, or (at your option) any later version.
18 *
19 *     Neither Dag Brattli nor University of Tromsø admit liability nor
20 *     provide warranty for any of this software. This material is
21 *     provided "AS-IS" and at no charge.
22 *
23 ********************************************************************/
24
25#include <net/irda/irda.h>
26#include <net/irda/iriap.h>
27#include <net/irda/irlmp.h>
28#include <net/irda/irttp.h>
29
30#include <net/irda/irlan_provider.h>
31#include <net/irda/irlan_event.h>
32
33static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
34				     struct sk_buff *skb);
35static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event,
36				     struct sk_buff *skb);
37static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event,
38				     struct sk_buff *skb);
39static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event,
40				     struct sk_buff *skb);
41
42static int (*state[])(struct irlan_cb *self, IRLAN_EVENT event,
43		      struct sk_buff *skb) =
44{
45	irlan_provider_state_idle,
46	NULL, /* Query */
47	NULL, /* Info */
48	irlan_provider_state_info,
49	NULL, /* Media */
50	irlan_provider_state_open,
51	NULL, /* Wait */
52	NULL, /* Arb */
53	irlan_provider_state_data,
54	NULL, /* Close */
55	NULL, /* Sync */
56};
57
58void irlan_do_provider_event(struct irlan_cb *self, IRLAN_EVENT event,
59			     struct sk_buff *skb)
60{
61	IRDA_ASSERT(*state[ self->provider.state] != NULL, return;);
62
63	(*state[self->provider.state]) (self, event, skb);
64}
65
66/*
67 * Function irlan_provider_state_idle (event, skb, info)
68 *
69 *    IDLE, We are waiting for an indication that there is a provider
70 *    available.
71 */
72static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
73				     struct sk_buff *skb)
74{
75	IRDA_ASSERT(self != NULL, return -1;);
76
77	switch(event) {
78	case IRLAN_CONNECT_INDICATION:
79	     irlan_provider_connect_response( self, self->provider.tsap_ctrl);
80	     irlan_next_provider_state( self, IRLAN_INFO);
81	     break;
82	default:
83		pr_debug("%s(), Unknown event %d\n", __func__ , event);
84		break;
85	}
86	if (skb)
87		dev_kfree_skb(skb);
88
89	return 0;
90}
91
92/*
93 * Function irlan_provider_state_info (self, event, skb, info)
94 *
95 *    INFO, We have issued a GetInfo command and is awaiting a reply.
96 */
97static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event,
98				     struct sk_buff *skb)
99{
100	int ret;
101
102	IRDA_ASSERT(self != NULL, return -1;);
103
104	switch(event) {
105	case IRLAN_GET_INFO_CMD:
106		/* Be sure to use 802.3 in case of peer mode */
107		if (self->provider.access_type == ACCESS_PEER) {
108			self->media = MEDIA_802_3;
109
110			/* Check if client has started yet */
111			if (self->client.state == IRLAN_IDLE) {
112				/* This should get the client going */
113				irlmp_discovery_request(8);
114			}
115		}
116
117		irlan_provider_send_reply(self, CMD_GET_PROVIDER_INFO,
118					  RSP_SUCCESS);
119		/* Keep state */
120		break;
121	case IRLAN_GET_MEDIA_CMD:
122		irlan_provider_send_reply(self, CMD_GET_MEDIA_CHAR,
123					  RSP_SUCCESS);
124		/* Keep state */
125		break;
126	case IRLAN_OPEN_DATA_CMD:
127		ret = irlan_parse_open_data_cmd(self, skb);
128		if (self->provider.access_type == ACCESS_PEER) {
129			/* FIXME: make use of random functions! */
130			self->provider.send_arb_val = (jiffies & 0xffff);
131		}
132		irlan_provider_send_reply(self, CMD_OPEN_DATA_CHANNEL, ret);
133
134		if (ret == RSP_SUCCESS) {
135			irlan_next_provider_state(self, IRLAN_OPEN);
136
137			/* Signal client that we are now open */
138			irlan_do_client_event(self, IRLAN_PROVIDER_SIGNAL, NULL);
139		}
140		break;
141	case IRLAN_LMP_DISCONNECT:  /* FALLTHROUGH */
142	case IRLAN_LAP_DISCONNECT:
143		irlan_next_provider_state(self, IRLAN_IDLE);
144		break;
145	default:
146		pr_debug("%s(), Unknown event %d\n", __func__ , event);
147		break;
148	}
149	if (skb)
150		dev_kfree_skb(skb);
151
152	return 0;
153}
154
155/*
156 * Function irlan_provider_state_open (self, event, skb, info)
157 *
158 *    OPEN, The client has issued a OpenData command and is awaiting a
159 *    reply
160 *
161 */
162static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event,
163				     struct sk_buff *skb)
164{
165	IRDA_ASSERT(self != NULL, return -1;);
166
167	switch(event) {
168	case IRLAN_FILTER_CONFIG_CMD:
169		irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb);
170		irlan_provider_send_reply(self, CMD_FILTER_OPERATION,
171					  RSP_SUCCESS);
172		/* Keep state */
173		break;
174	case IRLAN_DATA_CONNECT_INDICATION:
175		irlan_next_provider_state(self, IRLAN_DATA);
176		irlan_provider_connect_response(self, self->tsap_data);
177		break;
178	case IRLAN_LMP_DISCONNECT:  /* FALLTHROUGH */
179	case IRLAN_LAP_DISCONNECT:
180		irlan_next_provider_state(self, IRLAN_IDLE);
181		break;
182	default:
183		pr_debug("%s(), Unknown event %d\n", __func__ , event);
184		break;
185	}
186	if (skb)
187		dev_kfree_skb(skb);
188
189	return 0;
190}
191
192/*
193 * Function irlan_provider_state_data (self, event, skb, info)
194 *
195 *    DATA, The data channel is connected, allowing data transfers between
196 *    the local and remote machines.
197 *
198 */
199static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event,
200				     struct sk_buff *skb)
201{
202	IRDA_ASSERT(self != NULL, return -1;);
203	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
204
205	switch(event) {
206	case IRLAN_FILTER_CONFIG_CMD:
207		irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb);
208		irlan_provider_send_reply(self, CMD_FILTER_OPERATION,
209					  RSP_SUCCESS);
210		break;
211	case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
212	case IRLAN_LAP_DISCONNECT:
213		irlan_next_provider_state(self, IRLAN_IDLE);
214		break;
215	default:
216		pr_debug("%s(), Unknown event %d\n", __func__ , event);
217		break;
218	}
219	if (skb)
220		dev_kfree_skb(skb);
221
222	return 0;
223}
224
225
226
227
228
229
230
231
232
233
234