Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / 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 <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(&notify);
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, &notify);
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 }