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 
33 static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
34 				     struct sk_buff *skb);
35 static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event,
36 				     struct sk_buff *skb);
37 static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event,
38 				     struct sk_buff *skb);
39 static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event,
40 				     struct sk_buff *skb);
41 
42 static 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 
irlan_do_provider_event(struct irlan_cb * self,IRLAN_EVENT event,struct sk_buff * skb)58 void 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  */
irlan_provider_state_idle(struct irlan_cb * self,IRLAN_EVENT event,struct sk_buff * skb)72 static 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  */
irlan_provider_state_info(struct irlan_cb * self,IRLAN_EVENT event,struct sk_buff * skb)97 static 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  */
irlan_provider_state_open(struct irlan_cb * self,IRLAN_EVENT event,struct sk_buff * skb)162 static 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  */
irlan_provider_state_data(struct irlan_cb * self,IRLAN_EVENT event,struct sk_buff * skb)199 static 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