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