diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /net/irda/irlan/irlan_provider.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'net/irda/irlan/irlan_provider.c')
-rw-r--r-- | net/irda/irlan/irlan_provider.c | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/net/irda/irlan/irlan_provider.c b/net/irda/irlan/irlan_provider.c new file mode 100644 index 000000000000..39c202d1c374 --- /dev/null +++ b/net/irda/irlan/irlan_provider.c | |||
@@ -0,0 +1,413 @@ | |||
1 | /********************************************************************* | ||
2 | * | ||
3 | * Filename: irlan_provider.c | ||
4 | * Version: 0.9 | ||
5 | * Description: IrDA LAN Access Protocol Implementation | ||
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:10 1999 | ||
10 | * Modified by: Dag Brattli <dagb@cs.uit.no> | ||
11 | * Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov> | ||
12 | * slip.c by Laurence Culhane, <loz@holmes.demon.co.uk> | ||
13 | * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> | ||
14 | * | ||
15 | * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, | ||
16 | * All Rights Reserved. | ||
17 | * | ||
18 | * This program is free software; you can redistribute it and/or | ||
19 | * modify it under the terms of the GNU General Public License as | ||
20 | * published by the Free Software Foundation; either version 2 of | ||
21 | * the License, or (at your option) any later version. | ||
22 | * | ||
23 | * Neither Dag Brattli nor University of Tromsų admit liability nor | ||
24 | * provide warranty for any of this software. This material is | ||
25 | * provided "AS-IS" and at no charge. | ||
26 | * | ||
27 | ********************************************************************/ | ||
28 | |||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/string.h> | ||
31 | #include <linux/errno.h> | ||
32 | #include <linux/netdevice.h> | ||
33 | #include <linux/etherdevice.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/random.h> | ||
36 | #include <linux/bitops.h> | ||
37 | |||
38 | #include <asm/system.h> | ||
39 | #include <asm/byteorder.h> | ||
40 | |||
41 | #include <net/irda/irda.h> | ||
42 | #include <net/irda/irttp.h> | ||
43 | #include <net/irda/irlmp.h> | ||
44 | #include <net/irda/irias_object.h> | ||
45 | #include <net/irda/iriap.h> | ||
46 | #include <net/irda/timer.h> | ||
47 | |||
48 | #include <net/irda/irlan_common.h> | ||
49 | #include <net/irda/irlan_eth.h> | ||
50 | #include <net/irda/irlan_event.h> | ||
51 | #include <net/irda/irlan_provider.h> | ||
52 | #include <net/irda/irlan_filter.h> | ||
53 | #include <net/irda/irlan_client.h> | ||
54 | |||
55 | static void irlan_provider_connect_indication(void *instance, void *sap, | ||
56 | struct qos_info *qos, | ||
57 | __u32 max_sdu_size, | ||
58 | __u8 max_header_size, | ||
59 | struct sk_buff *skb); | ||
60 | |||
61 | /* | ||
62 | * Function irlan_provider_control_data_indication (handle, skb) | ||
63 | * | ||
64 | * This function gets the data that is received on the control channel | ||
65 | * | ||
66 | */ | ||
67 | static int irlan_provider_data_indication(void *instance, void *sap, | ||
68 | struct sk_buff *skb) | ||
69 | { | ||
70 | struct irlan_cb *self; | ||
71 | __u8 code; | ||
72 | |||
73 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
74 | |||
75 | self = (struct irlan_cb *) instance; | ||
76 | |||
77 | IRDA_ASSERT(self != NULL, return -1;); | ||
78 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); | ||
79 | |||
80 | IRDA_ASSERT(skb != NULL, return -1;); | ||
81 | |||
82 | code = skb->data[0]; | ||
83 | switch(code) { | ||
84 | case CMD_GET_PROVIDER_INFO: | ||
85 | IRDA_DEBUG(4, "Got GET_PROVIDER_INFO command!\n"); | ||
86 | irlan_do_provider_event(self, IRLAN_GET_INFO_CMD, skb); | ||
87 | break; | ||
88 | |||
89 | case CMD_GET_MEDIA_CHAR: | ||
90 | IRDA_DEBUG(4, "Got GET_MEDIA_CHAR command!\n"); | ||
91 | irlan_do_provider_event(self, IRLAN_GET_MEDIA_CMD, skb); | ||
92 | break; | ||
93 | case CMD_OPEN_DATA_CHANNEL: | ||
94 | IRDA_DEBUG(4, "Got OPEN_DATA_CHANNEL command!\n"); | ||
95 | irlan_do_provider_event(self, IRLAN_OPEN_DATA_CMD, skb); | ||
96 | break; | ||
97 | case CMD_FILTER_OPERATION: | ||
98 | IRDA_DEBUG(4, "Got FILTER_OPERATION command!\n"); | ||
99 | irlan_do_provider_event(self, IRLAN_FILTER_CONFIG_CMD, skb); | ||
100 | break; | ||
101 | case CMD_RECONNECT_DATA_CHAN: | ||
102 | IRDA_DEBUG(2, "%s(), Got RECONNECT_DATA_CHAN command\n", __FUNCTION__ ); | ||
103 | IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __FUNCTION__ ); | ||
104 | break; | ||
105 | case CMD_CLOSE_DATA_CHAN: | ||
106 | IRDA_DEBUG(2, "Got CLOSE_DATA_CHAN command!\n"); | ||
107 | IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __FUNCTION__ ); | ||
108 | break; | ||
109 | default: | ||
110 | IRDA_DEBUG(2, "%s(), Unknown command!\n", __FUNCTION__ ); | ||
111 | break; | ||
112 | } | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * Function irlan_provider_connect_indication (handle, skb, priv) | ||
118 | * | ||
119 | * Got connection from peer IrLAN client | ||
120 | * | ||
121 | */ | ||
122 | static void irlan_provider_connect_indication(void *instance, void *sap, | ||
123 | struct qos_info *qos, | ||
124 | __u32 max_sdu_size, | ||
125 | __u8 max_header_size, | ||
126 | struct sk_buff *skb) | ||
127 | { | ||
128 | struct irlan_cb *self; | ||
129 | struct tsap_cb *tsap; | ||
130 | __u32 saddr, daddr; | ||
131 | |||
132 | IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); | ||
133 | |||
134 | self = (struct irlan_cb *) instance; | ||
135 | tsap = (struct tsap_cb *) sap; | ||
136 | |||
137 | IRDA_ASSERT(self != NULL, return;); | ||
138 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
139 | |||
140 | IRDA_ASSERT(tsap == self->provider.tsap_ctrl,return;); | ||
141 | IRDA_ASSERT(self->provider.state == IRLAN_IDLE, return;); | ||
142 | |||
143 | daddr = irttp_get_daddr(tsap); | ||
144 | saddr = irttp_get_saddr(tsap); | ||
145 | self->provider.max_sdu_size = max_sdu_size; | ||
146 | self->provider.max_header_size = max_header_size; | ||
147 | |||
148 | irlan_do_provider_event(self, IRLAN_CONNECT_INDICATION, NULL); | ||
149 | |||
150 | /* | ||
151 | * If we are in peer mode, the client may not have got the discovery | ||
152 | * indication it needs to make progress. If the client is still in | ||
153 | * IDLE state, we must kick it. | ||
154 | */ | ||
155 | if ((self->provider.access_type == ACCESS_PEER) && | ||
156 | (self->client.state == IRLAN_IDLE)) | ||
157 | { | ||
158 | irlan_client_wakeup(self, self->saddr, self->daddr); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | /* | ||
163 | * Function irlan_provider_connect_response (handle) | ||
164 | * | ||
165 | * Accept incoming connection | ||
166 | * | ||
167 | */ | ||
168 | void irlan_provider_connect_response(struct irlan_cb *self, | ||
169 | struct tsap_cb *tsap) | ||
170 | { | ||
171 | IRDA_ASSERT(self != NULL, return;); | ||
172 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
173 | |||
174 | /* Just accept */ | ||
175 | irttp_connect_response(tsap, IRLAN_MTU, NULL); | ||
176 | } | ||
177 | |||
178 | static void irlan_provider_disconnect_indication(void *instance, void *sap, | ||
179 | LM_REASON reason, | ||
180 | struct sk_buff *userdata) | ||
181 | { | ||
182 | struct irlan_cb *self; | ||
183 | struct tsap_cb *tsap; | ||
184 | |||
185 | IRDA_DEBUG(4, "%s(), reason=%d\n", __FUNCTION__ , reason); | ||
186 | |||
187 | self = (struct irlan_cb *) instance; | ||
188 | tsap = (struct tsap_cb *) sap; | ||
189 | |||
190 | IRDA_ASSERT(self != NULL, return;); | ||
191 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
192 | IRDA_ASSERT(tsap != NULL, return;); | ||
193 | IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;); | ||
194 | |||
195 | IRDA_ASSERT(tsap == self->provider.tsap_ctrl, return;); | ||
196 | |||
197 | irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL); | ||
198 | } | ||
199 | |||
200 | /* | ||
201 | * Function irlan_parse_open_data_cmd (self, skb) | ||
202 | * | ||
203 | * | ||
204 | * | ||
205 | */ | ||
206 | int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb) | ||
207 | { | ||
208 | int ret; | ||
209 | |||
210 | ret = irlan_provider_parse_command(self, CMD_OPEN_DATA_CHANNEL, skb); | ||
211 | |||
212 | /* Open data channel */ | ||
213 | irlan_open_data_tsap(self); | ||
214 | |||
215 | return ret; | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * Function parse_command (skb) | ||
220 | * | ||
221 | * Extract all parameters from received buffer, then feed them to | ||
222 | * check_params for parsing | ||
223 | * | ||
224 | */ | ||
225 | int irlan_provider_parse_command(struct irlan_cb *self, int cmd, | ||
226 | struct sk_buff *skb) | ||
227 | { | ||
228 | __u8 *frame; | ||
229 | __u8 *ptr; | ||
230 | int count; | ||
231 | __u16 val_len; | ||
232 | int i; | ||
233 | char *name; | ||
234 | char *value; | ||
235 | int ret = RSP_SUCCESS; | ||
236 | |||
237 | IRDA_ASSERT(skb != NULL, return -RSP_PROTOCOL_ERROR;); | ||
238 | |||
239 | IRDA_DEBUG(4, "%s(), skb->len=%d\n", __FUNCTION__ , (int)skb->len); | ||
240 | |||
241 | IRDA_ASSERT(self != NULL, return -RSP_PROTOCOL_ERROR;); | ||
242 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -RSP_PROTOCOL_ERROR;); | ||
243 | |||
244 | if (!skb) | ||
245 | return -RSP_PROTOCOL_ERROR; | ||
246 | |||
247 | frame = skb->data; | ||
248 | |||
249 | name = kmalloc(255, GFP_ATOMIC); | ||
250 | if (!name) | ||
251 | return -RSP_INSUFFICIENT_RESOURCES; | ||
252 | value = kmalloc(1016, GFP_ATOMIC); | ||
253 | if (!value) { | ||
254 | kfree(name); | ||
255 | return -RSP_INSUFFICIENT_RESOURCES; | ||
256 | } | ||
257 | |||
258 | /* How many parameters? */ | ||
259 | count = frame[1]; | ||
260 | |||
261 | IRDA_DEBUG(4, "Got %d parameters\n", count); | ||
262 | |||
263 | ptr = frame+2; | ||
264 | |||
265 | /* For all parameters */ | ||
266 | for (i=0; i<count;i++) { | ||
267 | ret = irlan_extract_param(ptr, name, value, &val_len); | ||
268 | if (ret < 0) { | ||
269 | IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __FUNCTION__ ); | ||
270 | break; | ||
271 | } | ||
272 | ptr+=ret; | ||
273 | ret = RSP_SUCCESS; | ||
274 | irlan_check_command_param(self, name, value); | ||
275 | } | ||
276 | /* Cleanup */ | ||
277 | kfree(name); | ||
278 | kfree(value); | ||
279 | |||
280 | return ret; | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * Function irlan_provider_send_reply (self, info) | ||
285 | * | ||
286 | * Send reply to query to peer IrLAN layer | ||
287 | * | ||
288 | */ | ||
289 | void irlan_provider_send_reply(struct irlan_cb *self, int command, | ||
290 | int ret_code) | ||
291 | { | ||
292 | struct sk_buff *skb; | ||
293 | |||
294 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
295 | |||
296 | IRDA_ASSERT(self != NULL, return;); | ||
297 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
298 | |||
299 | skb = dev_alloc_skb(128); | ||
300 | if (!skb) | ||
301 | return; | ||
302 | |||
303 | /* Reserve space for TTP, LMP, and LAP header */ | ||
304 | skb_reserve(skb, self->provider.max_header_size); | ||
305 | skb_put(skb, 2); | ||
306 | |||
307 | switch (command) { | ||
308 | case CMD_GET_PROVIDER_INFO: | ||
309 | skb->data[0] = 0x00; /* Success */ | ||
310 | skb->data[1] = 0x02; /* 2 parameters */ | ||
311 | switch (self->media) { | ||
312 | case MEDIA_802_3: | ||
313 | irlan_insert_string_param(skb, "MEDIA", "802.3"); | ||
314 | break; | ||
315 | case MEDIA_802_5: | ||
316 | irlan_insert_string_param(skb, "MEDIA", "802.5"); | ||
317 | break; | ||
318 | default: | ||
319 | IRDA_DEBUG(2, "%s(), unknown media type!\n", __FUNCTION__ ); | ||
320 | break; | ||
321 | } | ||
322 | irlan_insert_short_param(skb, "IRLAN_VER", 0x0101); | ||
323 | break; | ||
324 | |||
325 | case CMD_GET_MEDIA_CHAR: | ||
326 | skb->data[0] = 0x00; /* Success */ | ||
327 | skb->data[1] = 0x05; /* 5 parameters */ | ||
328 | irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED"); | ||
329 | irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST"); | ||
330 | irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST"); | ||
331 | |||
332 | switch (self->provider.access_type) { | ||
333 | case ACCESS_DIRECT: | ||
334 | irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT"); | ||
335 | break; | ||
336 | case ACCESS_PEER: | ||
337 | irlan_insert_string_param(skb, "ACCESS_TYPE", "PEER"); | ||
338 | break; | ||
339 | case ACCESS_HOSTED: | ||
340 | irlan_insert_string_param(skb, "ACCESS_TYPE", "HOSTED"); | ||
341 | break; | ||
342 | default: | ||
343 | IRDA_DEBUG(2, "%s(), Unknown access type\n", __FUNCTION__ ); | ||
344 | break; | ||
345 | } | ||
346 | irlan_insert_short_param(skb, "MAX_FRAME", 0x05ee); | ||
347 | break; | ||
348 | case CMD_OPEN_DATA_CHANNEL: | ||
349 | skb->data[0] = 0x00; /* Success */ | ||
350 | if (self->provider.send_arb_val) { | ||
351 | skb->data[1] = 0x03; /* 3 parameters */ | ||
352 | irlan_insert_short_param(skb, "CON_ARB", | ||
353 | self->provider.send_arb_val); | ||
354 | } else | ||
355 | skb->data[1] = 0x02; /* 2 parameters */ | ||
356 | irlan_insert_byte_param(skb, "DATA_CHAN", self->stsap_sel_data); | ||
357 | irlan_insert_array_param(skb, "RECONNECT_KEY", "LINUX RULES!", | ||
358 | 12); | ||
359 | break; | ||
360 | case CMD_FILTER_OPERATION: | ||
361 | irlan_filter_request(self, skb); | ||
362 | break; | ||
363 | default: | ||
364 | IRDA_DEBUG(2, "%s(), Unknown command!\n", __FUNCTION__ ); | ||
365 | break; | ||
366 | } | ||
367 | |||
368 | irttp_data_request(self->provider.tsap_ctrl, skb); | ||
369 | } | ||
370 | |||
371 | /* | ||
372 | * Function irlan_provider_register(void) | ||
373 | * | ||
374 | * Register provider support so we can accept incoming connections. | ||
375 | * | ||
376 | */ | ||
377 | int irlan_provider_open_ctrl_tsap(struct irlan_cb *self) | ||
378 | { | ||
379 | struct tsap_cb *tsap; | ||
380 | notify_t notify; | ||
381 | |||
382 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
383 | |||
384 | IRDA_ASSERT(self != NULL, return -1;); | ||
385 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); | ||
386 | |||
387 | /* Check if already open */ | ||
388 | if (self->provider.tsap_ctrl) | ||
389 | return -1; | ||
390 | |||
391 | /* | ||
392 | * First register well known control TSAP | ||
393 | */ | ||
394 | irda_notify_init(¬ify); | ||
395 | notify.data_indication = irlan_provider_data_indication; | ||
396 | notify.connect_indication = irlan_provider_connect_indication; | ||
397 | notify.disconnect_indication = irlan_provider_disconnect_indication; | ||
398 | notify.instance = self; | ||
399 | strlcpy(notify.name, "IrLAN ctrl (p)", sizeof(notify.name)); | ||
400 | |||
401 | tsap = irttp_open_tsap(LSAP_ANY, 1, ¬ify); | ||
402 | if (!tsap) { | ||
403 | IRDA_DEBUG(2, "%s(), Got no tsap!\n", __FUNCTION__ ); | ||
404 | return -1; | ||
405 | } | ||
406 | self->provider.tsap_ctrl = tsap; | ||
407 | |||
408 | /* Register with LM-IAS */ | ||
409 | irlan_ias_register(self, tsap->stsap_sel); | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||