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 |
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')
-rw-r--r-- | net/irda/irlan/Kconfig | 14 | ||||
-rw-r--r-- | net/irda/irlan/Makefile | 7 | ||||
-rw-r--r-- | net/irda/irlan/irlan_client.c | 576 | ||||
-rw-r--r-- | net/irda/irlan/irlan_client_event.c | 533 | ||||
-rw-r--r-- | net/irda/irlan/irlan_common.c | 1200 | ||||
-rw-r--r-- | net/irda/irlan/irlan_eth.c | 387 | ||||
-rw-r--r-- | net/irda/irlan/irlan_event.c | 60 | ||||
-rw-r--r-- | net/irda/irlan/irlan_filter.c | 246 | ||||
-rw-r--r-- | net/irda/irlan/irlan_provider.c | 413 | ||||
-rw-r--r-- | net/irda/irlan/irlan_provider_event.c | 241 |
10 files changed, 3677 insertions, 0 deletions
diff --git a/net/irda/irlan/Kconfig b/net/irda/irlan/Kconfig new file mode 100644 index 000000000000..951abc2e3a7f --- /dev/null +++ b/net/irda/irlan/Kconfig | |||
@@ -0,0 +1,14 @@ | |||
1 | config IRLAN | ||
2 | tristate "IrLAN protocol" | ||
3 | depends on IRDA | ||
4 | help | ||
5 | Say Y here if you want to build support for the IrLAN protocol. | ||
6 | To compile it as a module, choose M here: the module will be called | ||
7 | irlan. IrLAN emulates an Ethernet and makes it possible to put up | ||
8 | a wireless LAN using infrared beams. | ||
9 | |||
10 | The IrLAN protocol can be used to talk with infrared access points | ||
11 | like the HP NetbeamIR, or the ESI JetEye NET. You can also connect | ||
12 | to another Linux machine running the IrLAN protocol for ad-hoc | ||
13 | networking! | ||
14 | |||
diff --git a/net/irda/irlan/Makefile b/net/irda/irlan/Makefile new file mode 100644 index 000000000000..77549bc8641b --- /dev/null +++ b/net/irda/irlan/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for the Linux IrDA IrLAN protocol layer. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_IRLAN) += irlan.o | ||
6 | |||
7 | irlan-objs := irlan_common.o irlan_eth.o irlan_event.o irlan_client.o irlan_provider.o irlan_filter.o irlan_provider_event.o irlan_client_event.o | ||
diff --git a/net/irda/irlan/irlan_client.c b/net/irda/irlan/irlan_client.c new file mode 100644 index 000000000000..f8e6cb0db04b --- /dev/null +++ b/net/irda/irlan/irlan_client.c | |||
@@ -0,0 +1,576 @@ | |||
1 | /********************************************************************* | ||
2 | * | ||
3 | * Filename: irlan_client.c | ||
4 | * Version: 0.9 | ||
5 | * Description: IrDA LAN Access Protocol (IrLAN) Client | ||
6 | * Status: Experimental. | ||
7 | * Author: Dag Brattli <dagb@cs.uit.no> | ||
8 | * Created at: Sun Aug 31 20:14:37 1997 | ||
9 | * Modified at: Tue Dec 14 15:47:02 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/init.h> | ||
33 | #include <linux/netdevice.h> | ||
34 | #include <linux/etherdevice.h> | ||
35 | #include <linux/if_arp.h> | ||
36 | #include <linux/bitops.h> | ||
37 | #include <net/arp.h> | ||
38 | |||
39 | #include <asm/system.h> | ||
40 | #include <asm/byteorder.h> | ||
41 | |||
42 | #include <net/irda/irda.h> | ||
43 | #include <net/irda/irttp.h> | ||
44 | #include <net/irda/irlmp.h> | ||
45 | #include <net/irda/irias_object.h> | ||
46 | #include <net/irda/iriap.h> | ||
47 | #include <net/irda/timer.h> | ||
48 | |||
49 | #include <net/irda/irlan_common.h> | ||
50 | #include <net/irda/irlan_event.h> | ||
51 | #include <net/irda/irlan_eth.h> | ||
52 | #include <net/irda/irlan_provider.h> | ||
53 | #include <net/irda/irlan_client.h> | ||
54 | |||
55 | #undef CONFIG_IRLAN_GRATUITOUS_ARP | ||
56 | |||
57 | static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap, | ||
58 | LM_REASON reason, | ||
59 | struct sk_buff *); | ||
60 | static int irlan_client_ctrl_data_indication(void *instance, void *sap, | ||
61 | struct sk_buff *skb); | ||
62 | static void irlan_client_ctrl_connect_confirm(void *instance, void *sap, | ||
63 | struct qos_info *qos, | ||
64 | __u32 max_sdu_size, | ||
65 | __u8 max_header_size, | ||
66 | struct sk_buff *); | ||
67 | static void irlan_check_response_param(struct irlan_cb *self, char *param, | ||
68 | char *value, int val_len); | ||
69 | static void irlan_client_open_ctrl_tsap(struct irlan_cb *self); | ||
70 | |||
71 | static void irlan_client_kick_timer_expired(void *data) | ||
72 | { | ||
73 | struct irlan_cb *self = (struct irlan_cb *) data; | ||
74 | |||
75 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
76 | |||
77 | IRDA_ASSERT(self != NULL, return;); | ||
78 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
79 | |||
80 | /* | ||
81 | * If we are in peer mode, the client may not have got the discovery | ||
82 | * indication it needs to make progress. If the client is still in | ||
83 | * IDLE state, we must kick it to, but only if the provider is not IDLE | ||
84 | */ | ||
85 | if ((self->provider.access_type == ACCESS_PEER) && | ||
86 | (self->client.state == IRLAN_IDLE) && | ||
87 | (self->provider.state != IRLAN_IDLE)) { | ||
88 | irlan_client_wakeup(self, self->saddr, self->daddr); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | static void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout) | ||
93 | { | ||
94 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
95 | |||
96 | irda_start_timer(&self->client.kick_timer, timeout, (void *) self, | ||
97 | irlan_client_kick_timer_expired); | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * Function irlan_client_wakeup (self, saddr, daddr) | ||
102 | * | ||
103 | * Wake up client | ||
104 | * | ||
105 | */ | ||
106 | void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr) | ||
107 | { | ||
108 | IRDA_DEBUG(1, "%s()\n", __FUNCTION__ ); | ||
109 | |||
110 | IRDA_ASSERT(self != NULL, return;); | ||
111 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
112 | |||
113 | /* | ||
114 | * Check if we are already awake, or if we are a provider in direct | ||
115 | * mode (in that case we must leave the client idle | ||
116 | */ | ||
117 | if ((self->client.state != IRLAN_IDLE) || | ||
118 | (self->provider.access_type == ACCESS_DIRECT)) | ||
119 | { | ||
120 | IRDA_DEBUG(0, "%s(), already awake!\n", __FUNCTION__ ); | ||
121 | return; | ||
122 | } | ||
123 | |||
124 | /* Addresses may have changed! */ | ||
125 | self->saddr = saddr; | ||
126 | self->daddr = daddr; | ||
127 | |||
128 | if (self->disconnect_reason == LM_USER_REQUEST) { | ||
129 | IRDA_DEBUG(0, "%s(), still stopped by user\n", __FUNCTION__ ); | ||
130 | return; | ||
131 | } | ||
132 | |||
133 | /* Open TSAPs */ | ||
134 | irlan_client_open_ctrl_tsap(self); | ||
135 | irlan_open_data_tsap(self); | ||
136 | |||
137 | irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL); | ||
138 | |||
139 | /* Start kick timer */ | ||
140 | irlan_client_start_kick_timer(self, 2*HZ); | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * Function irlan_discovery_indication (daddr) | ||
145 | * | ||
146 | * Remote device with IrLAN server support discovered | ||
147 | * | ||
148 | */ | ||
149 | void irlan_client_discovery_indication(discinfo_t *discovery, | ||
150 | DISCOVERY_MODE mode, | ||
151 | void *priv) | ||
152 | { | ||
153 | struct irlan_cb *self; | ||
154 | __u32 saddr, daddr; | ||
155 | |||
156 | IRDA_DEBUG(1, "%s()\n", __FUNCTION__ ); | ||
157 | |||
158 | IRDA_ASSERT(discovery != NULL, return;); | ||
159 | |||
160 | /* | ||
161 | * I didn't check it, but I bet that IrLAN suffer from the same | ||
162 | * deficiency as IrComm and doesn't handle two instances | ||
163 | * simultaneously connecting to each other. | ||
164 | * Same workaround, drop passive discoveries. | ||
165 | * Jean II */ | ||
166 | if(mode == DISCOVERY_PASSIVE) | ||
167 | return; | ||
168 | |||
169 | saddr = discovery->saddr; | ||
170 | daddr = discovery->daddr; | ||
171 | |||
172 | /* Find instance */ | ||
173 | rcu_read_lock(); | ||
174 | self = irlan_get_any(); | ||
175 | if (self) { | ||
176 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
177 | |||
178 | IRDA_DEBUG(1, "%s(), Found instance (%08x)!\n", __FUNCTION__ , | ||
179 | daddr); | ||
180 | |||
181 | irlan_client_wakeup(self, saddr, daddr); | ||
182 | } | ||
183 | rcu_read_unlock(); | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * Function irlan_client_data_indication (handle, skb) | ||
188 | * | ||
189 | * This function gets the data that is received on the control channel | ||
190 | * | ||
191 | */ | ||
192 | static int irlan_client_ctrl_data_indication(void *instance, void *sap, | ||
193 | struct sk_buff *skb) | ||
194 | { | ||
195 | struct irlan_cb *self; | ||
196 | |||
197 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
198 | |||
199 | self = (struct irlan_cb *) instance; | ||
200 | |||
201 | IRDA_ASSERT(self != NULL, return -1;); | ||
202 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); | ||
203 | IRDA_ASSERT(skb != NULL, return -1;); | ||
204 | |||
205 | irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb); | ||
206 | |||
207 | /* Ready for a new command */ | ||
208 | IRDA_DEBUG(2, "%s(), clearing tx_busy\n", __FUNCTION__ ); | ||
209 | self->client.tx_busy = FALSE; | ||
210 | |||
211 | /* Check if we have some queued commands waiting to be sent */ | ||
212 | irlan_run_ctrl_tx_queue(self); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap, | ||
218 | LM_REASON reason, | ||
219 | struct sk_buff *userdata) | ||
220 | { | ||
221 | struct irlan_cb *self; | ||
222 | struct tsap_cb *tsap; | ||
223 | struct sk_buff *skb; | ||
224 | |||
225 | IRDA_DEBUG(4, "%s(), reason=%d\n", __FUNCTION__ , reason); | ||
226 | |||
227 | self = (struct irlan_cb *) instance; | ||
228 | tsap = (struct tsap_cb *) sap; | ||
229 | |||
230 | IRDA_ASSERT(self != NULL, return;); | ||
231 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
232 | IRDA_ASSERT(tsap != NULL, return;); | ||
233 | IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;); | ||
234 | |||
235 | IRDA_ASSERT(tsap == self->client.tsap_ctrl, return;); | ||
236 | |||
237 | /* Remove frames queued on the control channel */ | ||
238 | while ((skb = skb_dequeue(&self->client.txq)) != NULL) { | ||
239 | dev_kfree_skb(skb); | ||
240 | } | ||
241 | self->client.tx_busy = FALSE; | ||
242 | |||
243 | irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL); | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * Function irlan_client_open_tsaps (self) | ||
248 | * | ||
249 | * Initialize callbacks and open IrTTP TSAPs | ||
250 | * | ||
251 | */ | ||
252 | static void irlan_client_open_ctrl_tsap(struct irlan_cb *self) | ||
253 | { | ||
254 | struct tsap_cb *tsap; | ||
255 | notify_t notify; | ||
256 | |||
257 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
258 | |||
259 | IRDA_ASSERT(self != NULL, return;); | ||
260 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
261 | |||
262 | /* Check if already open */ | ||
263 | if (self->client.tsap_ctrl) | ||
264 | return; | ||
265 | |||
266 | irda_notify_init(¬ify); | ||
267 | |||
268 | /* Set up callbacks */ | ||
269 | notify.data_indication = irlan_client_ctrl_data_indication; | ||
270 | notify.connect_confirm = irlan_client_ctrl_connect_confirm; | ||
271 | notify.disconnect_indication = irlan_client_ctrl_disconnect_indication; | ||
272 | notify.instance = self; | ||
273 | strlcpy(notify.name, "IrLAN ctrl (c)", sizeof(notify.name)); | ||
274 | |||
275 | tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, ¬ify); | ||
276 | if (!tsap) { | ||
277 | IRDA_DEBUG(2, "%s(), Got no tsap!\n", __FUNCTION__ ); | ||
278 | return; | ||
279 | } | ||
280 | self->client.tsap_ctrl = tsap; | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * Function irlan_client_connect_confirm (handle, skb) | ||
285 | * | ||
286 | * Connection to peer IrLAN laye confirmed | ||
287 | * | ||
288 | */ | ||
289 | static void irlan_client_ctrl_connect_confirm(void *instance, void *sap, | ||
290 | struct qos_info *qos, | ||
291 | __u32 max_sdu_size, | ||
292 | __u8 max_header_size, | ||
293 | struct sk_buff *skb) | ||
294 | { | ||
295 | struct irlan_cb *self; | ||
296 | |||
297 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
298 | |||
299 | self = (struct irlan_cb *) instance; | ||
300 | |||
301 | IRDA_ASSERT(self != NULL, return;); | ||
302 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
303 | |||
304 | self->client.max_sdu_size = max_sdu_size; | ||
305 | self->client.max_header_size = max_header_size; | ||
306 | |||
307 | /* TODO: we could set the MTU depending on the max_sdu_size */ | ||
308 | |||
309 | irlan_do_client_event(self, IRLAN_CONNECT_COMPLETE, NULL); | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * Function print_ret_code (code) | ||
314 | * | ||
315 | * Print return code of request to peer IrLAN layer. | ||
316 | * | ||
317 | */ | ||
318 | static void print_ret_code(__u8 code) | ||
319 | { | ||
320 | switch(code) { | ||
321 | case 0: | ||
322 | printk(KERN_INFO "Success\n"); | ||
323 | break; | ||
324 | case 1: | ||
325 | IRDA_WARNING("IrLAN: Insufficient resources\n"); | ||
326 | break; | ||
327 | case 2: | ||
328 | IRDA_WARNING("IrLAN: Invalid command format\n"); | ||
329 | break; | ||
330 | case 3: | ||
331 | IRDA_WARNING("IrLAN: Command not supported\n"); | ||
332 | break; | ||
333 | case 4: | ||
334 | IRDA_WARNING("IrLAN: Parameter not supported\n"); | ||
335 | break; | ||
336 | case 5: | ||
337 | IRDA_WARNING("IrLAN: Value not supported\n"); | ||
338 | break; | ||
339 | case 6: | ||
340 | IRDA_WARNING("IrLAN: Not open\n"); | ||
341 | break; | ||
342 | case 7: | ||
343 | IRDA_WARNING("IrLAN: Authentication required\n"); | ||
344 | break; | ||
345 | case 8: | ||
346 | IRDA_WARNING("IrLAN: Invalid password\n"); | ||
347 | break; | ||
348 | case 9: | ||
349 | IRDA_WARNING("IrLAN: Protocol error\n"); | ||
350 | break; | ||
351 | case 255: | ||
352 | IRDA_WARNING("IrLAN: Asynchronous status\n"); | ||
353 | break; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | /* | ||
358 | * Function irlan_client_parse_response (self, skb) | ||
359 | * | ||
360 | * Extract all parameters from received buffer, then feed them to | ||
361 | * check_params for parsing | ||
362 | */ | ||
363 | void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb) | ||
364 | { | ||
365 | __u8 *frame; | ||
366 | __u8 *ptr; | ||
367 | int count; | ||
368 | int ret; | ||
369 | __u16 val_len; | ||
370 | int i; | ||
371 | char *name; | ||
372 | char *value; | ||
373 | |||
374 | IRDA_ASSERT(skb != NULL, return;); | ||
375 | |||
376 | IRDA_DEBUG(4, "%s() skb->len=%d\n", __FUNCTION__ , (int) skb->len); | ||
377 | |||
378 | IRDA_ASSERT(self != NULL, return;); | ||
379 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
380 | |||
381 | if (!skb) { | ||
382 | IRDA_ERROR("%s(), Got NULL skb!\n", __FUNCTION__); | ||
383 | return; | ||
384 | } | ||
385 | frame = skb->data; | ||
386 | |||
387 | /* | ||
388 | * Check return code and print it if not success | ||
389 | */ | ||
390 | if (frame[0]) { | ||
391 | print_ret_code(frame[0]); | ||
392 | return; | ||
393 | } | ||
394 | |||
395 | name = kmalloc(255, GFP_ATOMIC); | ||
396 | if (!name) | ||
397 | return; | ||
398 | value = kmalloc(1016, GFP_ATOMIC); | ||
399 | if (!value) { | ||
400 | kfree(name); | ||
401 | return; | ||
402 | } | ||
403 | |||
404 | /* How many parameters? */ | ||
405 | count = frame[1]; | ||
406 | |||
407 | IRDA_DEBUG(4, "%s(), got %d parameters\n", __FUNCTION__ , count); | ||
408 | |||
409 | ptr = frame+2; | ||
410 | |||
411 | /* For all parameters */ | ||
412 | for (i=0; i<count;i++) { | ||
413 | ret = irlan_extract_param(ptr, name, value, &val_len); | ||
414 | if (ret < 0) { | ||
415 | IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __FUNCTION__ ); | ||
416 | break; | ||
417 | } | ||
418 | ptr += ret; | ||
419 | irlan_check_response_param(self, name, value, val_len); | ||
420 | } | ||
421 | /* Cleanup */ | ||
422 | kfree(name); | ||
423 | kfree(value); | ||
424 | } | ||
425 | |||
426 | /* | ||
427 | * Function irlan_check_response_param (self, param, value, val_len) | ||
428 | * | ||
429 | * Check which parameter is received and update local variables | ||
430 | * | ||
431 | */ | ||
432 | static void irlan_check_response_param(struct irlan_cb *self, char *param, | ||
433 | char *value, int val_len) | ||
434 | { | ||
435 | __u16 tmp_cpu; /* Temporary value in host order */ | ||
436 | __u8 *bytes; | ||
437 | int i; | ||
438 | |||
439 | IRDA_DEBUG(4, "%s(), parm=%s\n", __FUNCTION__ , param); | ||
440 | |||
441 | IRDA_ASSERT(self != NULL, return;); | ||
442 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
443 | |||
444 | /* Media type */ | ||
445 | if (strcmp(param, "MEDIA") == 0) { | ||
446 | if (strcmp(value, "802.3") == 0) | ||
447 | self->media = MEDIA_802_3; | ||
448 | else | ||
449 | self->media = MEDIA_802_5; | ||
450 | return; | ||
451 | } | ||
452 | if (strcmp(param, "FILTER_TYPE") == 0) { | ||
453 | if (strcmp(value, "DIRECTED") == 0) | ||
454 | self->client.filter_type |= IRLAN_DIRECTED; | ||
455 | else if (strcmp(value, "FUNCTIONAL") == 0) | ||
456 | self->client.filter_type |= IRLAN_FUNCTIONAL; | ||
457 | else if (strcmp(value, "GROUP") == 0) | ||
458 | self->client.filter_type |= IRLAN_GROUP; | ||
459 | else if (strcmp(value, "MAC_FRAME") == 0) | ||
460 | self->client.filter_type |= IRLAN_MAC_FRAME; | ||
461 | else if (strcmp(value, "MULTICAST") == 0) | ||
462 | self->client.filter_type |= IRLAN_MULTICAST; | ||
463 | else if (strcmp(value, "BROADCAST") == 0) | ||
464 | self->client.filter_type |= IRLAN_BROADCAST; | ||
465 | else if (strcmp(value, "IPX_SOCKET") == 0) | ||
466 | self->client.filter_type |= IRLAN_IPX_SOCKET; | ||
467 | |||
468 | } | ||
469 | if (strcmp(param, "ACCESS_TYPE") == 0) { | ||
470 | if (strcmp(value, "DIRECT") == 0) | ||
471 | self->client.access_type = ACCESS_DIRECT; | ||
472 | else if (strcmp(value, "PEER") == 0) | ||
473 | self->client.access_type = ACCESS_PEER; | ||
474 | else if (strcmp(value, "HOSTED") == 0) | ||
475 | self->client.access_type = ACCESS_HOSTED; | ||
476 | else { | ||
477 | IRDA_DEBUG(2, "%s(), unknown access type!\n", __FUNCTION__ ); | ||
478 | } | ||
479 | } | ||
480 | /* IRLAN version */ | ||
481 | if (strcmp(param, "IRLAN_VER") == 0) { | ||
482 | IRDA_DEBUG(4, "IrLAN version %d.%d\n", (__u8) value[0], | ||
483 | (__u8) value[1]); | ||
484 | |||
485 | self->version[0] = value[0]; | ||
486 | self->version[1] = value[1]; | ||
487 | return; | ||
488 | } | ||
489 | /* Which remote TSAP to use for data channel */ | ||
490 | if (strcmp(param, "DATA_CHAN") == 0) { | ||
491 | self->dtsap_sel_data = value[0]; | ||
492 | IRDA_DEBUG(4, "Data TSAP = %02x\n", self->dtsap_sel_data); | ||
493 | return; | ||
494 | } | ||
495 | if (strcmp(param, "CON_ARB") == 0) { | ||
496 | memcpy(&tmp_cpu, value, 2); /* Align value */ | ||
497 | le16_to_cpus(&tmp_cpu); /* Convert to host order */ | ||
498 | self->client.recv_arb_val = tmp_cpu; | ||
499 | IRDA_DEBUG(2, "%s(), receive arb val=%d\n", __FUNCTION__ , | ||
500 | self->client.recv_arb_val); | ||
501 | } | ||
502 | if (strcmp(param, "MAX_FRAME") == 0) { | ||
503 | memcpy(&tmp_cpu, value, 2); /* Align value */ | ||
504 | le16_to_cpus(&tmp_cpu); /* Convert to host order */ | ||
505 | self->client.max_frame = tmp_cpu; | ||
506 | IRDA_DEBUG(4, "%s(), max frame=%d\n", __FUNCTION__ , | ||
507 | self->client.max_frame); | ||
508 | } | ||
509 | |||
510 | /* RECONNECT_KEY, in case the link goes down! */ | ||
511 | if (strcmp(param, "RECONNECT_KEY") == 0) { | ||
512 | IRDA_DEBUG(4, "Got reconnect key: "); | ||
513 | /* for (i = 0; i < val_len; i++) */ | ||
514 | /* printk("%02x", value[i]); */ | ||
515 | memcpy(self->client.reconnect_key, value, val_len); | ||
516 | self->client.key_len = val_len; | ||
517 | IRDA_DEBUG(4, "\n"); | ||
518 | } | ||
519 | /* FILTER_ENTRY, have we got an ethernet address? */ | ||
520 | if (strcmp(param, "FILTER_ENTRY") == 0) { | ||
521 | bytes = value; | ||
522 | IRDA_DEBUG(4, "Ethernet address = %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
523 | bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], | ||
524 | bytes[5]); | ||
525 | for (i = 0; i < 6; i++) | ||
526 | self->dev->dev_addr[i] = bytes[i]; | ||
527 | } | ||
528 | } | ||
529 | |||
530 | /* | ||
531 | * Function irlan_client_get_value_confirm (obj_id, value) | ||
532 | * | ||
533 | * Got results from remote LM-IAS | ||
534 | * | ||
535 | */ | ||
536 | void irlan_client_get_value_confirm(int result, __u16 obj_id, | ||
537 | struct ias_value *value, void *priv) | ||
538 | { | ||
539 | struct irlan_cb *self; | ||
540 | |||
541 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
542 | |||
543 | IRDA_ASSERT(priv != NULL, return;); | ||
544 | |||
545 | self = (struct irlan_cb *) priv; | ||
546 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
547 | |||
548 | /* We probably don't need to make any more queries */ | ||
549 | iriap_close(self->client.iriap); | ||
550 | self->client.iriap = NULL; | ||
551 | |||
552 | /* Check if request succeeded */ | ||
553 | if (result != IAS_SUCCESS) { | ||
554 | IRDA_DEBUG(2, "%s(), got NULL value!\n", __FUNCTION__ ); | ||
555 | irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, | ||
556 | NULL); | ||
557 | return; | ||
558 | } | ||
559 | |||
560 | switch (value->type) { | ||
561 | case IAS_INTEGER: | ||
562 | self->dtsap_sel_ctrl = value->t.integer; | ||
563 | |||
564 | if (value->t.integer != -1) { | ||
565 | irlan_do_client_event(self, IRLAN_IAS_PROVIDER_AVAIL, | ||
566 | NULL); | ||
567 | return; | ||
568 | } | ||
569 | irias_delete_value(value); | ||
570 | break; | ||
571 | default: | ||
572 | IRDA_DEBUG(2, "%s(), unknown type!\n", __FUNCTION__ ); | ||
573 | break; | ||
574 | } | ||
575 | irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL); | ||
576 | } | ||
diff --git a/net/irda/irlan/irlan_client_event.c b/net/irda/irlan/irlan_client_event.c new file mode 100644 index 000000000000..ce943b69e996 --- /dev/null +++ b/net/irda/irlan/irlan_client_event.c | |||
@@ -0,0 +1,533 @@ | |||
1 | /********************************************************************* | ||
2 | * | ||
3 | * Filename: irlan_client_event.c | ||
4 | * Version: 0.9 | ||
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> | ||
11 | * | ||
12 | * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, | ||
13 | * All Rights Reserved. | ||
14 | * | ||
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. | ||
19 | * | ||
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. | ||
23 | * | ||
24 | ********************************************************************/ | ||
25 | |||
26 | #include <linux/skbuff.h> | ||
27 | |||
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> | ||
34 | |||
35 | #include <net/irda/irlan_common.h> | ||
36 | #include <net/irda/irlan_client.h> | ||
37 | #include <net/irda/irlan_event.h> | ||
38 | |||
39 | static int irlan_client_state_idle (struct irlan_cb *self, IRLAN_EVENT event, | ||
40 | struct sk_buff *skb); | ||
41 | static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event, | ||
42 | struct sk_buff *skb); | ||
43 | static int irlan_client_state_conn (struct irlan_cb *self, IRLAN_EVENT event, | ||
44 | struct sk_buff *skb); | ||
45 | static int irlan_client_state_info (struct irlan_cb *self, IRLAN_EVENT event, | ||
46 | struct sk_buff *skb); | ||
47 | static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event, | ||
48 | struct sk_buff *skb); | ||
49 | static int irlan_client_state_open (struct irlan_cb *self, IRLAN_EVENT event, | ||
50 | struct sk_buff *skb); | ||
51 | static int irlan_client_state_wait (struct irlan_cb *self, IRLAN_EVENT event, | ||
52 | struct sk_buff *skb); | ||
53 | static int irlan_client_state_arb (struct irlan_cb *self, IRLAN_EVENT event, | ||
54 | struct sk_buff *skb); | ||
55 | static int irlan_client_state_data (struct irlan_cb *self, IRLAN_EVENT event, | ||
56 | struct sk_buff *skb); | ||
57 | static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event, | ||
58 | struct sk_buff *skb); | ||
59 | static int irlan_client_state_sync (struct irlan_cb *self, IRLAN_EVENT event, | ||
60 | struct sk_buff *skb); | ||
61 | |||
62 | static int (*state[])(struct irlan_cb *, IRLAN_EVENT event, struct sk_buff *) = | ||
63 | { | ||
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 | ||
75 | }; | ||
76 | |||
77 | void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event, | ||
78 | struct sk_buff *skb) | ||
79 | { | ||
80 | IRDA_ASSERT(self != NULL, return;); | ||
81 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
82 | |||
83 | (*state[ self->client.state]) (self, event, skb); | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * Function irlan_client_state_idle (event, skb, info) | ||
88 | * | ||
89 | * IDLE, We are waiting for an indication that there is a provider | ||
90 | * available. | ||
91 | */ | ||
92 | static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event, | ||
93 | struct sk_buff *skb) | ||
94 | { | ||
95 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
96 | |||
97 | IRDA_ASSERT(self != NULL, return -1;); | ||
98 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); | ||
99 | |||
100 | switch (event) { | ||
101 | case IRLAN_DISCOVERY_INDICATION: | ||
102 | if (self->client.iriap) { | ||
103 | IRDA_WARNING("%s(), busy with a previous query\n", | ||
104 | __FUNCTION__); | ||
105 | return -EBUSY; | ||
106 | } | ||
107 | |||
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"); | ||
115 | break; | ||
116 | case IRLAN_WATCHDOG_TIMEOUT: | ||
117 | IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); | ||
118 | break; | ||
119 | default: | ||
120 | IRDA_DEBUG(4, "%s(), Unknown event %d\n", __FUNCTION__ , event); | ||
121 | break; | ||
122 | } | ||
123 | if (skb) | ||
124 | dev_kfree_skb(skb); | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * Function irlan_client_state_query (event, skb, info) | ||
131 | * | ||
132 | * QUERY, We have queryed the remote IAS and is ready to connect | ||
133 | * to provider, just waiting for the confirm. | ||
134 | * | ||
135 | */ | ||
136 | static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event, | ||
137 | struct sk_buff *skb) | ||
138 | { | ||
139 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
140 | |||
141 | IRDA_ASSERT(self != NULL, return -1;); | ||
142 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); | ||
143 | |||
144 | switch(event) { | ||
145 | case IRLAN_IAS_PROVIDER_AVAIL: | ||
146 | IRDA_ASSERT(self->dtsap_sel_ctrl != 0, return -1;); | ||
147 | |||
148 | self->client.open_retries = 0; | ||
149 | |||
150 | irttp_connect_request(self->client.tsap_ctrl, | ||
151 | self->dtsap_sel_ctrl, | ||
152 | self->saddr, self->daddr, NULL, | ||
153 | IRLAN_MTU, NULL); | ||
154 | irlan_next_client_state(self, IRLAN_CONN); | ||
155 | break; | ||
156 | case IRLAN_IAS_PROVIDER_NOT_AVAIL: | ||
157 | IRDA_DEBUG(2, "%s(), IAS_PROVIDER_NOT_AVAIL\n", __FUNCTION__ ); | ||
158 | irlan_next_client_state(self, IRLAN_IDLE); | ||
159 | |||
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); | ||
164 | break; | ||
165 | case IRLAN_LMP_DISCONNECT: | ||
166 | case IRLAN_LAP_DISCONNECT: | ||
167 | irlan_next_client_state(self, IRLAN_IDLE); | ||
168 | break; | ||
169 | case IRLAN_WATCHDOG_TIMEOUT: | ||
170 | IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); | ||
171 | break; | ||
172 | default: | ||
173 | IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); | ||
174 | break; | ||
175 | } | ||
176 | if (skb) | ||
177 | dev_kfree_skb(skb); | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Function irlan_client_state_conn (event, skb, info) | ||
184 | * | ||
185 | * CONN, We have connected to a provider but has not issued any | ||
186 | * commands yet. | ||
187 | * | ||
188 | */ | ||
189 | static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event, | ||
190 | struct sk_buff *skb) | ||
191 | { | ||
192 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
193 | |||
194 | IRDA_ASSERT(self != NULL, return -1;); | ||
195 | |||
196 | switch (event) { | ||
197 | case IRLAN_CONNECT_COMPLETE: | ||
198 | /* Send getinfo cmd */ | ||
199 | irlan_get_provider_info(self); | ||
200 | irlan_next_client_state(self, IRLAN_INFO); | ||
201 | break; | ||
202 | case IRLAN_LMP_DISCONNECT: | ||
203 | case IRLAN_LAP_DISCONNECT: | ||
204 | irlan_next_client_state(self, IRLAN_IDLE); | ||
205 | break; | ||
206 | case IRLAN_WATCHDOG_TIMEOUT: | ||
207 | IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); | ||
208 | break; | ||
209 | default: | ||
210 | IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); | ||
211 | break; | ||
212 | } | ||
213 | if (skb) | ||
214 | dev_kfree_skb(skb); | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * Function irlan_client_state_info (self, event, skb, info) | ||
221 | * | ||
222 | * INFO, We have issued a GetInfo command and is awaiting a reply. | ||
223 | */ | ||
224 | static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event, | ||
225 | struct sk_buff *skb) | ||
226 | { | ||
227 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
228 | |||
229 | IRDA_ASSERT(self != NULL, return -1;); | ||
230 | |||
231 | switch (event) { | ||
232 | case IRLAN_DATA_INDICATION: | ||
233 | IRDA_ASSERT(skb != NULL, return -1;); | ||
234 | |||
235 | irlan_client_parse_response(self, skb); | ||
236 | |||
237 | irlan_next_client_state(self, IRLAN_MEDIA); | ||
238 | |||
239 | irlan_get_media_char(self); | ||
240 | break; | ||
241 | |||
242 | case IRLAN_LMP_DISCONNECT: | ||
243 | case IRLAN_LAP_DISCONNECT: | ||
244 | irlan_next_client_state(self, IRLAN_IDLE); | ||
245 | break; | ||
246 | case IRLAN_WATCHDOG_TIMEOUT: | ||
247 | IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); | ||
248 | break; | ||
249 | default: | ||
250 | IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); | ||
251 | break; | ||
252 | } | ||
253 | if (skb) | ||
254 | dev_kfree_skb(skb); | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * Function irlan_client_state_media (self, event, skb, info) | ||
261 | * | ||
262 | * MEDIA, The irlan_client has issued a GetMedia command and is awaiting a | ||
263 | * reply. | ||
264 | * | ||
265 | */ | ||
266 | static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event, | ||
267 | struct sk_buff *skb) | ||
268 | { | ||
269 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
270 | |||
271 | IRDA_ASSERT(self != NULL, return -1;); | ||
272 | |||
273 | switch(event) { | ||
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); | ||
278 | break; | ||
279 | case IRLAN_LMP_DISCONNECT: | ||
280 | case IRLAN_LAP_DISCONNECT: | ||
281 | irlan_next_client_state(self, IRLAN_IDLE); | ||
282 | break; | ||
283 | case IRLAN_WATCHDOG_TIMEOUT: | ||
284 | IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); | ||
285 | break; | ||
286 | default: | ||
287 | IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); | ||
288 | break; | ||
289 | } | ||
290 | if (skb) | ||
291 | dev_kfree_skb(skb); | ||
292 | |||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | /* | ||
297 | * Function irlan_client_state_open (self, event, skb, info) | ||
298 | * | ||
299 | * OPEN, The irlan_client has issued a OpenData command and is awaiting a | ||
300 | * reply | ||
301 | * | ||
302 | */ | ||
303 | static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event, | ||
304 | struct sk_buff *skb) | ||
305 | { | ||
306 | struct qos_info qos; | ||
307 | |||
308 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
309 | |||
310 | IRDA_ASSERT(self != NULL, return -1;); | ||
311 | |||
312 | switch(event) { | ||
313 | case IRLAN_DATA_INDICATION: | ||
314 | irlan_client_parse_response(self, skb); | ||
315 | |||
316 | /* | ||
317 | * Check if we have got the remote TSAP for data | ||
318 | * communications | ||
319 | */ | ||
320 | IRDA_ASSERT(self->dtsap_sel_data != 0, return -1;); | ||
321 | |||
322 | /* Check which access type we are dealing with */ | ||
323 | switch (self->client.access_type) { | ||
324 | case ACCESS_PEER: | ||
325 | if (self->provider.state == IRLAN_OPEN) { | ||
326 | |||
327 | irlan_next_client_state(self, IRLAN_ARB); | ||
328 | irlan_do_client_event(self, IRLAN_CHECK_CON_ARB, | ||
329 | NULL); | ||
330 | } else { | ||
331 | |||
332 | irlan_next_client_state(self, IRLAN_WAIT); | ||
333 | } | ||
334 | break; | ||
335 | case ACCESS_DIRECT: | ||
336 | case ACCESS_HOSTED: | ||
337 | qos.link_disc_time.bits = 0x01; /* 3 secs */ | ||
338 | |||
339 | irttp_connect_request(self->tsap_data, | ||
340 | self->dtsap_sel_data, | ||
341 | self->saddr, self->daddr, &qos, | ||
342 | IRLAN_MTU, NULL); | ||
343 | |||
344 | irlan_next_client_state(self, IRLAN_DATA); | ||
345 | break; | ||
346 | default: | ||
347 | IRDA_DEBUG(2, "%s(), unknown access type!\n", __FUNCTION__ ); | ||
348 | break; | ||
349 | } | ||
350 | break; | ||
351 | case IRLAN_LMP_DISCONNECT: | ||
352 | case IRLAN_LAP_DISCONNECT: | ||
353 | irlan_next_client_state(self, IRLAN_IDLE); | ||
354 | break; | ||
355 | case IRLAN_WATCHDOG_TIMEOUT: | ||
356 | IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); | ||
357 | break; | ||
358 | default: | ||
359 | IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); | ||
360 | break; | ||
361 | } | ||
362 | |||
363 | if (skb) | ||
364 | dev_kfree_skb(skb); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | /* | ||
370 | * Function irlan_client_state_wait (self, event, skb, info) | ||
371 | * | ||
372 | * WAIT, The irlan_client is waiting for the local provider to enter the | ||
373 | * provider OPEN state. | ||
374 | * | ||
375 | */ | ||
376 | static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event, | ||
377 | struct sk_buff *skb) | ||
378 | { | ||
379 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
380 | |||
381 | IRDA_ASSERT(self != NULL, return -1;); | ||
382 | |||
383 | switch(event) { | ||
384 | case IRLAN_PROVIDER_SIGNAL: | ||
385 | irlan_next_client_state(self, IRLAN_ARB); | ||
386 | irlan_do_client_event(self, IRLAN_CHECK_CON_ARB, NULL); | ||
387 | break; | ||
388 | case IRLAN_LMP_DISCONNECT: | ||
389 | case IRLAN_LAP_DISCONNECT: | ||
390 | irlan_next_client_state(self, IRLAN_IDLE); | ||
391 | break; | ||
392 | case IRLAN_WATCHDOG_TIMEOUT: | ||
393 | IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); | ||
394 | break; | ||
395 | default: | ||
396 | IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); | ||
397 | break; | ||
398 | } | ||
399 | if (skb) | ||
400 | dev_kfree_skb(skb); | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event, | ||
406 | struct sk_buff *skb) | ||
407 | { | ||
408 | struct qos_info qos; | ||
409 | |||
410 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
411 | |||
412 | IRDA_ASSERT(self != NULL, return -1;); | ||
413 | |||
414 | switch(event) { | ||
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) | ||
421 | { | ||
422 | qos.link_disc_time.bits = 0x01; /* 3 secs */ | ||
423 | |||
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, | ||
428 | IRLAN_MTU, NULL); | ||
429 | } else if (self->client.recv_arb_val > | ||
430 | self->provider.send_arb_val) | ||
431 | { | ||
432 | IRDA_DEBUG(2, "%s(), lost the battle :-(\n", __FUNCTION__ ); | ||
433 | } | ||
434 | break; | ||
435 | case IRLAN_DATA_CONNECT_INDICATION: | ||
436 | irlan_next_client_state(self, IRLAN_DATA); | ||
437 | break; | ||
438 | case IRLAN_LMP_DISCONNECT: | ||
439 | case IRLAN_LAP_DISCONNECT: | ||
440 | irlan_next_client_state(self, IRLAN_IDLE); | ||
441 | break; | ||
442 | case IRLAN_WATCHDOG_TIMEOUT: | ||
443 | IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); | ||
444 | break; | ||
445 | default: | ||
446 | IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); | ||
447 | break; | ||
448 | } | ||
449 | if (skb) | ||
450 | dev_kfree_skb(skb); | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | /* | ||
456 | * Function irlan_client_state_data (self, event, skb, info) | ||
457 | * | ||
458 | * DATA, The data channel is connected, allowing data transfers between | ||
459 | * the local and remote machines. | ||
460 | * | ||
461 | */ | ||
462 | static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event, | ||
463 | struct sk_buff *skb) | ||
464 | { | ||
465 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
466 | |||
467 | IRDA_ASSERT(self != NULL, return -1;); | ||
468 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); | ||
469 | |||
470 | switch(event) { | ||
471 | case IRLAN_DATA_INDICATION: | ||
472 | irlan_client_parse_response(self, skb); | ||
473 | break; | ||
474 | case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */ | ||
475 | case IRLAN_LAP_DISCONNECT: | ||
476 | irlan_next_client_state(self, IRLAN_IDLE); | ||
477 | break; | ||
478 | default: | ||
479 | IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); | ||
480 | break; | ||
481 | } | ||
482 | if (skb) | ||
483 | dev_kfree_skb(skb); | ||
484 | |||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | /* | ||
489 | * Function irlan_client_state_close (self, event, skb, info) | ||
490 | * | ||
491 | * | ||
492 | * | ||
493 | */ | ||
494 | static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event, | ||
495 | struct sk_buff *skb) | ||
496 | { | ||
497 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
498 | |||
499 | if (skb) | ||
500 | dev_kfree_skb(skb); | ||
501 | |||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | /* | ||
506 | * Function irlan_client_state_sync (self, event, skb, info) | ||
507 | * | ||
508 | * | ||
509 | * | ||
510 | */ | ||
511 | static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event, | ||
512 | struct sk_buff *skb) | ||
513 | { | ||
514 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
515 | |||
516 | if (skb) | ||
517 | dev_kfree_skb(skb); | ||
518 | |||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | |||
523 | |||
524 | |||
525 | |||
526 | |||
527 | |||
528 | |||
529 | |||
530 | |||
531 | |||
532 | |||
533 | |||
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c new file mode 100644 index 000000000000..657d12210578 --- /dev/null +++ b/net/irda/irlan/irlan_common.c | |||
@@ -0,0 +1,1200 @@ | |||
1 | /********************************************************************* | ||
2 | * | ||
3 | * Filename: irlan_common.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: Sun Dec 26 21:53:10 1999 | ||
10 | * Modified by: Dag Brattli <dagb@cs.uit.no> | ||
11 | * | ||
12 | * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, | ||
13 | * All Rights Reserved. | ||
14 | * | ||
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. | ||
19 | * | ||
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. | ||
23 | * | ||
24 | ********************************************************************/ | ||
25 | |||
26 | #include <linux/config.h> | ||
27 | #include <linux/module.h> | ||
28 | |||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/string.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/errno.h> | ||
33 | #include <linux/proc_fs.h> | ||
34 | #include <linux/seq_file.h> | ||
35 | #include <linux/random.h> | ||
36 | #include <linux/netdevice.h> | ||
37 | #include <linux/etherdevice.h> | ||
38 | #include <linux/rtnetlink.h> | ||
39 | #include <linux/moduleparam.h> | ||
40 | #include <linux/bitops.h> | ||
41 | |||
42 | #include <asm/system.h> | ||
43 | #include <asm/byteorder.h> | ||
44 | |||
45 | #include <net/irda/irda.h> | ||
46 | #include <net/irda/irttp.h> | ||
47 | #include <net/irda/irlmp.h> | ||
48 | #include <net/irda/iriap.h> | ||
49 | #include <net/irda/timer.h> | ||
50 | |||
51 | #include <net/irda/irlan_common.h> | ||
52 | #include <net/irda/irlan_client.h> | ||
53 | #include <net/irda/irlan_provider.h> | ||
54 | #include <net/irda/irlan_eth.h> | ||
55 | #include <net/irda/irlan_filter.h> | ||
56 | |||
57 | |||
58 | /* | ||
59 | * Send gratuitous ARP when connected to a new AP or not. May be a clever | ||
60 | * thing to do, but for some reason the machine crashes if you use DHCP. So | ||
61 | * lets not use it by default. | ||
62 | */ | ||
63 | #undef CONFIG_IRLAN_SEND_GRATUITOUS_ARP | ||
64 | |||
65 | /* extern char sysctl_devname[]; */ | ||
66 | |||
67 | /* | ||
68 | * Master structure | ||
69 | */ | ||
70 | static LIST_HEAD(irlans); | ||
71 | |||
72 | static void *ckey; | ||
73 | static void *skey; | ||
74 | |||
75 | /* Module parameters */ | ||
76 | static int eth; /* Use "eth" or "irlan" name for devices */ | ||
77 | static int access = ACCESS_PEER; /* PEER, DIRECT or HOSTED */ | ||
78 | |||
79 | #ifdef CONFIG_PROC_FS | ||
80 | static const char *irlan_access[] = { | ||
81 | "UNKNOWN", | ||
82 | "DIRECT", | ||
83 | "PEER", | ||
84 | "HOSTED" | ||
85 | }; | ||
86 | |||
87 | static const char *irlan_media[] = { | ||
88 | "UNKNOWN", | ||
89 | "802.3", | ||
90 | "802.5" | ||
91 | }; | ||
92 | |||
93 | extern struct proc_dir_entry *proc_irda; | ||
94 | |||
95 | static int irlan_seq_open(struct inode *inode, struct file *file); | ||
96 | |||
97 | static struct file_operations irlan_fops = { | ||
98 | .owner = THIS_MODULE, | ||
99 | .open = irlan_seq_open, | ||
100 | .read = seq_read, | ||
101 | .llseek = seq_lseek, | ||
102 | .release = seq_release, | ||
103 | }; | ||
104 | |||
105 | extern struct proc_dir_entry *proc_irda; | ||
106 | #endif /* CONFIG_PROC_FS */ | ||
107 | |||
108 | static struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr); | ||
109 | static void __irlan_close(struct irlan_cb *self); | ||
110 | static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, | ||
111 | __u8 value_byte, __u16 value_short, | ||
112 | __u8 *value_array, __u16 value_len); | ||
113 | static void irlan_open_unicast_addr(struct irlan_cb *self); | ||
114 | static void irlan_get_unicast_addr(struct irlan_cb *self); | ||
115 | void irlan_close_tsaps(struct irlan_cb *self); | ||
116 | |||
117 | /* | ||
118 | * Function irlan_init (void) | ||
119 | * | ||
120 | * Initialize IrLAN layer | ||
121 | * | ||
122 | */ | ||
123 | static int __init irlan_init(void) | ||
124 | { | ||
125 | struct irlan_cb *new; | ||
126 | __u16 hints; | ||
127 | |||
128 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
129 | |||
130 | #ifdef CONFIG_PROC_FS | ||
131 | { struct proc_dir_entry *proc; | ||
132 | proc = create_proc_entry("irlan", 0, proc_irda); | ||
133 | if (!proc) { | ||
134 | printk(KERN_ERR "irlan_init: can't create /proc entry!\n"); | ||
135 | return -ENODEV; | ||
136 | } | ||
137 | |||
138 | proc->proc_fops = &irlan_fops; | ||
139 | } | ||
140 | #endif /* CONFIG_PROC_FS */ | ||
141 | |||
142 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
143 | hints = irlmp_service_to_hint(S_LAN); | ||
144 | |||
145 | /* Register with IrLMP as a client */ | ||
146 | ckey = irlmp_register_client(hints, &irlan_client_discovery_indication, | ||
147 | NULL, NULL); | ||
148 | |||
149 | /* Register with IrLMP as a service */ | ||
150 | skey = irlmp_register_service(hints); | ||
151 | |||
152 | /* Start the master IrLAN instance (the only one for now) */ | ||
153 | new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY); | ||
154 | |||
155 | /* The master will only open its (listen) control TSAP */ | ||
156 | irlan_provider_open_ctrl_tsap(new); | ||
157 | |||
158 | /* Do some fast discovery! */ | ||
159 | irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS); | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static void __exit irlan_cleanup(void) | ||
165 | { | ||
166 | struct irlan_cb *self, *next; | ||
167 | |||
168 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
169 | |||
170 | irlmp_unregister_client(ckey); | ||
171 | irlmp_unregister_service(skey); | ||
172 | |||
173 | #ifdef CONFIG_PROC_FS | ||
174 | remove_proc_entry("irlan", proc_irda); | ||
175 | #endif /* CONFIG_PROC_FS */ | ||
176 | |||
177 | /* Cleanup any leftover network devices */ | ||
178 | rtnl_lock(); | ||
179 | list_for_each_entry_safe(self, next, &irlans, dev_list) { | ||
180 | __irlan_close(self); | ||
181 | } | ||
182 | rtnl_unlock(); | ||
183 | } | ||
184 | |||
185 | /* | ||
186 | * Function irlan_open (void) | ||
187 | * | ||
188 | * Open new instance of a client/provider, we should only register the | ||
189 | * network device if this instance is ment for a particular client/provider | ||
190 | */ | ||
191 | static struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr) | ||
192 | { | ||
193 | struct net_device *dev; | ||
194 | struct irlan_cb *self; | ||
195 | |||
196 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
197 | |||
198 | /* Create network device with irlan */ | ||
199 | dev = alloc_irlandev(eth ? "eth%d" : "irlan%d"); | ||
200 | if (!dev) | ||
201 | return NULL; | ||
202 | |||
203 | self = dev->priv; | ||
204 | self->dev = dev; | ||
205 | |||
206 | /* | ||
207 | * Initialize local device structure | ||
208 | */ | ||
209 | self->magic = IRLAN_MAGIC; | ||
210 | self->saddr = saddr; | ||
211 | self->daddr = daddr; | ||
212 | |||
213 | /* Provider access can only be PEER, DIRECT, or HOSTED */ | ||
214 | self->provider.access_type = access; | ||
215 | if (access == ACCESS_DIRECT) { | ||
216 | /* | ||
217 | * Since we are emulating an IrLAN sever we will have to | ||
218 | * give ourself an ethernet address! | ||
219 | */ | ||
220 | dev->dev_addr[0] = 0x40; | ||
221 | dev->dev_addr[1] = 0x00; | ||
222 | dev->dev_addr[2] = 0x00; | ||
223 | dev->dev_addr[3] = 0x00; | ||
224 | get_random_bytes(dev->dev_addr+4, 1); | ||
225 | get_random_bytes(dev->dev_addr+5, 1); | ||
226 | } | ||
227 | |||
228 | self->media = MEDIA_802_3; | ||
229 | self->disconnect_reason = LM_USER_REQUEST; | ||
230 | init_timer(&self->watchdog_timer); | ||
231 | init_timer(&self->client.kick_timer); | ||
232 | init_waitqueue_head(&self->open_wait); | ||
233 | |||
234 | skb_queue_head_init(&self->client.txq); | ||
235 | |||
236 | irlan_next_client_state(self, IRLAN_IDLE); | ||
237 | irlan_next_provider_state(self, IRLAN_IDLE); | ||
238 | |||
239 | if (register_netdev(dev)) { | ||
240 | IRDA_DEBUG(2, "%s(), register_netdev() failed!\n", | ||
241 | __FUNCTION__ ); | ||
242 | self = NULL; | ||
243 | free_netdev(dev); | ||
244 | } else { | ||
245 | rtnl_lock(); | ||
246 | list_add_rcu(&self->dev_list, &irlans); | ||
247 | rtnl_unlock(); | ||
248 | } | ||
249 | |||
250 | return self; | ||
251 | } | ||
252 | /* | ||
253 | * Function __irlan_close (self) | ||
254 | * | ||
255 | * This function closes and deallocates the IrLAN client instances. Be | ||
256 | * aware that other functions which calls client_close() must | ||
257 | * remove self from irlans list first. | ||
258 | */ | ||
259 | static void __irlan_close(struct irlan_cb *self) | ||
260 | { | ||
261 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
262 | |||
263 | ASSERT_RTNL(); | ||
264 | IRDA_ASSERT(self != NULL, return;); | ||
265 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
266 | |||
267 | del_timer_sync(&self->watchdog_timer); | ||
268 | del_timer_sync(&self->client.kick_timer); | ||
269 | |||
270 | /* Close all open connections and remove TSAPs */ | ||
271 | irlan_close_tsaps(self); | ||
272 | |||
273 | if (self->client.iriap) | ||
274 | iriap_close(self->client.iriap); | ||
275 | |||
276 | /* Remove frames queued on the control channel */ | ||
277 | skb_queue_purge(&self->client.txq); | ||
278 | |||
279 | /* Unregister and free self via destructor */ | ||
280 | unregister_netdevice(self->dev); | ||
281 | } | ||
282 | |||
283 | /* Find any instance of irlan, used for client discovery wakeup */ | ||
284 | struct irlan_cb *irlan_get_any(void) | ||
285 | { | ||
286 | struct irlan_cb *self; | ||
287 | |||
288 | list_for_each_entry_rcu(self, &irlans, dev_list) { | ||
289 | return self; | ||
290 | } | ||
291 | return NULL; | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | * Function irlan_connect_indication (instance, sap, qos, max_sdu_size, skb) | ||
296 | * | ||
297 | * Here we receive the connect indication for the data channel | ||
298 | * | ||
299 | */ | ||
300 | static void irlan_connect_indication(void *instance, void *sap, | ||
301 | struct qos_info *qos, | ||
302 | __u32 max_sdu_size, | ||
303 | __u8 max_header_size, | ||
304 | struct sk_buff *skb) | ||
305 | { | ||
306 | struct irlan_cb *self; | ||
307 | struct tsap_cb *tsap; | ||
308 | |||
309 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
310 | |||
311 | self = (struct irlan_cb *) instance; | ||
312 | tsap = (struct tsap_cb *) sap; | ||
313 | |||
314 | IRDA_ASSERT(self != NULL, return;); | ||
315 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
316 | IRDA_ASSERT(tsap == self->tsap_data,return;); | ||
317 | |||
318 | self->max_sdu_size = max_sdu_size; | ||
319 | self->max_header_size = max_header_size; | ||
320 | |||
321 | IRDA_DEBUG(0, "%s: We are now connected!\n", __FUNCTION__); | ||
322 | |||
323 | del_timer(&self->watchdog_timer); | ||
324 | |||
325 | /* If you want to pass the skb to *both* state machines, you will | ||
326 | * need to skb_clone() it, so that you don't free it twice. | ||
327 | * As the state machines don't need it, git rid of it here... | ||
328 | * Jean II */ | ||
329 | if (skb) | ||
330 | dev_kfree_skb(skb); | ||
331 | |||
332 | irlan_do_provider_event(self, IRLAN_DATA_CONNECT_INDICATION, NULL); | ||
333 | irlan_do_client_event(self, IRLAN_DATA_CONNECT_INDICATION, NULL); | ||
334 | |||
335 | if (self->provider.access_type == ACCESS_PEER) { | ||
336 | /* | ||
337 | * Data channel is open, so we are now allowed to | ||
338 | * configure the remote filter | ||
339 | */ | ||
340 | irlan_get_unicast_addr(self); | ||
341 | irlan_open_unicast_addr(self); | ||
342 | } | ||
343 | /* Ready to transfer Ethernet frames (at last) */ | ||
344 | netif_start_queue(self->dev); /* Clear reason */ | ||
345 | } | ||
346 | |||
347 | static void irlan_connect_confirm(void *instance, void *sap, | ||
348 | struct qos_info *qos, | ||
349 | __u32 max_sdu_size, | ||
350 | __u8 max_header_size, | ||
351 | struct sk_buff *skb) | ||
352 | { | ||
353 | struct irlan_cb *self; | ||
354 | |||
355 | self = (struct irlan_cb *) instance; | ||
356 | |||
357 | IRDA_ASSERT(self != NULL, return;); | ||
358 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
359 | |||
360 | self->max_sdu_size = max_sdu_size; | ||
361 | self->max_header_size = max_header_size; | ||
362 | |||
363 | /* TODO: we could set the MTU depending on the max_sdu_size */ | ||
364 | |||
365 | IRDA_DEBUG(0, "%s: We are now connected!\n", __FUNCTION__); | ||
366 | del_timer(&self->watchdog_timer); | ||
367 | |||
368 | /* | ||
369 | * Data channel is open, so we are now allowed to configure the remote | ||
370 | * filter | ||
371 | */ | ||
372 | irlan_get_unicast_addr(self); | ||
373 | irlan_open_unicast_addr(self); | ||
374 | |||
375 | /* Open broadcast and multicast filter by default */ | ||
376 | irlan_set_broadcast_filter(self, TRUE); | ||
377 | irlan_set_multicast_filter(self, TRUE); | ||
378 | |||
379 | /* Ready to transfer Ethernet frames */ | ||
380 | netif_start_queue(self->dev); | ||
381 | self->disconnect_reason = 0; /* Clear reason */ | ||
382 | #ifdef CONFIG_IRLAN_SEND_GRATUITOUS_ARP | ||
383 | irlan_eth_send_gratuitous_arp(&self->dev); | ||
384 | #endif | ||
385 | wake_up_interruptible(&self->open_wait); | ||
386 | } | ||
387 | |||
388 | /* | ||
389 | * Function irlan_client_disconnect_indication (handle) | ||
390 | * | ||
391 | * Callback function for the IrTTP layer. Indicates a disconnection of | ||
392 | * the specified connection (handle) | ||
393 | */ | ||
394 | static void irlan_disconnect_indication(void *instance, | ||
395 | void *sap, LM_REASON reason, | ||
396 | struct sk_buff *userdata) | ||
397 | { | ||
398 | struct irlan_cb *self; | ||
399 | struct tsap_cb *tsap; | ||
400 | |||
401 | IRDA_DEBUG(0, "%s(), reason=%d\n", __FUNCTION__ , reason); | ||
402 | |||
403 | self = (struct irlan_cb *) instance; | ||
404 | tsap = (struct tsap_cb *) sap; | ||
405 | |||
406 | IRDA_ASSERT(self != NULL, return;); | ||
407 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
408 | IRDA_ASSERT(tsap != NULL, return;); | ||
409 | IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;); | ||
410 | |||
411 | IRDA_ASSERT(tsap == self->tsap_data, return;); | ||
412 | |||
413 | IRDA_DEBUG(2, "IrLAN, data channel disconnected by peer!\n"); | ||
414 | |||
415 | /* Save reason so we know if we should try to reconnect or not */ | ||
416 | self->disconnect_reason = reason; | ||
417 | |||
418 | switch (reason) { | ||
419 | case LM_USER_REQUEST: /* User request */ | ||
420 | IRDA_DEBUG(2, "%s(), User requested\n", __FUNCTION__ ); | ||
421 | break; | ||
422 | case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */ | ||
423 | IRDA_DEBUG(2, "%s(), Unexpected IrLAP disconnect\n", __FUNCTION__ ); | ||
424 | break; | ||
425 | case LM_CONNECT_FAILURE: /* Failed to establish IrLAP connection */ | ||
426 | IRDA_DEBUG(2, "%s(), IrLAP connect failed\n", __FUNCTION__ ); | ||
427 | break; | ||
428 | case LM_LAP_RESET: /* IrLAP reset */ | ||
429 | IRDA_DEBUG(2, "%s(), IrLAP reset\n", __FUNCTION__ ); | ||
430 | break; | ||
431 | case LM_INIT_DISCONNECT: | ||
432 | IRDA_DEBUG(2, "%s(), IrLMP connect failed\n", __FUNCTION__ ); | ||
433 | break; | ||
434 | default: | ||
435 | IRDA_ERROR("%s(), Unknown disconnect reason\n", __FUNCTION__); | ||
436 | break; | ||
437 | } | ||
438 | |||
439 | /* If you want to pass the skb to *both* state machines, you will | ||
440 | * need to skb_clone() it, so that you don't free it twice. | ||
441 | * As the state machines don't need it, git rid of it here... | ||
442 | * Jean II */ | ||
443 | if (userdata) | ||
444 | dev_kfree_skb(userdata); | ||
445 | |||
446 | irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL); | ||
447 | irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL); | ||
448 | |||
449 | wake_up_interruptible(&self->open_wait); | ||
450 | } | ||
451 | |||
452 | void irlan_open_data_tsap(struct irlan_cb *self) | ||
453 | { | ||
454 | struct tsap_cb *tsap; | ||
455 | notify_t notify; | ||
456 | |||
457 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
458 | |||
459 | IRDA_ASSERT(self != NULL, return;); | ||
460 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
461 | |||
462 | /* Check if already open */ | ||
463 | if (self->tsap_data) | ||
464 | return; | ||
465 | |||
466 | irda_notify_init(¬ify); | ||
467 | |||
468 | notify.data_indication = irlan_eth_receive; | ||
469 | notify.udata_indication = irlan_eth_receive; | ||
470 | notify.connect_indication = irlan_connect_indication; | ||
471 | notify.connect_confirm = irlan_connect_confirm; | ||
472 | notify.flow_indication = irlan_eth_flow_indication; | ||
473 | notify.disconnect_indication = irlan_disconnect_indication; | ||
474 | notify.instance = self; | ||
475 | strlcpy(notify.name, "IrLAN data", sizeof(notify.name)); | ||
476 | |||
477 | tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, ¬ify); | ||
478 | if (!tsap) { | ||
479 | IRDA_DEBUG(2, "%s(), Got no tsap!\n", __FUNCTION__ ); | ||
480 | return; | ||
481 | } | ||
482 | self->tsap_data = tsap; | ||
483 | |||
484 | /* | ||
485 | * This is the data TSAP selector which we will pass to the client | ||
486 | * when the client ask for it. | ||
487 | */ | ||
488 | self->stsap_sel_data = self->tsap_data->stsap_sel; | ||
489 | } | ||
490 | |||
491 | void irlan_close_tsaps(struct irlan_cb *self) | ||
492 | { | ||
493 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
494 | |||
495 | IRDA_ASSERT(self != NULL, return;); | ||
496 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
497 | |||
498 | /* Disconnect and close all open TSAP connections */ | ||
499 | if (self->tsap_data) { | ||
500 | irttp_disconnect_request(self->tsap_data, NULL, P_NORMAL); | ||
501 | irttp_close_tsap(self->tsap_data); | ||
502 | self->tsap_data = NULL; | ||
503 | } | ||
504 | if (self->client.tsap_ctrl) { | ||
505 | irttp_disconnect_request(self->client.tsap_ctrl, NULL, | ||
506 | P_NORMAL); | ||
507 | irttp_close_tsap(self->client.tsap_ctrl); | ||
508 | self->client.tsap_ctrl = NULL; | ||
509 | } | ||
510 | if (self->provider.tsap_ctrl) { | ||
511 | irttp_disconnect_request(self->provider.tsap_ctrl, NULL, | ||
512 | P_NORMAL); | ||
513 | irttp_close_tsap(self->provider.tsap_ctrl); | ||
514 | self->provider.tsap_ctrl = NULL; | ||
515 | } | ||
516 | self->disconnect_reason = LM_USER_REQUEST; | ||
517 | } | ||
518 | |||
519 | /* | ||
520 | * Function irlan_ias_register (self, tsap_sel) | ||
521 | * | ||
522 | * Register with LM-IAS | ||
523 | * | ||
524 | */ | ||
525 | void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel) | ||
526 | { | ||
527 | struct ias_object *obj; | ||
528 | struct ias_value *new_value; | ||
529 | |||
530 | IRDA_ASSERT(self != NULL, return;); | ||
531 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
532 | |||
533 | /* | ||
534 | * Check if object has already been registered by a previous provider. | ||
535 | * If that is the case, we just change the value of the attribute | ||
536 | */ | ||
537 | if (!irias_find_object("IrLAN")) { | ||
538 | obj = irias_new_object("IrLAN", IAS_IRLAN_ID); | ||
539 | irias_add_integer_attrib(obj, "IrDA:TinyTP:LsapSel", tsap_sel, | ||
540 | IAS_KERNEL_ATTR); | ||
541 | irias_insert_object(obj); | ||
542 | } else { | ||
543 | new_value = irias_new_integer_value(tsap_sel); | ||
544 | irias_object_change_attribute("IrLAN", "IrDA:TinyTP:LsapSel", | ||
545 | new_value); | ||
546 | } | ||
547 | |||
548 | /* Register PnP object only if not registered before */ | ||
549 | if (!irias_find_object("PnP")) { | ||
550 | obj = irias_new_object("PnP", IAS_PNP_ID); | ||
551 | #if 0 | ||
552 | irias_add_string_attrib(obj, "Name", sysctl_devname, | ||
553 | IAS_KERNEL_ATTR); | ||
554 | #else | ||
555 | irias_add_string_attrib(obj, "Name", "Linux", IAS_KERNEL_ATTR); | ||
556 | #endif | ||
557 | irias_add_string_attrib(obj, "DeviceID", "HWP19F0", | ||
558 | IAS_KERNEL_ATTR); | ||
559 | irias_add_integer_attrib(obj, "CompCnt", 1, IAS_KERNEL_ATTR); | ||
560 | if (self->provider.access_type == ACCESS_PEER) | ||
561 | irias_add_string_attrib(obj, "Comp#01", "PNP8389", | ||
562 | IAS_KERNEL_ATTR); | ||
563 | else | ||
564 | irias_add_string_attrib(obj, "Comp#01", "PNP8294", | ||
565 | IAS_KERNEL_ATTR); | ||
566 | |||
567 | irias_add_string_attrib(obj, "Manufacturer", | ||
568 | "Linux-IrDA Project", IAS_KERNEL_ATTR); | ||
569 | irias_insert_object(obj); | ||
570 | } | ||
571 | } | ||
572 | |||
573 | /* | ||
574 | * Function irlan_run_ctrl_tx_queue (self) | ||
575 | * | ||
576 | * Try to send the next command in the control transmit queue | ||
577 | * | ||
578 | */ | ||
579 | int irlan_run_ctrl_tx_queue(struct irlan_cb *self) | ||
580 | { | ||
581 | struct sk_buff *skb; | ||
582 | |||
583 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
584 | |||
585 | if (irda_lock(&self->client.tx_busy) == FALSE) | ||
586 | return -EBUSY; | ||
587 | |||
588 | skb = skb_dequeue(&self->client.txq); | ||
589 | if (!skb) { | ||
590 | self->client.tx_busy = FALSE; | ||
591 | return 0; | ||
592 | } | ||
593 | |||
594 | /* Check that it's really possible to send commands */ | ||
595 | if ((self->client.tsap_ctrl == NULL) || | ||
596 | (self->client.state == IRLAN_IDLE)) | ||
597 | { | ||
598 | self->client.tx_busy = FALSE; | ||
599 | dev_kfree_skb(skb); | ||
600 | return -1; | ||
601 | } | ||
602 | IRDA_DEBUG(2, "%s(), sending ...\n", __FUNCTION__ ); | ||
603 | |||
604 | return irttp_data_request(self->client.tsap_ctrl, skb); | ||
605 | } | ||
606 | |||
607 | /* | ||
608 | * Function irlan_ctrl_data_request (self, skb) | ||
609 | * | ||
610 | * This function makes sure that commands on the control channel is being | ||
611 | * sent in a command/response fashion | ||
612 | */ | ||
613 | static void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb) | ||
614 | { | ||
615 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
616 | |||
617 | /* Queue command */ | ||
618 | skb_queue_tail(&self->client.txq, skb); | ||
619 | |||
620 | /* Try to send command */ | ||
621 | irlan_run_ctrl_tx_queue(self); | ||
622 | } | ||
623 | |||
624 | /* | ||
625 | * Function irlan_get_provider_info (self) | ||
626 | * | ||
627 | * Send Get Provider Information command to peer IrLAN layer | ||
628 | * | ||
629 | */ | ||
630 | void irlan_get_provider_info(struct irlan_cb *self) | ||
631 | { | ||
632 | struct sk_buff *skb; | ||
633 | __u8 *frame; | ||
634 | |||
635 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
636 | |||
637 | IRDA_ASSERT(self != NULL, return;); | ||
638 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
639 | |||
640 | skb = dev_alloc_skb(64); | ||
641 | if (!skb) | ||
642 | return; | ||
643 | |||
644 | /* Reserve space for TTP, LMP, and LAP header */ | ||
645 | skb_reserve(skb, self->client.max_header_size); | ||
646 | skb_put(skb, 2); | ||
647 | |||
648 | frame = skb->data; | ||
649 | |||
650 | frame[0] = CMD_GET_PROVIDER_INFO; | ||
651 | frame[1] = 0x00; /* Zero parameters */ | ||
652 | |||
653 | irlan_ctrl_data_request(self, skb); | ||
654 | } | ||
655 | |||
656 | /* | ||
657 | * Function irlan_open_data_channel (self) | ||
658 | * | ||
659 | * Send an Open Data Command to provider | ||
660 | * | ||
661 | */ | ||
662 | void irlan_open_data_channel(struct irlan_cb *self) | ||
663 | { | ||
664 | struct sk_buff *skb; | ||
665 | __u8 *frame; | ||
666 | |||
667 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
668 | |||
669 | IRDA_ASSERT(self != NULL, return;); | ||
670 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
671 | |||
672 | skb = dev_alloc_skb(64); | ||
673 | if (!skb) | ||
674 | return; | ||
675 | |||
676 | skb_reserve(skb, self->client.max_header_size); | ||
677 | skb_put(skb, 2); | ||
678 | |||
679 | frame = skb->data; | ||
680 | |||
681 | /* Build frame */ | ||
682 | frame[0] = CMD_OPEN_DATA_CHANNEL; | ||
683 | frame[1] = 0x02; /* Two parameters */ | ||
684 | |||
685 | irlan_insert_string_param(skb, "MEDIA", "802.3"); | ||
686 | irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT"); | ||
687 | /* irlan_insert_string_param(skb, "MODE", "UNRELIABLE"); */ | ||
688 | |||
689 | /* self->use_udata = TRUE; */ | ||
690 | |||
691 | irlan_ctrl_data_request(self, skb); | ||
692 | } | ||
693 | |||
694 | void irlan_close_data_channel(struct irlan_cb *self) | ||
695 | { | ||
696 | struct sk_buff *skb; | ||
697 | __u8 *frame; | ||
698 | |||
699 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
700 | |||
701 | IRDA_ASSERT(self != NULL, return;); | ||
702 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
703 | |||
704 | /* Check if the TSAP is still there */ | ||
705 | if (self->client.tsap_ctrl == NULL) | ||
706 | return; | ||
707 | |||
708 | skb = dev_alloc_skb(64); | ||
709 | if (!skb) | ||
710 | return; | ||
711 | |||
712 | skb_reserve(skb, self->client.max_header_size); | ||
713 | skb_put(skb, 2); | ||
714 | |||
715 | frame = skb->data; | ||
716 | |||
717 | /* Build frame */ | ||
718 | frame[0] = CMD_CLOSE_DATA_CHAN; | ||
719 | frame[1] = 0x01; /* Two parameters */ | ||
720 | |||
721 | irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data); | ||
722 | |||
723 | irlan_ctrl_data_request(self, skb); | ||
724 | } | ||
725 | |||
726 | /* | ||
727 | * Function irlan_open_unicast_addr (self) | ||
728 | * | ||
729 | * Make IrLAN provider accept ethernet frames addressed to the unicast | ||
730 | * address. | ||
731 | * | ||
732 | */ | ||
733 | static void irlan_open_unicast_addr(struct irlan_cb *self) | ||
734 | { | ||
735 | struct sk_buff *skb; | ||
736 | __u8 *frame; | ||
737 | |||
738 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
739 | |||
740 | IRDA_ASSERT(self != NULL, return;); | ||
741 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
742 | |||
743 | skb = dev_alloc_skb(128); | ||
744 | if (!skb) | ||
745 | return; | ||
746 | |||
747 | /* Reserve space for TTP, LMP, and LAP header */ | ||
748 | skb_reserve(skb, self->max_header_size); | ||
749 | skb_put(skb, 2); | ||
750 | |||
751 | frame = skb->data; | ||
752 | |||
753 | frame[0] = CMD_FILTER_OPERATION; | ||
754 | frame[1] = 0x03; /* Three parameters */ | ||
755 | irlan_insert_byte_param(skb, "DATA_CHAN" , self->dtsap_sel_data); | ||
756 | irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED"); | ||
757 | irlan_insert_string_param(skb, "FILTER_MODE", "FILTER"); | ||
758 | |||
759 | irlan_ctrl_data_request(self, skb); | ||
760 | } | ||
761 | |||
762 | /* | ||
763 | * Function irlan_set_broadcast_filter (self, status) | ||
764 | * | ||
765 | * Make IrLAN provider accept ethernet frames addressed to the broadcast | ||
766 | * address. Be careful with the use of this one, since there may be a lot | ||
767 | * of broadcast traffic out there. We can still function without this | ||
768 | * one but then _we_ have to initiate all communication with other | ||
769 | * hosts, since ARP request for this host will not be answered. | ||
770 | */ | ||
771 | void irlan_set_broadcast_filter(struct irlan_cb *self, int status) | ||
772 | { | ||
773 | struct sk_buff *skb; | ||
774 | __u8 *frame; | ||
775 | |||
776 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
777 | |||
778 | IRDA_ASSERT(self != NULL, return;); | ||
779 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
780 | |||
781 | skb = dev_alloc_skb(128); | ||
782 | if (!skb) | ||
783 | return; | ||
784 | |||
785 | /* Reserve space for TTP, LMP, and LAP header */ | ||
786 | skb_reserve(skb, self->client.max_header_size); | ||
787 | skb_put(skb, 2); | ||
788 | |||
789 | frame = skb->data; | ||
790 | |||
791 | frame[0] = CMD_FILTER_OPERATION; | ||
792 | frame[1] = 0x03; /* Three parameters */ | ||
793 | irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data); | ||
794 | irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST"); | ||
795 | if (status) | ||
796 | irlan_insert_string_param(skb, "FILTER_MODE", "FILTER"); | ||
797 | else | ||
798 | irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); | ||
799 | |||
800 | irlan_ctrl_data_request(self, skb); | ||
801 | } | ||
802 | |||
803 | /* | ||
804 | * Function irlan_set_multicast_filter (self, status) | ||
805 | * | ||
806 | * Make IrLAN provider accept ethernet frames addressed to the multicast | ||
807 | * address. | ||
808 | * | ||
809 | */ | ||
810 | void irlan_set_multicast_filter(struct irlan_cb *self, int status) | ||
811 | { | ||
812 | struct sk_buff *skb; | ||
813 | __u8 *frame; | ||
814 | |||
815 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
816 | |||
817 | IRDA_ASSERT(self != NULL, return;); | ||
818 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
819 | |||
820 | skb = dev_alloc_skb(128); | ||
821 | if (!skb) | ||
822 | return; | ||
823 | |||
824 | /* Reserve space for TTP, LMP, and LAP header */ | ||
825 | skb_reserve(skb, self->client.max_header_size); | ||
826 | skb_put(skb, 2); | ||
827 | |||
828 | frame = skb->data; | ||
829 | |||
830 | frame[0] = CMD_FILTER_OPERATION; | ||
831 | frame[1] = 0x03; /* Three parameters */ | ||
832 | irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data); | ||
833 | irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST"); | ||
834 | if (status) | ||
835 | irlan_insert_string_param(skb, "FILTER_MODE", "ALL"); | ||
836 | else | ||
837 | irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); | ||
838 | |||
839 | irlan_ctrl_data_request(self, skb); | ||
840 | } | ||
841 | |||
842 | /* | ||
843 | * Function irlan_get_unicast_addr (self) | ||
844 | * | ||
845 | * Retrieves the unicast address from the IrLAN provider. This address | ||
846 | * will be inserted into the devices structure, so the ethernet layer | ||
847 | * can construct its packets. | ||
848 | * | ||
849 | */ | ||
850 | static void irlan_get_unicast_addr(struct irlan_cb *self) | ||
851 | { | ||
852 | struct sk_buff *skb; | ||
853 | __u8 *frame; | ||
854 | |||
855 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
856 | |||
857 | IRDA_ASSERT(self != NULL, return;); | ||
858 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
859 | |||
860 | skb = dev_alloc_skb(128); | ||
861 | if (!skb) | ||
862 | return; | ||
863 | |||
864 | /* Reserve space for TTP, LMP, and LAP header */ | ||
865 | skb_reserve(skb, self->client.max_header_size); | ||
866 | skb_put(skb, 2); | ||
867 | |||
868 | frame = skb->data; | ||
869 | |||
870 | frame[0] = CMD_FILTER_OPERATION; | ||
871 | frame[1] = 0x03; /* Three parameters */ | ||
872 | irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data); | ||
873 | irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED"); | ||
874 | irlan_insert_string_param(skb, "FILTER_OPERATION", "DYNAMIC"); | ||
875 | |||
876 | irlan_ctrl_data_request(self, skb); | ||
877 | } | ||
878 | |||
879 | /* | ||
880 | * Function irlan_get_media_char (self) | ||
881 | * | ||
882 | * | ||
883 | * | ||
884 | */ | ||
885 | void irlan_get_media_char(struct irlan_cb *self) | ||
886 | { | ||
887 | struct sk_buff *skb; | ||
888 | __u8 *frame; | ||
889 | |||
890 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
891 | |||
892 | IRDA_ASSERT(self != NULL, return;); | ||
893 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
894 | |||
895 | skb = dev_alloc_skb(64); | ||
896 | if (!skb) | ||
897 | return; | ||
898 | |||
899 | /* Reserve space for TTP, LMP, and LAP header */ | ||
900 | skb_reserve(skb, self->client.max_header_size); | ||
901 | skb_put(skb, 2); | ||
902 | |||
903 | frame = skb->data; | ||
904 | |||
905 | /* Build frame */ | ||
906 | frame[0] = CMD_GET_MEDIA_CHAR; | ||
907 | frame[1] = 0x01; /* One parameter */ | ||
908 | |||
909 | irlan_insert_string_param(skb, "MEDIA", "802.3"); | ||
910 | irlan_ctrl_data_request(self, skb); | ||
911 | } | ||
912 | |||
913 | /* | ||
914 | * Function insert_byte_param (skb, param, value) | ||
915 | * | ||
916 | * Insert byte parameter into frame | ||
917 | * | ||
918 | */ | ||
919 | int irlan_insert_byte_param(struct sk_buff *skb, char *param, __u8 value) | ||
920 | { | ||
921 | return __irlan_insert_param(skb, param, IRLAN_BYTE, value, 0, NULL, 0); | ||
922 | } | ||
923 | |||
924 | int irlan_insert_short_param(struct sk_buff *skb, char *param, __u16 value) | ||
925 | { | ||
926 | return __irlan_insert_param(skb, param, IRLAN_SHORT, 0, value, NULL, 0); | ||
927 | } | ||
928 | |||
929 | /* | ||
930 | * Function insert_string (skb, param, value) | ||
931 | * | ||
932 | * Insert string parameter into frame | ||
933 | * | ||
934 | */ | ||
935 | int irlan_insert_string_param(struct sk_buff *skb, char *param, char *string) | ||
936 | { | ||
937 | int string_len = strlen(string); | ||
938 | |||
939 | return __irlan_insert_param(skb, param, IRLAN_ARRAY, 0, 0, string, | ||
940 | string_len); | ||
941 | } | ||
942 | |||
943 | /* | ||
944 | * Function insert_array_param(skb, param, value, len_value) | ||
945 | * | ||
946 | * Insert array parameter into frame | ||
947 | * | ||
948 | */ | ||
949 | int irlan_insert_array_param(struct sk_buff *skb, char *name, __u8 *array, | ||
950 | __u16 array_len) | ||
951 | { | ||
952 | return __irlan_insert_param(skb, name, IRLAN_ARRAY, 0, 0, array, | ||
953 | array_len); | ||
954 | } | ||
955 | |||
956 | /* | ||
957 | * Function insert_param (skb, param, value, byte) | ||
958 | * | ||
959 | * Insert parameter at end of buffer, structure of a parameter is: | ||
960 | * | ||
961 | * ----------------------------------------------------------------------- | ||
962 | * | Name Length[1] | Param Name[1..255] | Val Length[2] | Value[0..1016]| | ||
963 | * ----------------------------------------------------------------------- | ||
964 | */ | ||
965 | static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, | ||
966 | __u8 value_byte, __u16 value_short, | ||
967 | __u8 *value_array, __u16 value_len) | ||
968 | { | ||
969 | __u8 *frame; | ||
970 | __u8 param_len; | ||
971 | __u16 tmp_le; /* Temporary value in little endian format */ | ||
972 | int n=0; | ||
973 | |||
974 | if (skb == NULL) { | ||
975 | IRDA_DEBUG(2, "%s(), Got NULL skb\n", __FUNCTION__ ); | ||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | param_len = strlen(param); | ||
980 | switch (type) { | ||
981 | case IRLAN_BYTE: | ||
982 | value_len = 1; | ||
983 | break; | ||
984 | case IRLAN_SHORT: | ||
985 | value_len = 2; | ||
986 | break; | ||
987 | case IRLAN_ARRAY: | ||
988 | IRDA_ASSERT(value_array != NULL, return 0;); | ||
989 | IRDA_ASSERT(value_len > 0, return 0;); | ||
990 | break; | ||
991 | default: | ||
992 | IRDA_DEBUG(2, "%s(), Unknown parameter type!\n", __FUNCTION__ ); | ||
993 | return 0; | ||
994 | break; | ||
995 | } | ||
996 | |||
997 | /* Insert at end of sk-buffer */ | ||
998 | frame = skb->tail; | ||
999 | |||
1000 | /* Make space for data */ | ||
1001 | if (skb_tailroom(skb) < (param_len+value_len+3)) { | ||
1002 | IRDA_DEBUG(2, "%s(), No more space at end of skb\n", __FUNCTION__ ); | ||
1003 | return 0; | ||
1004 | } | ||
1005 | skb_put(skb, param_len+value_len+3); | ||
1006 | |||
1007 | /* Insert parameter length */ | ||
1008 | frame[n++] = param_len; | ||
1009 | |||
1010 | /* Insert parameter */ | ||
1011 | memcpy(frame+n, param, param_len); n += param_len; | ||
1012 | |||
1013 | /* Insert value length (2 byte little endian format, LSB first) */ | ||
1014 | tmp_le = cpu_to_le16(value_len); | ||
1015 | memcpy(frame+n, &tmp_le, 2); n += 2; /* To avoid alignment problems */ | ||
1016 | |||
1017 | /* Insert value */ | ||
1018 | switch (type) { | ||
1019 | case IRLAN_BYTE: | ||
1020 | frame[n++] = value_byte; | ||
1021 | break; | ||
1022 | case IRLAN_SHORT: | ||
1023 | tmp_le = cpu_to_le16(value_short); | ||
1024 | memcpy(frame+n, &tmp_le, 2); n += 2; | ||
1025 | break; | ||
1026 | case IRLAN_ARRAY: | ||
1027 | memcpy(frame+n, value_array, value_len); n+=value_len; | ||
1028 | break; | ||
1029 | default: | ||
1030 | break; | ||
1031 | } | ||
1032 | IRDA_ASSERT(n == (param_len+value_len+3), return 0;); | ||
1033 | |||
1034 | return param_len+value_len+3; | ||
1035 | } | ||
1036 | |||
1037 | /* | ||
1038 | * Function irlan_extract_param (buf, name, value, len) | ||
1039 | * | ||
1040 | * Extracts a single parameter name/value pair from buffer and updates | ||
1041 | * the buffer pointer to point to the next name/value pair. | ||
1042 | */ | ||
1043 | int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len) | ||
1044 | { | ||
1045 | __u8 name_len; | ||
1046 | __u16 val_len; | ||
1047 | int n=0; | ||
1048 | |||
1049 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
1050 | |||
1051 | /* get length of parameter name (1 byte) */ | ||
1052 | name_len = buf[n++]; | ||
1053 | |||
1054 | if (name_len > 254) { | ||
1055 | IRDA_DEBUG(2, "%s(), name_len > 254\n", __FUNCTION__ ); | ||
1056 | return -RSP_INVALID_COMMAND_FORMAT; | ||
1057 | } | ||
1058 | |||
1059 | /* get parameter name */ | ||
1060 | memcpy(name, buf+n, name_len); | ||
1061 | name[name_len] = '\0'; | ||
1062 | n+=name_len; | ||
1063 | |||
1064 | /* | ||
1065 | * Get length of parameter value (2 bytes in little endian | ||
1066 | * format) | ||
1067 | */ | ||
1068 | memcpy(&val_len, buf+n, 2); /* To avoid alignment problems */ | ||
1069 | le16_to_cpus(&val_len); n+=2; | ||
1070 | |||
1071 | if (val_len > 1016) { | ||
1072 | IRDA_DEBUG(2, "%s(), parameter length to long\n", __FUNCTION__ ); | ||
1073 | return -RSP_INVALID_COMMAND_FORMAT; | ||
1074 | } | ||
1075 | *len = val_len; | ||
1076 | |||
1077 | /* get parameter value */ | ||
1078 | memcpy(value, buf+n, val_len); | ||
1079 | value[val_len] = '\0'; | ||
1080 | n+=val_len; | ||
1081 | |||
1082 | IRDA_DEBUG(4, "Parameter: %s ", name); | ||
1083 | IRDA_DEBUG(4, "Value: %s\n", value); | ||
1084 | |||
1085 | return n; | ||
1086 | } | ||
1087 | |||
1088 | #ifdef CONFIG_PROC_FS | ||
1089 | |||
1090 | /* | ||
1091 | * Start of reading /proc entries. | ||
1092 | * Return entry at pos, | ||
1093 | * or start_token to indicate print header line | ||
1094 | * or NULL if end of file | ||
1095 | */ | ||
1096 | static void *irlan_seq_start(struct seq_file *seq, loff_t *pos) | ||
1097 | { | ||
1098 | int i = 1; | ||
1099 | struct irlan_cb *self; | ||
1100 | |||
1101 | rcu_read_lock(); | ||
1102 | if (*pos == 0) | ||
1103 | return SEQ_START_TOKEN; | ||
1104 | |||
1105 | list_for_each_entry(self, &irlans, dev_list) { | ||
1106 | if (*pos == i) | ||
1107 | return self; | ||
1108 | ++i; | ||
1109 | } | ||
1110 | return NULL; | ||
1111 | } | ||
1112 | |||
1113 | /* Return entry after v, and increment pos */ | ||
1114 | static void *irlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
1115 | { | ||
1116 | struct list_head *nxt; | ||
1117 | |||
1118 | ++*pos; | ||
1119 | if (v == SEQ_START_TOKEN) | ||
1120 | nxt = irlans.next; | ||
1121 | else | ||
1122 | nxt = ((struct irlan_cb *)v)->dev_list.next; | ||
1123 | |||
1124 | return (nxt == &irlans) ? NULL | ||
1125 | : list_entry(nxt, struct irlan_cb, dev_list); | ||
1126 | } | ||
1127 | |||
1128 | /* End of reading /proc file */ | ||
1129 | static void irlan_seq_stop(struct seq_file *seq, void *v) | ||
1130 | { | ||
1131 | rcu_read_unlock(); | ||
1132 | } | ||
1133 | |||
1134 | |||
1135 | /* | ||
1136 | * Show one entry in /proc file. | ||
1137 | */ | ||
1138 | static int irlan_seq_show(struct seq_file *seq, void *v) | ||
1139 | { | ||
1140 | if (v == SEQ_START_TOKEN) | ||
1141 | seq_puts(seq, "IrLAN instances:\n"); | ||
1142 | else { | ||
1143 | struct irlan_cb *self = v; | ||
1144 | |||
1145 | IRDA_ASSERT(self != NULL, return -1;); | ||
1146 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); | ||
1147 | |||
1148 | seq_printf(seq,"ifname: %s,\n", | ||
1149 | self->dev->name); | ||
1150 | seq_printf(seq,"client state: %s, ", | ||
1151 | irlan_state[ self->client.state]); | ||
1152 | seq_printf(seq,"provider state: %s,\n", | ||
1153 | irlan_state[ self->provider.state]); | ||
1154 | seq_printf(seq,"saddr: %#08x, ", | ||
1155 | self->saddr); | ||
1156 | seq_printf(seq,"daddr: %#08x\n", | ||
1157 | self->daddr); | ||
1158 | seq_printf(seq,"version: %d.%d,\n", | ||
1159 | self->version[1], self->version[0]); | ||
1160 | seq_printf(seq,"access type: %s\n", | ||
1161 | irlan_access[self->client.access_type]); | ||
1162 | seq_printf(seq,"media: %s\n", | ||
1163 | irlan_media[self->media]); | ||
1164 | |||
1165 | seq_printf(seq,"local filter:\n"); | ||
1166 | seq_printf(seq,"remote filter: "); | ||
1167 | irlan_print_filter(seq, self->client.filter_type); | ||
1168 | seq_printf(seq,"tx busy: %s\n", | ||
1169 | netif_queue_stopped(self->dev) ? "TRUE" : "FALSE"); | ||
1170 | |||
1171 | seq_putc(seq,'\n'); | ||
1172 | } | ||
1173 | return 0; | ||
1174 | } | ||
1175 | |||
1176 | static struct seq_operations irlan_seq_ops = { | ||
1177 | .start = irlan_seq_start, | ||
1178 | .next = irlan_seq_next, | ||
1179 | .stop = irlan_seq_stop, | ||
1180 | .show = irlan_seq_show, | ||
1181 | }; | ||
1182 | |||
1183 | static int irlan_seq_open(struct inode *inode, struct file *file) | ||
1184 | { | ||
1185 | return seq_open(file, &irlan_seq_ops); | ||
1186 | } | ||
1187 | #endif | ||
1188 | |||
1189 | MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); | ||
1190 | MODULE_DESCRIPTION("The Linux IrDA LAN protocol"); | ||
1191 | MODULE_LICENSE("GPL"); | ||
1192 | |||
1193 | module_param(eth, bool, 0); | ||
1194 | MODULE_PARM_DESC(eth, "Name devices ethX (0) or irlanX (1)"); | ||
1195 | module_param(access, int, 0); | ||
1196 | MODULE_PARM_DESC(access, "Access type DIRECT=1, PEER=2, HOSTED=3"); | ||
1197 | |||
1198 | module_init(irlan_init); | ||
1199 | module_exit(irlan_cleanup); | ||
1200 | |||
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c new file mode 100644 index 000000000000..071cd2cefd8a --- /dev/null +++ b/net/irda/irlan/irlan_eth.c | |||
@@ -0,0 +1,387 @@ | |||
1 | /********************************************************************* | ||
2 | * | ||
3 | * Filename: irlan_eth.c | ||
4 | * Version: | ||
5 | * Description: | ||
6 | * Status: Experimental. | ||
7 | * Author: Dag Brattli <dagb@cs.uit.no> | ||
8 | * Created at: Thu Oct 15 08:37:58 1998 | ||
9 | * Modified at: Tue Mar 21 09:06:41 2000 | ||
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-2000 Dag Brattli, All Rights Reserved. | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or | ||
18 | * modify it under the terms of the GNU General Public License as | ||
19 | * published by the Free Software Foundation; either version 2 of | ||
20 | * the License, or (at your option) any later version. | ||
21 | * | ||
22 | * Neither Dag Brattli nor University of Tromsų admit liability nor | ||
23 | * provide warranty for any of this software. This material is | ||
24 | * provided "AS-IS" and at no charge. | ||
25 | * | ||
26 | ********************************************************************/ | ||
27 | |||
28 | #include <linux/config.h> | ||
29 | #include <linux/netdevice.h> | ||
30 | #include <linux/etherdevice.h> | ||
31 | #include <linux/inetdevice.h> | ||
32 | #include <linux/if_arp.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <net/arp.h> | ||
35 | |||
36 | #include <net/irda/irda.h> | ||
37 | #include <net/irda/irmod.h> | ||
38 | #include <net/irda/irlan_common.h> | ||
39 | #include <net/irda/irlan_client.h> | ||
40 | #include <net/irda/irlan_event.h> | ||
41 | #include <net/irda/irlan_eth.h> | ||
42 | |||
43 | static int irlan_eth_open(struct net_device *dev); | ||
44 | static int irlan_eth_close(struct net_device *dev); | ||
45 | static int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev); | ||
46 | static void irlan_eth_set_multicast_list( struct net_device *dev); | ||
47 | static struct net_device_stats *irlan_eth_get_stats(struct net_device *dev); | ||
48 | |||
49 | /* | ||
50 | * Function irlan_eth_setup (dev) | ||
51 | * | ||
52 | * The network device initialization function. | ||
53 | * | ||
54 | */ | ||
55 | static void irlan_eth_setup(struct net_device *dev) | ||
56 | { | ||
57 | dev->open = irlan_eth_open; | ||
58 | dev->stop = irlan_eth_close; | ||
59 | dev->hard_start_xmit = irlan_eth_xmit; | ||
60 | dev->get_stats = irlan_eth_get_stats; | ||
61 | dev->set_multicast_list = irlan_eth_set_multicast_list; | ||
62 | dev->destructor = free_netdev; | ||
63 | |||
64 | SET_MODULE_OWNER(dev); | ||
65 | |||
66 | ether_setup(dev); | ||
67 | |||
68 | /* | ||
69 | * Lets do all queueing in IrTTP instead of this device driver. | ||
70 | * Queueing here as well can introduce some strange latency | ||
71 | * problems, which we will avoid by setting the queue size to 0. | ||
72 | */ | ||
73 | /* | ||
74 | * The bugs in IrTTP and IrLAN that created this latency issue | ||
75 | * have now been fixed, and we can propagate flow control properly | ||
76 | * to the network layer. However, this requires a minimal queue of | ||
77 | * packets for the device. | ||
78 | * Without flow control, the Tx Queue is 14 (ttp) + 0 (dev) = 14 | ||
79 | * With flow control, the Tx Queue is 7 (ttp) + 4 (dev) = 11 | ||
80 | * See irlan_eth_flow_indication()... | ||
81 | * Note : this number was randomly selected and would need to | ||
82 | * be adjusted. | ||
83 | * Jean II */ | ||
84 | dev->tx_queue_len = 4; | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * Function alloc_irlandev | ||
89 | * | ||
90 | * Allocate network device and control block | ||
91 | * | ||
92 | */ | ||
93 | struct net_device *alloc_irlandev(const char *name) | ||
94 | { | ||
95 | return alloc_netdev(sizeof(struct irlan_cb), name, | ||
96 | irlan_eth_setup); | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * Function irlan_eth_open (dev) | ||
101 | * | ||
102 | * Network device has been opened by user | ||
103 | * | ||
104 | */ | ||
105 | static int irlan_eth_open(struct net_device *dev) | ||
106 | { | ||
107 | struct irlan_cb *self = netdev_priv(dev); | ||
108 | |||
109 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
110 | |||
111 | /* Ready to play! */ | ||
112 | netif_stop_queue(dev); /* Wait until data link is ready */ | ||
113 | |||
114 | /* We are now open, so time to do some work */ | ||
115 | self->disconnect_reason = 0; | ||
116 | irlan_client_wakeup(self, self->saddr, self->daddr); | ||
117 | |||
118 | /* Make sure we have a hardware address before we return, | ||
119 | so DHCP clients gets happy */ | ||
120 | return wait_event_interruptible(self->open_wait, | ||
121 | !self->tsap_data->connected); | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * Function irlan_eth_close (dev) | ||
126 | * | ||
127 | * Stop the ether network device, his function will usually be called by | ||
128 | * ifconfig down. We should now disconnect the link, We start the | ||
129 | * close timer, so that the instance will be removed if we are unable | ||
130 | * to discover the remote device after the disconnect. | ||
131 | */ | ||
132 | static int irlan_eth_close(struct net_device *dev) | ||
133 | { | ||
134 | struct irlan_cb *self = netdev_priv(dev); | ||
135 | |||
136 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
137 | |||
138 | /* Stop device */ | ||
139 | netif_stop_queue(dev); | ||
140 | |||
141 | irlan_close_data_channel(self); | ||
142 | irlan_close_tsaps(self); | ||
143 | |||
144 | irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL); | ||
145 | irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL); | ||
146 | |||
147 | /* Remove frames queued on the control channel */ | ||
148 | skb_queue_purge(&self->client.txq); | ||
149 | |||
150 | self->client.tx_busy = 0; | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * Function irlan_eth_tx (skb) | ||
157 | * | ||
158 | * Transmits ethernet frames over IrDA link. | ||
159 | * | ||
160 | */ | ||
161 | static int irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev) | ||
162 | { | ||
163 | struct irlan_cb *self = netdev_priv(dev); | ||
164 | int ret; | ||
165 | |||
166 | /* skb headroom large enough to contain all IrDA-headers? */ | ||
167 | if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) { | ||
168 | struct sk_buff *new_skb = | ||
169 | skb_realloc_headroom(skb, self->max_header_size); | ||
170 | |||
171 | /* We have to free the original skb anyway */ | ||
172 | dev_kfree_skb(skb); | ||
173 | |||
174 | /* Did the realloc succeed? */ | ||
175 | if (new_skb == NULL) | ||
176 | return 0; | ||
177 | |||
178 | /* Use the new skb instead */ | ||
179 | skb = new_skb; | ||
180 | } | ||
181 | |||
182 | dev->trans_start = jiffies; | ||
183 | |||
184 | /* Now queue the packet in the transport layer */ | ||
185 | if (self->use_udata) | ||
186 | ret = irttp_udata_request(self->tsap_data, skb); | ||
187 | else | ||
188 | ret = irttp_data_request(self->tsap_data, skb); | ||
189 | |||
190 | if (ret < 0) { | ||
191 | /* | ||
192 | * IrTTPs tx queue is full, so we just have to | ||
193 | * drop the frame! You might think that we should | ||
194 | * just return -1 and don't deallocate the frame, | ||
195 | * but that is dangerous since it's possible that | ||
196 | * we have replaced the original skb with a new | ||
197 | * one with larger headroom, and that would really | ||
198 | * confuse do_dev_queue_xmit() in dev.c! I have | ||
199 | * tried :-) DB | ||
200 | */ | ||
201 | /* irttp_data_request already free the packet */ | ||
202 | self->stats.tx_dropped++; | ||
203 | } else { | ||
204 | self->stats.tx_packets++; | ||
205 | self->stats.tx_bytes += skb->len; | ||
206 | } | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * Function irlan_eth_receive (handle, skb) | ||
213 | * | ||
214 | * This function gets the data that is received on the data channel | ||
215 | * | ||
216 | */ | ||
217 | int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb) | ||
218 | { | ||
219 | struct irlan_cb *self = instance; | ||
220 | |||
221 | if (skb == NULL) { | ||
222 | ++self->stats.rx_dropped; | ||
223 | return 0; | ||
224 | } | ||
225 | if (skb->len < ETH_HLEN) { | ||
226 | IRDA_DEBUG(0, "%s() : IrLAN frame too short (%d)\n", | ||
227 | __FUNCTION__, skb->len); | ||
228 | ++self->stats.rx_dropped; | ||
229 | dev_kfree_skb(skb); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * Adopt this frame! Important to set all these fields since they | ||
235 | * might have been previously set by the low level IrDA network | ||
236 | * device driver | ||
237 | */ | ||
238 | skb->dev = self->dev; | ||
239 | skb->protocol=eth_type_trans(skb, skb->dev); /* Remove eth header */ | ||
240 | |||
241 | self->stats.rx_packets++; | ||
242 | self->stats.rx_bytes += skb->len; | ||
243 | |||
244 | netif_rx(skb); /* Eat it! */ | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* | ||
250 | * Function irlan_eth_flow (status) | ||
251 | * | ||
252 | * Do flow control between IP/Ethernet and IrLAN/IrTTP. This is done by | ||
253 | * controlling the queue stop/start. | ||
254 | * | ||
255 | * The IrDA link layer has the advantage to have flow control, and | ||
256 | * IrTTP now properly handles that. Flow controlling the higher layers | ||
257 | * prevent us to drop Tx packets in here (up to 15% for a TCP socket, | ||
258 | * more for UDP socket). | ||
259 | * Also, this allow us to reduce the overall transmit queue, which means | ||
260 | * less latency in case of mixed traffic. | ||
261 | * Jean II | ||
262 | */ | ||
263 | void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) | ||
264 | { | ||
265 | struct irlan_cb *self; | ||
266 | struct net_device *dev; | ||
267 | |||
268 | self = (struct irlan_cb *) instance; | ||
269 | |||
270 | IRDA_ASSERT(self != NULL, return;); | ||
271 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
272 | |||
273 | dev = self->dev; | ||
274 | |||
275 | IRDA_ASSERT(dev != NULL, return;); | ||
276 | |||
277 | IRDA_DEBUG(0, "%s() : flow %s ; running %d\n", __FUNCTION__, | ||
278 | flow == FLOW_STOP ? "FLOW_STOP" : "FLOW_START", | ||
279 | netif_running(dev)); | ||
280 | |||
281 | switch (flow) { | ||
282 | case FLOW_STOP: | ||
283 | /* IrTTP is full, stop higher layers */ | ||
284 | netif_stop_queue(dev); | ||
285 | break; | ||
286 | case FLOW_START: | ||
287 | default: | ||
288 | /* Tell upper layers that its time to transmit frames again */ | ||
289 | /* Schedule network layer */ | ||
290 | netif_wake_queue(dev); | ||
291 | break; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | /* | ||
296 | * Function irlan_etc_send_gratuitous_arp (dev) | ||
297 | * | ||
298 | * Send gratuitous ARP to announce that we have changed | ||
299 | * hardware address, so that all peers updates their ARP tables | ||
300 | */ | ||
301 | void irlan_eth_send_gratuitous_arp(struct net_device *dev) | ||
302 | { | ||
303 | struct in_device *in_dev; | ||
304 | |||
305 | /* | ||
306 | * When we get a new MAC address do a gratuitous ARP. This | ||
307 | * is useful if we have changed access points on the same | ||
308 | * subnet. | ||
309 | */ | ||
310 | #ifdef CONFIG_INET | ||
311 | IRDA_DEBUG(4, "IrLAN: Sending gratuitous ARP\n"); | ||
312 | rcu_read_lock(); | ||
313 | in_dev = __in_dev_get(dev); | ||
314 | if (in_dev == NULL) | ||
315 | goto out; | ||
316 | if (in_dev->ifa_list) | ||
317 | |||
318 | arp_send(ARPOP_REQUEST, ETH_P_ARP, | ||
319 | in_dev->ifa_list->ifa_address, | ||
320 | dev, | ||
321 | in_dev->ifa_list->ifa_address, | ||
322 | NULL, dev->dev_addr, NULL); | ||
323 | out: | ||
324 | rcu_read_unlock(); | ||
325 | #endif /* CONFIG_INET */ | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * Function set_multicast_list (dev) | ||
330 | * | ||
331 | * Configure the filtering of the device | ||
332 | * | ||
333 | */ | ||
334 | #define HW_MAX_ADDRS 4 /* Must query to get it! */ | ||
335 | static void irlan_eth_set_multicast_list(struct net_device *dev) | ||
336 | { | ||
337 | struct irlan_cb *self = netdev_priv(dev); | ||
338 | |||
339 | IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); | ||
340 | |||
341 | /* Check if data channel has been connected yet */ | ||
342 | if (self->client.state != IRLAN_DATA) { | ||
343 | IRDA_DEBUG(1, "%s(), delaying!\n", __FUNCTION__ ); | ||
344 | return; | ||
345 | } | ||
346 | |||
347 | if (dev->flags & IFF_PROMISC) { | ||
348 | /* Enable promiscuous mode */ | ||
349 | IRDA_WARNING("Promiscous mode not implemented by IrLAN!\n"); | ||
350 | } | ||
351 | else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) { | ||
352 | /* Disable promiscuous mode, use normal mode. */ | ||
353 | IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __FUNCTION__ ); | ||
354 | /* hardware_set_filter(NULL); */ | ||
355 | |||
356 | irlan_set_multicast_filter(self, TRUE); | ||
357 | } | ||
358 | else if (dev->mc_count) { | ||
359 | IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __FUNCTION__ ); | ||
360 | /* Walk the address list, and load the filter */ | ||
361 | /* hardware_set_filter(dev->mc_list); */ | ||
362 | |||
363 | irlan_set_multicast_filter(self, TRUE); | ||
364 | } | ||
365 | else { | ||
366 | IRDA_DEBUG(4, "%s(), Clearing multicast filter\n", __FUNCTION__ ); | ||
367 | irlan_set_multicast_filter(self, FALSE); | ||
368 | } | ||
369 | |||
370 | if (dev->flags & IFF_BROADCAST) | ||
371 | irlan_set_broadcast_filter(self, TRUE); | ||
372 | else | ||
373 | irlan_set_broadcast_filter(self, FALSE); | ||
374 | } | ||
375 | |||
376 | /* | ||
377 | * Function irlan_get_stats (dev) | ||
378 | * | ||
379 | * Get the current statistics for this device | ||
380 | * | ||
381 | */ | ||
382 | static struct net_device_stats *irlan_eth_get_stats(struct net_device *dev) | ||
383 | { | ||
384 | struct irlan_cb *self = netdev_priv(dev); | ||
385 | |||
386 | return &self->stats; | ||
387 | } | ||
diff --git a/net/irda/irlan/irlan_event.c b/net/irda/irlan/irlan_event.c new file mode 100644 index 000000000000..2778d8c6aa31 --- /dev/null +++ b/net/irda/irlan/irlan_event.c | |||
@@ -0,0 +1,60 @@ | |||
1 | /********************************************************************* | ||
2 | * | ||
3 | * Filename: irlan_event.c | ||
4 | * Version: | ||
5 | * Description: | ||
6 | * Status: Experimental. | ||
7 | * Author: Dag Brattli <dagb@cs.uit.no> | ||
8 | * Created at: Tue Oct 20 09:10:16 1998 | ||
9 | * Modified at: Sat Oct 30 12:59:01 1999 | ||
10 | * Modified by: Dag Brattli <dagb@cs.uit.no> | ||
11 | * | ||
12 | * Copyright (c) 1998-1999 Dag Brattli, 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/irlan_event.h> | ||
26 | |||
27 | char *irlan_state[] = { | ||
28 | "IRLAN_IDLE", | ||
29 | "IRLAN_QUERY", | ||
30 | "IRLAN_CONN", | ||
31 | "IRLAN_INFO", | ||
32 | "IRLAN_MEDIA", | ||
33 | "IRLAN_OPEN", | ||
34 | "IRLAN_WAIT", | ||
35 | "IRLAN_ARB", | ||
36 | "IRLAN_DATA", | ||
37 | "IRLAN_CLOSE", | ||
38 | "IRLAN_SYNC", | ||
39 | }; | ||
40 | |||
41 | void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state) | ||
42 | { | ||
43 | IRDA_DEBUG(2, "%s(), %s\n", __FUNCTION__ , irlan_state[state]); | ||
44 | |||
45 | IRDA_ASSERT(self != NULL, return;); | ||
46 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
47 | |||
48 | self->client.state = state; | ||
49 | } | ||
50 | |||
51 | void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state) | ||
52 | { | ||
53 | IRDA_DEBUG(2, "%s(), %s\n", __FUNCTION__ , irlan_state[state]); | ||
54 | |||
55 | IRDA_ASSERT(self != NULL, return;); | ||
56 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
57 | |||
58 | self->provider.state = state; | ||
59 | } | ||
60 | |||
diff --git a/net/irda/irlan/irlan_filter.c b/net/irda/irlan/irlan_filter.c new file mode 100644 index 000000000000..343c5d4a1a1d --- /dev/null +++ b/net/irda/irlan/irlan_filter.c | |||
@@ -0,0 +1,246 @@ | |||
1 | /********************************************************************* | ||
2 | * | ||
3 | * Filename: irlan_filter.c | ||
4 | * Version: | ||
5 | * Description: | ||
6 | * Status: Experimental. | ||
7 | * Author: Dag Brattli <dagb@cs.uit.no> | ||
8 | * Created at: Fri Jan 29 11:16:38 1999 | ||
9 | * Modified at: Sat Oct 30 12:58:45 1999 | ||
10 | * Modified by: Dag Brattli <dagb@cs.uit.no> | ||
11 | * | ||
12 | * Copyright (c) 1998-1999 Dag Brattli, 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 <linux/skbuff.h> | ||
26 | #include <linux/random.h> | ||
27 | #include <linux/seq_file.h> | ||
28 | |||
29 | #include <net/irda/irlan_common.h> | ||
30 | |||
31 | /* | ||
32 | * Function irlan_filter_request (self, skb) | ||
33 | * | ||
34 | * Handle filter request from client peer device | ||
35 | * | ||
36 | */ | ||
37 | void irlan_filter_request(struct irlan_cb *self, struct sk_buff *skb) | ||
38 | { | ||
39 | IRDA_ASSERT(self != NULL, return;); | ||
40 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
41 | |||
42 | if ((self->provider.filter_type == IRLAN_DIRECTED) && | ||
43 | (self->provider.filter_operation == DYNAMIC)) | ||
44 | { | ||
45 | IRDA_DEBUG(0, "Giving peer a dynamic Ethernet address\n"); | ||
46 | self->provider.mac_address[0] = 0x40; | ||
47 | self->provider.mac_address[1] = 0x00; | ||
48 | self->provider.mac_address[2] = 0x00; | ||
49 | self->provider.mac_address[3] = 0x00; | ||
50 | |||
51 | /* Use arbitration value to generate MAC address */ | ||
52 | if (self->provider.access_type == ACCESS_PEER) { | ||
53 | self->provider.mac_address[4] = | ||
54 | self->provider.send_arb_val & 0xff; | ||
55 | self->provider.mac_address[5] = | ||
56 | (self->provider.send_arb_val >> 8) & 0xff; | ||
57 | } else { | ||
58 | /* Just generate something for now */ | ||
59 | get_random_bytes(self->provider.mac_address+4, 1); | ||
60 | get_random_bytes(self->provider.mac_address+5, 1); | ||
61 | } | ||
62 | |||
63 | skb->data[0] = 0x00; /* Success */ | ||
64 | skb->data[1] = 0x03; | ||
65 | irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); | ||
66 | irlan_insert_short_param(skb, "MAX_ENTRY", 0x0001); | ||
67 | irlan_insert_array_param(skb, "FILTER_ENTRY", | ||
68 | self->provider.mac_address, 6); | ||
69 | return; | ||
70 | } | ||
71 | |||
72 | if ((self->provider.filter_type == IRLAN_DIRECTED) && | ||
73 | (self->provider.filter_mode == FILTER)) | ||
74 | { | ||
75 | IRDA_DEBUG(0, "Directed filter on\n"); | ||
76 | skb->data[0] = 0x00; /* Success */ | ||
77 | skb->data[1] = 0x00; | ||
78 | return; | ||
79 | } | ||
80 | if ((self->provider.filter_type == IRLAN_DIRECTED) && | ||
81 | (self->provider.filter_mode == NONE)) | ||
82 | { | ||
83 | IRDA_DEBUG(0, "Directed filter off\n"); | ||
84 | skb->data[0] = 0x00; /* Success */ | ||
85 | skb->data[1] = 0x00; | ||
86 | return; | ||
87 | } | ||
88 | |||
89 | if ((self->provider.filter_type == IRLAN_BROADCAST) && | ||
90 | (self->provider.filter_mode == FILTER)) | ||
91 | { | ||
92 | IRDA_DEBUG(0, "Broadcast filter on\n"); | ||
93 | skb->data[0] = 0x00; /* Success */ | ||
94 | skb->data[1] = 0x00; | ||
95 | return; | ||
96 | } | ||
97 | if ((self->provider.filter_type == IRLAN_BROADCAST) && | ||
98 | (self->provider.filter_mode == NONE)) | ||
99 | { | ||
100 | IRDA_DEBUG(0, "Broadcast filter off\n"); | ||
101 | skb->data[0] = 0x00; /* Success */ | ||
102 | skb->data[1] = 0x00; | ||
103 | return; | ||
104 | } | ||
105 | if ((self->provider.filter_type == IRLAN_MULTICAST) && | ||
106 | (self->provider.filter_mode == FILTER)) | ||
107 | { | ||
108 | IRDA_DEBUG(0, "Multicast filter on\n"); | ||
109 | skb->data[0] = 0x00; /* Success */ | ||
110 | skb->data[1] = 0x00; | ||
111 | return; | ||
112 | } | ||
113 | if ((self->provider.filter_type == IRLAN_MULTICAST) && | ||
114 | (self->provider.filter_mode == NONE)) | ||
115 | { | ||
116 | IRDA_DEBUG(0, "Multicast filter off\n"); | ||
117 | skb->data[0] = 0x00; /* Success */ | ||
118 | skb->data[1] = 0x00; | ||
119 | return; | ||
120 | } | ||
121 | if ((self->provider.filter_type == IRLAN_MULTICAST) && | ||
122 | (self->provider.filter_operation == GET)) | ||
123 | { | ||
124 | IRDA_DEBUG(0, "Multicast filter get\n"); | ||
125 | skb->data[0] = 0x00; /* Success? */ | ||
126 | skb->data[1] = 0x02; | ||
127 | irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); | ||
128 | irlan_insert_short_param(skb, "MAX_ENTRY", 16); | ||
129 | return; | ||
130 | } | ||
131 | skb->data[0] = 0x00; /* Command not supported */ | ||
132 | skb->data[1] = 0x00; | ||
133 | |||
134 | IRDA_DEBUG(0, "Not implemented!\n"); | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * Function check_request_param (self, param, value) | ||
139 | * | ||
140 | * Check parameters in request from peer device | ||
141 | * | ||
142 | */ | ||
143 | void irlan_check_command_param(struct irlan_cb *self, char *param, char *value) | ||
144 | { | ||
145 | __u8 *bytes; | ||
146 | |||
147 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
148 | |||
149 | bytes = value; | ||
150 | |||
151 | IRDA_ASSERT(self != NULL, return;); | ||
152 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); | ||
153 | |||
154 | IRDA_DEBUG(4, "%s, %s\n", param, value); | ||
155 | |||
156 | /* | ||
157 | * This is experimental!! DB. | ||
158 | */ | ||
159 | if (strcmp(param, "MODE") == 0) { | ||
160 | IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); | ||
161 | self->use_udata = TRUE; | ||
162 | return; | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * FILTER_TYPE | ||
167 | */ | ||
168 | if (strcmp(param, "FILTER_TYPE") == 0) { | ||
169 | if (strcmp(value, "DIRECTED") == 0) { | ||
170 | self->provider.filter_type = IRLAN_DIRECTED; | ||
171 | return; | ||
172 | } | ||
173 | if (strcmp(value, "MULTICAST") == 0) { | ||
174 | self->provider.filter_type = IRLAN_MULTICAST; | ||
175 | return; | ||
176 | } | ||
177 | if (strcmp(value, "BROADCAST") == 0) { | ||
178 | self->provider.filter_type = IRLAN_BROADCAST; | ||
179 | return; | ||
180 | } | ||
181 | } | ||
182 | /* | ||
183 | * FILTER_MODE | ||
184 | */ | ||
185 | if (strcmp(param, "FILTER_MODE") == 0) { | ||
186 | if (strcmp(value, "ALL") == 0) { | ||
187 | self->provider.filter_mode = ALL; | ||
188 | return; | ||
189 | } | ||
190 | if (strcmp(value, "FILTER") == 0) { | ||
191 | self->provider.filter_mode = FILTER; | ||
192 | return; | ||
193 | } | ||
194 | if (strcmp(value, "NONE") == 0) { | ||
195 | self->provider.filter_mode = FILTER; | ||
196 | return; | ||
197 | } | ||
198 | } | ||
199 | /* | ||
200 | * FILTER_OPERATION | ||
201 | */ | ||
202 | if (strcmp(param, "FILTER_OPERATION") == 0) { | ||
203 | if (strcmp(value, "DYNAMIC") == 0) { | ||
204 | self->provider.filter_operation = DYNAMIC; | ||
205 | return; | ||
206 | } | ||
207 | if (strcmp(value, "GET") == 0) { | ||
208 | self->provider.filter_operation = GET; | ||
209 | return; | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * Function irlan_print_filter (filter_type, buf) | ||
216 | * | ||
217 | * Print status of filter. Used by /proc file system | ||
218 | * | ||
219 | */ | ||
220 | #ifdef CONFIG_PROC_FS | ||
221 | #define MASK2STR(m,s) { .mask = m, .str = s } | ||
222 | |||
223 | void irlan_print_filter(struct seq_file *seq, int filter_type) | ||
224 | { | ||
225 | static struct { | ||
226 | int mask; | ||
227 | const char *str; | ||
228 | } filter_mask2str[] = { | ||
229 | MASK2STR(IRLAN_DIRECTED, "DIRECTED"), | ||
230 | MASK2STR(IRLAN_FUNCTIONAL, "FUNCTIONAL"), | ||
231 | MASK2STR(IRLAN_GROUP, "GROUP"), | ||
232 | MASK2STR(IRLAN_MAC_FRAME, "MAC_FRAME"), | ||
233 | MASK2STR(IRLAN_MULTICAST, "MULTICAST"), | ||
234 | MASK2STR(IRLAN_BROADCAST, "BROADCAST"), | ||
235 | MASK2STR(IRLAN_IPX_SOCKET, "IPX_SOCKET"), | ||
236 | MASK2STR(0, NULL) | ||
237 | }, *p; | ||
238 | |||
239 | for (p = filter_mask2str; p->str; p++) { | ||
240 | if (filter_type & p->mask) | ||
241 | seq_printf(seq, "%s ", p->str); | ||
242 | } | ||
243 | seq_putc(seq, '\n'); | ||
244 | } | ||
245 | #undef MASK2STR | ||
246 | #endif | ||
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 | |||
diff --git a/net/irda/irlan/irlan_provider_event.c b/net/irda/irlan/irlan_provider_event.c new file mode 100644 index 000000000000..5a086f9827ed --- /dev/null +++ b/net/irda/irlan/irlan_provider_event.c | |||
@@ -0,0 +1,241 @@ | |||
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 | |||
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 | */ | ||
72 | static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event, | ||
73 | struct sk_buff *skb) | ||
74 | { | ||
75 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
76 | |||
77 | IRDA_ASSERT(self != NULL, return -1;); | ||
78 | |||
79 | switch(event) { | ||
80 | case IRLAN_CONNECT_INDICATION: | ||
81 | irlan_provider_connect_response( self, self->provider.tsap_ctrl); | ||
82 | irlan_next_provider_state( self, IRLAN_INFO); | ||
83 | break; | ||
84 | default: | ||
85 | IRDA_DEBUG(4, "%s(), Unknown event %d\n", __FUNCTION__ , event); | ||
86 | break; | ||
87 | } | ||
88 | if (skb) | ||
89 | dev_kfree_skb(skb); | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * Function irlan_provider_state_info (self, event, skb, info) | ||
96 | * | ||
97 | * INFO, We have issued a GetInfo command and is awaiting a reply. | ||
98 | */ | ||
99 | static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event, | ||
100 | struct sk_buff *skb) | ||
101 | { | ||
102 | int ret; | ||
103 | |||
104 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
105 | |||
106 | IRDA_ASSERT(self != NULL, return -1;); | ||
107 | |||
108 | switch(event) { | ||
109 | case IRLAN_GET_INFO_CMD: | ||
110 | /* Be sure to use 802.3 in case of peer mode */ | ||
111 | if (self->provider.access_type == ACCESS_PEER) { | ||
112 | self->media = MEDIA_802_3; | ||
113 | |||
114 | /* Check if client has started yet */ | ||
115 | if (self->client.state == IRLAN_IDLE) { | ||
116 | /* This should get the client going */ | ||
117 | irlmp_discovery_request(8); | ||
118 | } | ||
119 | } | ||
120 | |||
121 | irlan_provider_send_reply(self, CMD_GET_PROVIDER_INFO, | ||
122 | RSP_SUCCESS); | ||
123 | /* Keep state */ | ||
124 | break; | ||
125 | case IRLAN_GET_MEDIA_CMD: | ||
126 | irlan_provider_send_reply(self, CMD_GET_MEDIA_CHAR, | ||
127 | RSP_SUCCESS); | ||
128 | /* Keep state */ | ||
129 | break; | ||
130 | case IRLAN_OPEN_DATA_CMD: | ||
131 | ret = irlan_parse_open_data_cmd(self, skb); | ||
132 | if (self->provider.access_type == ACCESS_PEER) { | ||
133 | /* FIXME: make use of random functions! */ | ||
134 | self->provider.send_arb_val = (jiffies & 0xffff); | ||
135 | } | ||
136 | irlan_provider_send_reply(self, CMD_OPEN_DATA_CHANNEL, ret); | ||
137 | |||
138 | if (ret == RSP_SUCCESS) { | ||
139 | irlan_next_provider_state(self, IRLAN_OPEN); | ||
140 | |||
141 | /* Signal client that we are now open */ | ||
142 | irlan_do_client_event(self, IRLAN_PROVIDER_SIGNAL, NULL); | ||
143 | } | ||
144 | break; | ||
145 | case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */ | ||
146 | case IRLAN_LAP_DISCONNECT: | ||
147 | irlan_next_provider_state(self, IRLAN_IDLE); | ||
148 | break; | ||
149 | default: | ||
150 | IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __FUNCTION__ , event); | ||
151 | break; | ||
152 | } | ||
153 | if (skb) | ||
154 | dev_kfree_skb(skb); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * Function irlan_provider_state_open (self, event, skb, info) | ||
161 | * | ||
162 | * OPEN, The client has issued a OpenData command and is awaiting a | ||
163 | * reply | ||
164 | * | ||
165 | */ | ||
166 | static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event, | ||
167 | struct sk_buff *skb) | ||
168 | { | ||
169 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
170 | |||
171 | IRDA_ASSERT(self != NULL, return -1;); | ||
172 | |||
173 | switch(event) { | ||
174 | case IRLAN_FILTER_CONFIG_CMD: | ||
175 | irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb); | ||
176 | irlan_provider_send_reply(self, CMD_FILTER_OPERATION, | ||
177 | RSP_SUCCESS); | ||
178 | /* Keep state */ | ||
179 | break; | ||
180 | case IRLAN_DATA_CONNECT_INDICATION: | ||
181 | irlan_next_provider_state(self, IRLAN_DATA); | ||
182 | irlan_provider_connect_response(self, self->tsap_data); | ||
183 | break; | ||
184 | case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */ | ||
185 | case IRLAN_LAP_DISCONNECT: | ||
186 | irlan_next_provider_state(self, IRLAN_IDLE); | ||
187 | break; | ||
188 | default: | ||
189 | IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); | ||
190 | break; | ||
191 | } | ||
192 | if (skb) | ||
193 | dev_kfree_skb(skb); | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * Function irlan_provider_state_data (self, event, skb, info) | ||
200 | * | ||
201 | * DATA, The data channel is connected, allowing data transfers between | ||
202 | * the local and remote machines. | ||
203 | * | ||
204 | */ | ||
205 | static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event, | ||
206 | struct sk_buff *skb) | ||
207 | { | ||
208 | IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); | ||
209 | |||
210 | IRDA_ASSERT(self != NULL, return -1;); | ||
211 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); | ||
212 | |||
213 | switch(event) { | ||
214 | case IRLAN_FILTER_CONFIG_CMD: | ||
215 | irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb); | ||
216 | irlan_provider_send_reply(self, CMD_FILTER_OPERATION, | ||
217 | RSP_SUCCESS); | ||
218 | break; | ||
219 | case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */ | ||
220 | case IRLAN_LAP_DISCONNECT: | ||
221 | irlan_next_provider_state(self, IRLAN_IDLE); | ||
222 | break; | ||
223 | default: | ||
224 | IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __FUNCTION__ , event); | ||
225 | break; | ||
226 | } | ||
227 | if (skb) | ||
228 | dev_kfree_skb(skb); | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | |||
234 | |||
235 | |||
236 | |||
237 | |||
238 | |||
239 | |||
240 | |||
241 | |||