Import 2.3.4pre3
[davej-history.git] / net / irda / irlan / irlan_client.c
blob66b94eec8092e251ff0e68e52cb15bb77fd47624
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 May 11 00:22:39 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>
15 * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
16 * All Rights Reserved.
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.
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.
27 ********************************************************************/
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>
38 #include <asm/system.h>
39 #include <asm/bitops.h>
40 #include <asm/byteorder.h>
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>
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>
55 #undef CONFIG_IRLAN_GRATUITOUS_ARP
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);
70 static void irlan_client_kick_timer_expired(unsigned long data)
72 struct irlan_cb *self = (struct irlan_cb *) data;
74 DEBUG(2, __FUNCTION__ "()\n");
76 ASSERT(self != NULL, return;);
77 ASSERT(self->magic == IRLAN_MAGIC, return;);
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
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);
91 void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout)
93 DEBUG(4, __FUNCTION__ "()\n");
95 irda_start_timer(&self->client.kick_timer, timeout,
96 (unsigned long) self,
97 irlan_client_kick_timer_expired);
101 * Function irlan_client_wakeup (self, saddr, daddr)
103 * Wake up client
106 void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
108 struct irmanager_event mgr_event;
110 DEBUG(1, __FUNCTION__ "()\n");
112 ASSERT(self != NULL, return;);
113 ASSERT(self->magic == IRLAN_MAGIC, return;);
116 * Check if we are already awake, or if we are a provider in direct
117 * mode (in that case we must leave the client idle
119 if ((self->client.state != IRLAN_IDLE) ||
120 (self->provider.access_type == ACCESS_DIRECT))
121 return;
123 /* saddr may have changed! */
124 self->saddr = saddr;
126 /* Before we try to connect, we check if network device is up. If it
127 * is up, that means that the "user" really wants to connect. If not
128 * we notify the user about the possibility of an IrLAN connection
130 if (self->dev.start) {
131 /* Open TSAPs */
132 irlan_client_open_ctrl_tsap(self);
133 irlan_open_data_tsap(self);
135 irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL);
136 } else if (self->notify_irmanager) {
138 * Tell irmanager that the device can now be
139 * configured but only if the device was not taken
140 * down by the user
142 mgr_event.event = EVENT_IRLAN_START;
143 sprintf(mgr_event.devname, "%s", self->ifname);
144 irmanager_notify(&mgr_event);
147 * We set this so that we only notify once, since if
148 * configuration of the network device fails, the user
149 * will have to sort it out first anyway. No need to
150 * try again.
152 self->notify_irmanager = FALSE;
154 /* Restart watchdog timer */
155 irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
157 /* Start kick timer */
158 irlan_client_start_kick_timer(self, 2*HZ);
162 * Function irlan_discovery_indication (daddr)
164 * Remote device with IrLAN server support discovered
167 void irlan_client_discovery_indication(discovery_t *discovery)
169 struct irlan_cb *self, *entry;
170 __u32 saddr, daddr;
172 DEBUG(1, __FUNCTION__"()\n");
174 ASSERT(irlan != NULL, return;);
175 ASSERT(discovery != NULL, return;);
177 saddr = discovery->saddr;
178 daddr = discovery->daddr;
181 * Check if we already dealing with this provider.
183 self = (struct irlan_cb *) hashbin_find(irlan, daddr, NULL);
184 if (self) {
185 ASSERT(self->magic == IRLAN_MAGIC, return;);
187 DEBUG(1, __FUNCTION__ "(), Found instance (%08x)!\n",
188 daddr);
190 irlan_client_wakeup(self, saddr, daddr);
192 return;
196 * We have no instance for daddr, so start a new one
198 DEBUG(1, __FUNCTION__ "(), starting new instance!\n");
199 self = irlan_open(saddr, daddr, TRUE);
201 /* Restart watchdog timer */
202 irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
206 * Function irlan_client_data_indication (handle, skb)
208 * This function gets the data that is received on the control channel
211 static int irlan_client_ctrl_data_indication(void *instance, void *sap,
212 struct sk_buff *skb)
214 struct irlan_cb *self;
216 DEBUG(4, __FUNCTION__ "()\n");
218 self = (struct irlan_cb *) instance;
220 ASSERT(self != NULL, return -1;);
221 ASSERT(self->magic == IRLAN_MAGIC, return -1;);
222 ASSERT(skb != NULL, return -1;);
224 irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb);
226 return 0;
229 static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap,
230 LM_REASON reason,
231 struct sk_buff *userdata)
233 struct irlan_cb *self;
234 struct tsap_cb *tsap;
236 DEBUG(4, __FUNCTION__ "(), reason=%d\n", reason);
238 self = (struct irlan_cb *) instance;
239 tsap = (struct tsap_cb *) sap;
241 ASSERT(self != NULL, return;);
242 ASSERT(self->magic == IRLAN_MAGIC, return;);
243 ASSERT(tsap != NULL, return;);
244 ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
246 ASSERT(tsap == self->client.tsap_ctrl, return;);
248 irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
252 * Function irlan_client_open_tsaps (self)
254 * Initialize callbacks and open IrTTP TSAPs
257 void irlan_client_open_ctrl_tsap(struct irlan_cb *self)
259 struct notify_t notify;
260 struct tsap_cb *tsap;
262 DEBUG(4, __FUNCTION__ "()\n");
264 ASSERT(self != NULL, return;);
265 ASSERT(self->magic == IRLAN_MAGIC, return;);
267 /* Check if already open */
268 if (self->client.tsap_ctrl)
269 return;
271 irda_notify_init(&notify);
273 /* Set up callbacks */
274 notify.data_indication = irlan_client_ctrl_data_indication;
275 notify.connect_confirm = irlan_client_ctrl_connect_confirm;
276 notify.disconnect_indication = irlan_client_ctrl_disconnect_indication;
277 notify.instance = self;
278 strncpy(notify.name, "IrLAN ctrl (c)", NOTIFY_MAX_NAME);
280 tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, &notify);
281 if (!tsap) {
282 DEBUG(2, __FUNCTION__ "(), Got no tsap!\n");
283 return;
285 self->client.tsap_ctrl = tsap;
289 * Function irlan_client_connect_confirm (handle, skb)
291 * Connection to peer IrLAN laye confirmed
294 static void irlan_client_ctrl_connect_confirm(void *instance, void *sap,
295 struct qos_info *qos,
296 __u32 max_sdu_size,
297 __u8 max_header_size,
298 struct sk_buff *skb)
300 struct irlan_cb *self;
302 DEBUG(4, __FUNCTION__ "()\n");
304 self = (struct irlan_cb *) instance;
306 ASSERT(self != NULL, return;);
307 ASSERT(self->magic == IRLAN_MAGIC, return;);
309 self->client.max_sdu_size = max_sdu_size;
310 self->client.max_header_size = max_header_size;
312 /* TODO: we could set the MTU depending on the max_sdu_size */
314 irlan_do_client_event(self, IRLAN_CONNECT_COMPLETE, NULL);
318 * Function irlan_client_reconnect_data_channel (self)
320 * Try to reconnect data channel (currently not used)
323 void irlan_client_reconnect_data_channel(struct irlan_cb *self)
325 struct sk_buff *skb;
326 __u8 *frame;
328 DEBUG(4, __FUNCTION__ "()\n");
330 ASSERT(self != NULL, return;);
331 ASSERT(self->magic == IRLAN_MAGIC, return;);
333 skb = dev_alloc_skb(128);
334 if (!skb)
335 return;
337 /* Reserve space for TTP, LMP, and LAP header */
338 skb_reserve(skb, self->max_header_size);
339 skb_put(skb, 2);
341 frame = skb->data;
343 frame[0] = CMD_RECONNECT_DATA_CHAN;
344 frame[1] = 0x01;
345 irlan_insert_array_param(skb, "RECONNECT_KEY",
346 self->client.reconnect_key,
347 self->client.key_len);
349 irttp_data_request(self->client.tsap_ctrl, skb);
353 * Function irlan_client_parse_response (self, skb)
355 * Extract all parameters from received buffer, then feed them to
356 * check_params for parsing
358 void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb)
360 __u8 *frame;
361 __u8 *ptr;
362 int count;
363 int ret;
364 __u16 val_len;
365 int i;
366 char *name;
367 char *value;
369 ASSERT(skb != NULL, return;);
371 DEBUG(4, __FUNCTION__ "() skb->len=%d\n", (int) skb->len);
373 ASSERT(self != NULL, return;);
374 ASSERT(self->magic == IRLAN_MAGIC, return;);
376 if (!skb) {
377 ERROR( __FUNCTION__ "(), Got NULL skb!\n");
378 return;
380 frame = skb->data;
383 * Check return code and print it if not success
385 if (frame[0]) {
386 print_ret_code(frame[0]);
387 return;
390 name = kmalloc(255, GFP_ATOMIC);
391 if (!name)
392 return;
393 value = kmalloc(1016, GFP_ATOMIC);
394 if (!value) {
395 kfree(name);
396 return;
399 /* How many parameters? */
400 count = frame[1];
402 DEBUG(4, __FUNCTION__ "(), got %d parameters\n", count);
404 ptr = frame+2;
406 /* For all parameters */
407 for (i=0; i<count;i++) {
408 ret = irlan_extract_param(ptr, name, value, &val_len);
409 if (ret < 0) {
410 DEBUG(2, __FUNCTION__ "(), IrLAN, Error!\n");
411 break;
413 ptr += ret;
414 irlan_check_response_param(self, name, value, val_len);
416 /* Cleanup */
417 kfree(name);
418 kfree(value);
422 * Function irlan_check_response_param (self, param, value, val_len)
424 * Check which parameter is received and update local variables
427 static void irlan_check_response_param(struct irlan_cb *self, char *param,
428 char *value, int val_len)
430 __u16 tmp_cpu; /* Temporary value in host order */
431 __u8 *bytes;
432 int i;
434 DEBUG(4, __FUNCTION__ "(), parm=%s\n", param);
436 ASSERT(self != NULL, return;);
437 ASSERT(self->magic == IRLAN_MAGIC, return;);
440 * Media type
442 if (strcmp(param, "MEDIA") == 0) {
443 if (strcmp(value, "802.3") == 0)
444 self->media = MEDIA_802_3;
445 else
446 self->media = MEDIA_802_5;
447 return;
449 if (strcmp(param, "FILTER_TYPE") == 0) {
450 if (strcmp(value, "DIRECTED") == 0)
451 self->client.filter_type |= IRLAN_DIRECTED;
452 else if (strcmp(value, "FUNCTIONAL") == 0)
453 self->client.filter_type |= IRLAN_FUNCTIONAL;
454 else if (strcmp(value, "GROUP") == 0)
455 self->client.filter_type |= IRLAN_GROUP;
456 else if (strcmp(value, "MAC_FRAME") == 0)
457 self->client.filter_type |= IRLAN_MAC_FRAME;
458 else if (strcmp(value, "MULTICAST") == 0)
459 self->client.filter_type |= IRLAN_MULTICAST;
460 else if (strcmp(value, "BROADCAST") == 0)
461 self->client.filter_type |= IRLAN_BROADCAST;
462 else if (strcmp(value, "IPX_SOCKET") == 0)
463 self->client.filter_type |= IRLAN_IPX_SOCKET;
466 if (strcmp(param, "ACCESS_TYPE") == 0) {
467 if (strcmp(value, "DIRECT") == 0)
468 self->client.access_type = ACCESS_DIRECT;
469 else if (strcmp(value, "PEER") == 0)
470 self->client.access_type = ACCESS_PEER;
471 else if (strcmp(value, "HOSTED") == 0)
472 self->client.access_type = ACCESS_HOSTED;
473 else {
474 DEBUG(2, __FUNCTION__ "(), unknown access type!\n");
478 * IRLAN version
480 if (strcmp(param, "IRLAN_VER") == 0) {
481 DEBUG(4, "IrLAN version %d.%d\n", (__u8) value[0],
482 (__u8) value[1]);
484 self->version[0] = value[0];
485 self->version[1] = value[1];
486 return;
489 * Which remote TSAP to use for data channel
491 if (strcmp(param, "DATA_CHAN") == 0) {
492 self->dtsap_sel_data = value[0];
493 DEBUG(4, "Data TSAP = %02x\n", self->dtsap_sel_data);
494 return;
496 if (strcmp(param, "CON_ARB") == 0) {
497 memcpy(&tmp_cpu, value, 2); /* Align value */
498 le16_to_cpus(&tmp_cpu); /* Convert to host order */
499 self->client.recv_arb_val = tmp_cpu;
500 DEBUG(2, __FUNCTION__ "(), receive arb val=%d\n",
501 self->client.recv_arb_val);
503 if (strcmp(param, "MAX_FRAME") == 0) {
504 memcpy(&tmp_cpu, value, 2); /* Align value */
505 le16_to_cpus(&tmp_cpu); /* Convert to host order */
506 self->client.max_frame = tmp_cpu;
507 DEBUG(4, __FUNCTION__ "(), max frame=%d\n",
508 self->client.max_frame);
512 * RECONNECT_KEY, in case the link goes down!
514 if (strcmp(param, "RECONNECT_KEY") == 0) {
515 DEBUG(4, "Got reconnect key: ");
516 /* for (i = 0; i < val_len; i++) */
517 /* printk("%02x", value[i]); */
518 memcpy(self->client.reconnect_key, value, val_len);
519 self->client.key_len = val_len;
520 DEBUG(4, "\n");
523 * FILTER_ENTRY, have we got an ethernet address?
525 if (strcmp(param, "FILTER_ENTRY") == 0) {
526 bytes = value;
527 DEBUG(4, "Ethernet address = %02x:%02x:%02x:%02x:%02x:%02x\n",
528 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
529 bytes[5]);
530 for (i = 0; i < 6; i++)
531 self->dev.dev_addr[i] = bytes[i];
536 * Function irlan_client_get_value_confirm (obj_id, value)
538 * Got results from remote LM-IAS
541 void irlan_client_get_value_confirm(int result, __u16 obj_id,
542 struct ias_value *value, void *priv)
544 struct irlan_cb *self;
546 DEBUG(4, __FUNCTION__ "()\n");
548 ASSERT(priv != NULL, return;);
550 self = (struct irlan_cb *) priv;
551 ASSERT(self->magic == IRLAN_MAGIC, return;);
553 /* Check if request succeeded */
554 if (result != IAS_SUCCESS) {
555 DEBUG(2, __FUNCTION__ "(), got NULL value!\n");
556 irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL,
557 NULL);
558 return;
561 switch (value->type) {
562 case IAS_INTEGER:
563 self->dtsap_sel_ctrl = value->t.integer;
565 if (value->t.integer != -1) {
566 irlan_do_client_event(self, IRLAN_IAS_PROVIDER_AVAIL,
567 NULL);
568 return;
570 break;
571 case IAS_STRING:
572 DEBUG(2, __FUNCTION__ "(), got string %s\n", value->t.string);
573 break;
574 case IAS_OCT_SEQ:
575 DEBUG(2, __FUNCTION__ "(), OCT_SEQ not implemented\n");
576 break;
577 case IAS_MISSING:
578 DEBUG(2, __FUNCTION__ "(), MISSING not implemented\n");
579 break;
580 default:
581 DEBUG(2, __FUNCTION__ "(), unknown type!\n");
582 break;
584 irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL);