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