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