File: /usr/src/linux/net/irda/irlan/irlan_client.c
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 <net/arp.h>
37
38 #include <asm/system.h>
39 #include <asm/bitops.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
70 static void irlan_client_kick_timer_expired(void *data)
71 {
72 struct irlan_cb *self = (struct irlan_cb *) data;
73
74 IRDA_DEBUG(2, __FUNCTION__ "()\n");
75
76 ASSERT(self != NULL, return;);
77 ASSERT(self->magic == IRLAN_MAGIC, return;);
78
79 /*
80 * If we are in peer mode, the client may not have got the discovery
81 * indication it needs to make progress. If the client is still in
82 * IDLE state, we must kick it to, but only if the provider is not IDLE
83 */
84 if ((self->provider.access_type == ACCESS_PEER) &&
85 (self->client.state == IRLAN_IDLE) &&
86 (self->provider.state != IRLAN_IDLE)) {
87 irlan_client_wakeup(self, self->saddr, self->daddr);
88 }
89 }
90
91 void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout)
92 {
93 IRDA_DEBUG(4, __FUNCTION__ "()\n");
94
95 irda_start_timer(&self->client.kick_timer, timeout, (void *) self,
96 irlan_client_kick_timer_expired);
97 }
98
99 /*
100 * Function irlan_client_wakeup (self, saddr, daddr)
101 *
102 * Wake up client
103 *
104 */
105 void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
106 {
107 IRDA_DEBUG(1, __FUNCTION__ "()\n");
108
109 ASSERT(self != NULL, return;);
110 ASSERT(self->magic == IRLAN_MAGIC, return;);
111
112 /*
113 * Check if we are already awake, or if we are a provider in direct
114 * mode (in that case we must leave the client idle
115 */
116 if ((self->client.state != IRLAN_IDLE) ||
117 (self->provider.access_type == ACCESS_DIRECT))
118 {
119 IRDA_DEBUG(0, __FUNCTION__ "(), already awake!\n");
120 return;
121 }
122
123 /* Addresses may have changed! */
124 self->saddr = saddr;
125 self->daddr = daddr;
126
127 if (self->disconnect_reason == LM_USER_REQUEST) {
128 IRDA_DEBUG(0, __FUNCTION__ "(), still stopped by user\n");
129 return;
130 }
131
132 /* Open TSAPs */
133 irlan_client_open_ctrl_tsap(self);
134 irlan_open_data_tsap(self);
135
136 irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL);
137
138 /* Start kick timer */
139 irlan_client_start_kick_timer(self, 2*HZ);
140 }
141
142 /*
143 * Function irlan_discovery_indication (daddr)
144 *
145 * Remote device with IrLAN server support discovered
146 *
147 */
148 void irlan_client_discovery_indication(discovery_t *discovery, void *priv)
149 {
150 struct irlan_cb *self;
151 __u32 saddr, daddr;
152
153 IRDA_DEBUG(1, __FUNCTION__"()\n");
154
155 ASSERT(irlan != NULL, return;);
156 ASSERT(discovery != NULL, return;);
157
158 saddr = discovery->saddr;
159 daddr = discovery->daddr;
160
161 /* Find instance */
162 self = (struct irlan_cb *) hashbin_get_first(irlan);
163 if (self) {
164 ASSERT(self->magic == IRLAN_MAGIC, return;);
165
166 IRDA_DEBUG(1, __FUNCTION__ "(), Found instance (%08x)!\n",
167 daddr);
168
169 irlan_client_wakeup(self, saddr, daddr);
170 }
171 }
172
173 /*
174 * Function irlan_client_data_indication (handle, skb)
175 *
176 * This function gets the data that is received on the control channel
177 *
178 */
179 static int irlan_client_ctrl_data_indication(void *instance, void *sap,
180 struct sk_buff *skb)
181 {
182 struct irlan_cb *self;
183
184 IRDA_DEBUG(2, __FUNCTION__ "()\n");
185
186 self = (struct irlan_cb *) instance;
187
188 ASSERT(self != NULL, return -1;);
189 ASSERT(self->magic == IRLAN_MAGIC, return -1;);
190 ASSERT(skb != NULL, return -1;);
191
192 irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb);
193
194 /* Ready for a new command */
195 IRDA_DEBUG(2, __FUNCTION__ "(), clearing tx_busy\n");
196 self->client.tx_busy = FALSE;
197
198 /* Check if we have some queued commands waiting to be sent */
199 irlan_run_ctrl_tx_queue(self);
200
201 return 0;
202 }
203
204 static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap,
205 LM_REASON reason,
206 struct sk_buff *userdata)
207 {
208 struct irlan_cb *self;
209 struct tsap_cb *tsap;
210 struct sk_buff *skb;
211
212 IRDA_DEBUG(4, __FUNCTION__ "(), reason=%d\n", reason);
213
214 self = (struct irlan_cb *) instance;
215 tsap = (struct tsap_cb *) sap;
216
217 ASSERT(self != NULL, return;);
218 ASSERT(self->magic == IRLAN_MAGIC, return;);
219 ASSERT(tsap != NULL, return;);
220 ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
221
222 ASSERT(tsap == self->client.tsap_ctrl, return;);
223
224 /* Remove frames queued on the control channel */
225 while ((skb = skb_dequeue(&self->client.txq))) {
226 dev_kfree_skb(skb);
227 }
228 self->client.tx_busy = FALSE;
229
230 irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
231 }
232
233 /*
234 * Function irlan_client_open_tsaps (self)
235 *
236 * Initialize callbacks and open IrTTP TSAPs
237 *
238 */
239 void irlan_client_open_ctrl_tsap(struct irlan_cb *self)
240 {
241 struct tsap_cb *tsap;
242 notify_t notify;
243
244 IRDA_DEBUG(4, __FUNCTION__ "()\n");
245
246 ASSERT(self != NULL, return;);
247 ASSERT(self->magic == IRLAN_MAGIC, return;);
248
249 /* Check if already open */
250 if (self->client.tsap_ctrl)
251 return;
252
253 irda_notify_init(¬ify);
254
255 /* Set up callbacks */
256 notify.data_indication = irlan_client_ctrl_data_indication;
257 notify.connect_confirm = irlan_client_ctrl_connect_confirm;
258 notify.disconnect_indication = irlan_client_ctrl_disconnect_indication;
259 notify.instance = self;
260 strncpy(notify.name, "IrLAN ctrl (c)", NOTIFY_MAX_NAME);
261
262 tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, ¬ify);
263 if (!tsap) {
264 IRDA_DEBUG(2, __FUNCTION__ "(), Got no tsap!\n");
265 return;
266 }
267 self->client.tsap_ctrl = tsap;
268 }
269
270 /*
271 * Function irlan_client_connect_confirm (handle, skb)
272 *
273 * Connection to peer IrLAN laye confirmed
274 *
275 */
276 static void irlan_client_ctrl_connect_confirm(void *instance, void *sap,
277 struct qos_info *qos,
278 __u32 max_sdu_size,
279 __u8 max_header_size,
280 struct sk_buff *skb)
281 {
282 struct irlan_cb *self;
283
284 IRDA_DEBUG(4, __FUNCTION__ "()\n");
285
286 self = (struct irlan_cb *) instance;
287
288 ASSERT(self != NULL, return;);
289 ASSERT(self->magic == IRLAN_MAGIC, return;);
290
291 self->client.max_sdu_size = max_sdu_size;
292 self->client.max_header_size = max_header_size;
293
294 /* TODO: we could set the MTU depending on the max_sdu_size */
295
296 irlan_do_client_event(self, IRLAN_CONNECT_COMPLETE, NULL);
297 }
298
299 /*
300 * Function irlan_client_reconnect_data_channel (self)
301 *
302 * Try to reconnect data channel (currently not used)
303 *
304 */
305 void irlan_client_reconnect_data_channel(struct irlan_cb *self)
306 {
307 struct sk_buff *skb;
308 __u8 *frame;
309
310 IRDA_DEBUG(4, __FUNCTION__ "()\n");
311
312 ASSERT(self != NULL, return;);
313 ASSERT(self->magic == IRLAN_MAGIC, return;);
314
315 skb = dev_alloc_skb(128);
316 if (!skb)
317 return;
318
319 /* Reserve space for TTP, LMP, and LAP header */
320 skb_reserve(skb, self->max_header_size);
321 skb_put(skb, 2);
322
323 frame = skb->data;
324
325 frame[0] = CMD_RECONNECT_DATA_CHAN;
326 frame[1] = 0x01;
327 irlan_insert_array_param(skb, "RECONNECT_KEY",
328 self->client.reconnect_key,
329 self->client.key_len);
330
331 irttp_data_request(self->client.tsap_ctrl, skb);
332 }
333
334 /*
335 * Function irlan_client_parse_response (self, skb)
336 *
337 * Extract all parameters from received buffer, then feed them to
338 * check_params for parsing
339 */
340 void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb)
341 {
342 __u8 *frame;
343 __u8 *ptr;
344 int count;
345 int ret;
346 __u16 val_len;
347 int i;
348 char *name;
349 char *value;
350
351 ASSERT(skb != NULL, return;);
352
353 IRDA_DEBUG(4, __FUNCTION__ "() skb->len=%d\n", (int) skb->len);
354
355 ASSERT(self != NULL, return;);
356 ASSERT(self->magic == IRLAN_MAGIC, return;);
357
358 if (!skb) {
359 ERROR( __FUNCTION__ "(), Got NULL skb!\n");
360 return;
361 }
362 frame = skb->data;
363
364 /*
365 * Check return code and print it if not success
366 */
367 if (frame[0]) {
368 print_ret_code(frame[0]);
369 return;
370 }
371
372 name = kmalloc(255, GFP_ATOMIC);
373 if (!name)
374 return;
375 value = kmalloc(1016, GFP_ATOMIC);
376 if (!value) {
377 kfree(name);
378 return;
379 }
380
381 /* How many parameters? */
382 count = frame[1];
383
384 IRDA_DEBUG(4, __FUNCTION__ "(), got %d parameters\n", count);
385
386 ptr = frame+2;
387
388 /* For all parameters */
389 for (i=0; i<count;i++) {
390 ret = irlan_extract_param(ptr, name, value, &val_len);
391 if (ret < 0) {
392 IRDA_DEBUG(2, __FUNCTION__ "(), IrLAN, Error!\n");
393 break;
394 }
395 ptr += ret;
396 irlan_check_response_param(self, name, value, val_len);
397 }
398 /* Cleanup */
399 kfree(name);
400 kfree(value);
401 }
402
403 /*
404 * Function irlan_check_response_param (self, param, value, val_len)
405 *
406 * Check which parameter is received and update local variables
407 *
408 */
409 static void irlan_check_response_param(struct irlan_cb *self, char *param,
410 char *value, int val_len)
411 {
412 __u16 tmp_cpu; /* Temporary value in host order */
413 __u8 *bytes;
414 int i;
415
416 IRDA_DEBUG(4, __FUNCTION__ "(), parm=%s\n", param);
417
418 ASSERT(self != NULL, return;);
419 ASSERT(self->magic == IRLAN_MAGIC, return;);
420
421 /* Media type */
422 if (strcmp(param, "MEDIA") == 0) {
423 if (strcmp(value, "802.3") == 0)
424 self->media = MEDIA_802_3;
425 else
426 self->media = MEDIA_802_5;
427 return;
428 }
429 if (strcmp(param, "FILTER_TYPE") == 0) {
430 if (strcmp(value, "DIRECTED") == 0)
431 self->client.filter_type |= IRLAN_DIRECTED;
432 else if (strcmp(value, "FUNCTIONAL") == 0)
433 self->client.filter_type |= IRLAN_FUNCTIONAL;
434 else if (strcmp(value, "GROUP") == 0)
435 self->client.filter_type |= IRLAN_GROUP;
436 else if (strcmp(value, "MAC_FRAME") == 0)
437 self->client.filter_type |= IRLAN_MAC_FRAME;
438 else if (strcmp(value, "MULTICAST") == 0)
439 self->client.filter_type |= IRLAN_MULTICAST;
440 else if (strcmp(value, "BROADCAST") == 0)
441 self->client.filter_type |= IRLAN_BROADCAST;
442 else if (strcmp(value, "IPX_SOCKET") == 0)
443 self->client.filter_type |= IRLAN_IPX_SOCKET;
444
445 }
446 if (strcmp(param, "ACCESS_TYPE") == 0) {
447 if (strcmp(value, "DIRECT") == 0)
448 self->client.access_type = ACCESS_DIRECT;
449 else if (strcmp(value, "PEER") == 0)
450 self->client.access_type = ACCESS_PEER;
451 else if (strcmp(value, "HOSTED") == 0)
452 self->client.access_type = ACCESS_HOSTED;
453 else {
454 IRDA_DEBUG(2, __FUNCTION__ "(), unknown access type!\n");
455 }
456 }
457 /* IRLAN version */
458 if (strcmp(param, "IRLAN_VER") == 0) {
459 IRDA_DEBUG(4, "IrLAN version %d.%d\n", (__u8) value[0],
460 (__u8) value[1]);
461
462 self->version[0] = value[0];
463 self->version[1] = value[1];
464 return;
465 }
466 /* Which remote TSAP to use for data channel */
467 if (strcmp(param, "DATA_CHAN") == 0) {
468 self->dtsap_sel_data = value[0];
469 IRDA_DEBUG(4, "Data TSAP = %02x\n", self->dtsap_sel_data);
470 return;
471 }
472 if (strcmp(param, "CON_ARB") == 0) {
473 memcpy(&tmp_cpu, value, 2); /* Align value */
474 le16_to_cpus(&tmp_cpu); /* Convert to host order */
475 self->client.recv_arb_val = tmp_cpu;
476 IRDA_DEBUG(2, __FUNCTION__ "(), receive arb val=%d\n",
477 self->client.recv_arb_val);
478 }
479 if (strcmp(param, "MAX_FRAME") == 0) {
480 memcpy(&tmp_cpu, value, 2); /* Align value */
481 le16_to_cpus(&tmp_cpu); /* Convert to host order */
482 self->client.max_frame = tmp_cpu;
483 IRDA_DEBUG(4, __FUNCTION__ "(), max frame=%d\n",
484 self->client.max_frame);
485 }
486
487 /* RECONNECT_KEY, in case the link goes down! */
488 if (strcmp(param, "RECONNECT_KEY") == 0) {
489 IRDA_DEBUG(4, "Got reconnect key: ");
490 /* for (i = 0; i < val_len; i++) */
491 /* printk("%02x", value[i]); */
492 memcpy(self->client.reconnect_key, value, val_len);
493 self->client.key_len = val_len;
494 IRDA_DEBUG(4, "\n");
495 }
496 /* FILTER_ENTRY, have we got an ethernet address? */
497 if (strcmp(param, "FILTER_ENTRY") == 0) {
498 bytes = value;
499 IRDA_DEBUG(4, "Ethernet address = %02x:%02x:%02x:%02x:%02x:%02x\n",
500 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
501 bytes[5]);
502 for (i = 0; i < 6; i++)
503 self->dev.dev_addr[i] = bytes[i];
504 }
505 }
506
507 /*
508 * Function irlan_client_get_value_confirm (obj_id, value)
509 *
510 * Got results from remote LM-IAS
511 *
512 */
513 void irlan_client_get_value_confirm(int result, __u16 obj_id,
514 struct ias_value *value, void *priv)
515 {
516 struct irlan_cb *self;
517
518 IRDA_DEBUG(4, __FUNCTION__ "()\n");
519
520 ASSERT(priv != NULL, return;);
521
522 self = (struct irlan_cb *) priv;
523 ASSERT(self->magic == IRLAN_MAGIC, return;);
524
525 /* We probably don't need to make any more queries */
526 iriap_close(self->client.iriap);
527 self->client.iriap = NULL;
528
529 /* Check if request succeeded */
530 if (result != IAS_SUCCESS) {
531 IRDA_DEBUG(2, __FUNCTION__ "(), got NULL value!\n");
532 irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL,
533 NULL);
534 return;
535 }
536
537 switch (value->type) {
538 case IAS_INTEGER:
539 self->dtsap_sel_ctrl = value->t.integer;
540
541 if (value->t.integer != -1) {
542 irlan_do_client_event(self, IRLAN_IAS_PROVIDER_AVAIL,
543 NULL);
544 return;
545 }
546 irias_delete_value(value);
547 break;
548 default:
549 IRDA_DEBUG(2, __FUNCTION__ "(), unknown type!\n");
550 break;
551 }
552 irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL);
553 }
554