2.2.0-final
[davej-history.git] / net / irda / irlan / irlan_common.c
blob90be583f5b9dc9bad12f7ad0af594002da9cf4be
1 /*********************************************************************
2 *
3 * Filename: irlan_common.c
4 * Version: 0.1
5 * Description: IrDA LAN Access Protocol Implementation
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 Jan 19 23:11:30 1999
10 * Modified by: Dag Brattli <dagb@cs.uit.no>
12 * Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation; either version 2 of
17 * the License, or (at your option) any later version.
19 * Neither Dag Brattli nor University of Tromsø admit liability nor
20 * provide warranty for any of this software. This material is
21 * provided "AS-IS" and at no charge.
23 ********************************************************************/
25 #include <linux/config.h>
26 #include <linux/module.h>
28 #include <linux/kernel.h>
29 #include <linux/string.h>
30 #include <linux/init.h>
31 #include <linux/errno.h>
32 #include <linux/proc_fs.h>
33 #include <linux/netdevice.h>
34 #include <linux/etherdevice.h>
36 #include <asm/system.h>
37 #include <asm/bitops.h>
38 #include <asm/byteorder.h>
40 #include <net/irda/irda.h>
41 #include <net/irda/irttp.h>
42 #include <net/irda/irlmp.h>
43 #include <net/irda/iriap.h>
44 #include <net/irda/timer.h>
46 #include <net/irda/irlan_common.h>
48 static void __irlan_close( struct irlan_cb *self);
51 * Master structure
53 hashbin_t *irlan = NULL;
55 #ifdef CONFIG_PROC_FS
56 static int irlan_proc_read( char *buf, char **start, off_t offset,
57 int len, int unused);
59 extern struct proc_dir_entry proc_irda;
61 struct proc_dir_entry proc_irlan = {
62 0, 5, "irlan",
63 S_IFREG | S_IRUGO, 1, 0, 0,
64 0, NULL,
65 &irlan_proc_read,
67 #endif
70 * Function irlan_init (void)
72 * Initialize IrLAN layer
75 __initfunc(int irlan_init( void))
77 /* Allocate master array */
78 irlan = hashbin_new( HB_LOCAL);
79 if ( irlan == NULL) {
80 printk( KERN_WARNING "IrLAN: Can't allocate hashbin!\n");
81 return -ENOMEM;
83 #ifdef CONFIG_PROC_FS
84 proc_register( &proc_irda, &proc_irlan);
85 #endif /* CONFIG_PROC_FS */
87 return 0;
90 void irlan_cleanup(void)
92 DEBUG( 4, __FUNCTION__ "()\n");
94 #ifdef CONFIG_PROC_FS
95 proc_unregister( &proc_irda, proc_irlan.low_ino);
96 #endif
98 * Delete hashbin and close all irlan client instances in it
100 hashbin_delete( irlan, (FREE_FUNC) __irlan_close);
105 * Function irlan_open (void)
110 struct irlan_cb *irlan_open(void)
112 struct irlan_cb *self;
114 DEBUG( 4, __FUNCTION__ "()\n");
117 * Initialize the irlan structure.
119 self = kmalloc( sizeof(struct irlan_cb), GFP_ATOMIC);
120 if ( self == NULL)
121 return NULL;
123 memset( self, 0, sizeof( struct irlan_cb));
126 * Initialize local device structure
128 self->magic = IRLAN_MAGIC;
130 return self;
133 * Function irlan_close (self)
135 * This function closes and deallocates the IrLAN client instances. Be
136 * aware that other functions which calles client_close() must call
137 * hashbin_remove() first!!!
140 void __irlan_close( struct irlan_cb *self)
142 DEBUG( 4, __FUNCTION__ "()\n");
144 ASSERT( self != NULL, return;);
145 ASSERT( self->magic == IRLAN_MAGIC, return;);
148 * Disconnect open TSAP connections
150 if ( self->tsap_data) {
151 irttp_disconnect_request( self->tsap_data, NULL, P_HIGH);
153 /* FIXME: this will close the tsap before the disconenct
154 * frame has been sent
156 /* irttp_close_tsap( self->tsap_data); */
158 if ( self->tsap_ctrl) {
159 irttp_disconnect_request( self->tsap_ctrl, NULL, P_HIGH);
161 /* irttp_close_tsap( self->tsap_control); */
164 unregister_netdev( &self->dev);
167 * Make sure that nobody uses this instance anymore!
169 self->magic = 0;
172 * Dealloacte structure
174 kfree( self);
178 * Function irlan_close (self)
183 void irlan_close( struct irlan_cb *self)
185 struct irlan_cb *entry;
187 DEBUG( 4, __FUNCTION__ "()\n");
189 ASSERT( self != NULL, return;);
190 ASSERT( self->magic == IRLAN_MAGIC, return;);
192 entry = hashbin_remove( irlan, self->daddr, NULL);
194 ASSERT( entry == self, return;);
196 __irlan_close( self);
200 * Function irlan_get_provider_info (self)
202 * Send Get Provider Information command to peer IrLAN layer
205 void irlan_get_provider_info( struct irlan_cb *self)
207 struct sk_buff *skb;
208 __u8 *frame;
210 DEBUG( 4, __FUNCTION__ "()\n");
212 ASSERT( self != NULL, return;);
213 ASSERT( self->magic == IRLAN_MAGIC, return;);
215 skb = dev_alloc_skb( 64);
216 if (skb == NULL) {
217 DEBUG( 0, __FUNCTION__
218 "(), Could not allocate an skb of length %d\n", 64);
219 return;
222 /* Reserve space for TTP, LMP, and LAP header */
223 skb_reserve( skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
224 skb_put( skb, 2);
226 frame = skb->data;
228 frame[0] = CMD_GET_PROVIDER_INFO;
229 frame[1] = 0x00; /* Zero parameters */
231 irttp_data_request( self->tsap_ctrl, skb);
235 * Function irlan_open_data_channel (self)
237 * Send an Open Data Command to provider
240 void irlan_open_data_channel( struct irlan_cb *self)
242 struct sk_buff *skb;
243 __u8 *frame;
245 DEBUG( 4, __FUNCTION__ "()\n");
247 ASSERT( self != NULL, return;);
248 ASSERT( self->magic == IRLAN_MAGIC, return;);
250 skb = dev_alloc_skb( 64);
251 if (skb == NULL) {
252 DEBUG( 0, __FUNCTION__
253 "(), Could not allocate an skb of length %d\n", 64);
254 return;
257 /* Reserve space for TTP, LMP, and LAP header */
258 skb_reserve( skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
259 skb_put( skb, 2);
261 frame = skb->data;
263 /* Build frame */
264 frame[0] = CMD_OPEN_DATA_CHANNEL;
265 frame[1] = 0x02; /* Two parameters */
267 insert_string_param( skb, "MEDIA", "802.3");
268 insert_string_param( skb, "ACCESS_TYPE", "DIRECT");
269 /* insert_string_param( skb, "MODE", "UNRELIABLE"); */
271 /* self->use_udata = TRUE; */
273 irttp_data_request( self->tsap_ctrl, skb);
277 * Function irlan_open_unicast_addr (self)
279 * Make IrLAN provider accept ethernet frames addressed to the unicast
280 * address.
283 void irlan_open_unicast_addr( struct irlan_cb *self)
285 struct sk_buff *skb;
286 __u8 *frame;
288 DEBUG( 4, __FUNCTION__ "()\n");
290 ASSERT( self != NULL, return;);
291 ASSERT( self->magic == IRLAN_MAGIC, return;);
293 skb = dev_alloc_skb( 128);
294 if (skb == NULL) {
295 DEBUG( 0, __FUNCTION__
296 "(), Could not allocate an skb of length %d\n", 64);
297 return;
300 /* Reserve space for TTP, LMP, and LAP header */
301 skb_reserve( skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
302 skb_put( skb, 2);
304 frame = skb->data;
306 frame[0] = CMD_FILTER_OPERATION;
307 frame[1] = 0x03; /* Three parameters */
308 insert_byte_param( skb, "DATA_CHAN" , self->dtsap_sel_data);
309 insert_string_param( skb, "FILTER_TYPE", "DIRECTED");
310 insert_string_param( skb, "FILTER_MODE", "FILTER");
312 irttp_data_request( self->tsap_ctrl, skb);
316 * Function irlan_set_broadcast_filter (self, status)
318 * Make IrLAN provider accept ethernet frames addressed to the broadcast
319 * address. Be careful with the use of this one, sice there may be a lot
320 * of broadcast traffic out there. We can still function without this
321 * one but then _we_ have to initiate all communication with other
322 * hosts, sice ARP request for this host will not be answered.
324 void irlan_set_broadcast_filter( struct irlan_cb *self, int status)
326 struct sk_buff *skb;
327 __u8 *frame;
329 DEBUG( 4, __FUNCTION__ "()\n");
331 ASSERT( self != NULL, return;);
332 ASSERT( self->magic == IRLAN_MAGIC, return;);
334 /* Should only be used by client */
335 if (!self->client)
336 return;
338 skb = dev_alloc_skb( 128);
339 if (skb == NULL) {
340 DEBUG( 0, __FUNCTION__
341 "(), Could not allocate an skb of length %d\n", 64);
342 return;
345 /* Reserve space for TTP, LMP, and LAP header */
346 skb_reserve( skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
347 skb_put( skb, 2);
349 frame = skb->data;
351 frame[0] = CMD_FILTER_OPERATION;
352 frame[1] = 0x03; /* Three parameters */
353 insert_byte_param( skb, "DATA_CHAN", self->dtsap_sel_data);
354 insert_string_param( skb, "FILTER_TYPE", "BROADCAST");
355 if ( status)
356 insert_string_param( skb, "FILTER_MODE", "FILTER");
357 else
358 insert_string_param( skb, "FILTER_MODE", "NONE");
360 irttp_data_request( self->tsap_ctrl, skb);
364 * Function irlan_set_multicast_filter (self, status)
366 * Make IrLAN provider accept ethernet frames addressed to the multicast
367 * address.
370 void irlan_set_multicast_filter( struct irlan_cb *self, int status)
372 struct sk_buff *skb;
373 __u8 *frame;
375 DEBUG( 4, __FUNCTION__ "()\n");
377 ASSERT( self != NULL, return;);
378 ASSERT( self->magic == IRLAN_MAGIC, return;);
380 /* Should only be used by client */
381 if (!self->client)
382 return;
384 skb = dev_alloc_skb( 128);
385 if (skb == NULL) {
386 DEBUG( 0, __FUNCTION__
387 "(), Could not allocate an skb of length %d\n", 64);
388 return;
391 /* Reserve space for TTP, LMP, and LAP header */
392 skb_reserve( skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
393 skb_put( skb, 2);
395 frame = skb->data;
397 frame[0] = CMD_FILTER_OPERATION;
398 frame[1] = 0x03; /* Three parameters */
399 insert_byte_param( skb, "DATA_CHAN", self->dtsap_sel_data);
400 insert_string_param( skb, "FILTER_TYPE", "MULTICAST");
401 if ( status)
402 insert_string_param( skb, "FILTER_MODE", "ALL");
403 else
404 insert_string_param( skb, "FILTER_MODE", "NONE");
406 irttp_data_request( self->tsap_ctrl, skb);
410 * Function irlan_get_unicast_addr (self)
412 * Retrives the unicast address from the IrLAN provider. This address
413 * will be inserted into the devices structure, so the ethernet layer
414 * can construct its packets.
417 void irlan_get_unicast_addr( struct irlan_cb *self)
419 struct sk_buff *skb;
420 __u8 *frame;
422 DEBUG( 4, __FUNCTION__ "()\n");
424 ASSERT( self != NULL, return;);
425 ASSERT( self->magic == IRLAN_MAGIC, return;);
427 skb = dev_alloc_skb( 128);
428 if (skb == NULL) {
429 DEBUG( 0, "irlan_client_get_unicast_addr: "
430 "Could not allocate an sk_buff of length %d\n", 64);
431 return;
434 /* Reserve space for TTP, LMP, and LAP header */
435 skb_reserve( skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
436 skb_put( skb, 2);
438 frame = skb->data;
440 frame[0] = CMD_FILTER_OPERATION;
441 frame[1] = 0x03; /* Three parameters */
442 insert_byte_param( skb, "DATA_CHAN", self->dtsap_sel_data);
443 insert_string_param( skb, "FILTER_TYPE", "DIRECTED");
444 insert_string_param( skb, "FILTER_OPERATION", "DYNAMIC");
446 irttp_data_request( self->tsap_ctrl, skb);
450 * Function irlan_get_media_char (self)
455 void irlan_get_media_char( struct irlan_cb *self)
457 struct sk_buff *skb;
458 __u8 *frame;
460 DEBUG( 4, __FUNCTION__ "()\n");
462 ASSERT( self != NULL, return;);
463 ASSERT( self->magic == IRLAN_MAGIC, return;);
465 skb = dev_alloc_skb( 64);
466 if (skb == NULL) {
467 DEBUG( 0,"irlan_server_get_media_char: "
468 "Could not allocate an sk_buff of length %d\n", 64);
469 return;
472 /* Reserve space for TTP, LMP, and LAP header */
473 skb_reserve( skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
474 skb_put( skb, 2);
476 frame = skb->data;
478 /* Build frame */
479 frame[0] = CMD_GET_MEDIA_CHAR;
480 frame[1] = 0x01; /* One parameter */
482 insert_string_param( skb, "MEDIA", "802.3");
484 irttp_data_request( self->tsap_ctrl, skb);
488 * Function insert_byte_param (skb, param, value)
490 * Insert byte parameter into frame
493 int insert_byte_param( struct sk_buff *skb, char *param, __u8 value)
495 __u8 *frame;
496 __u8 len_param;
497 __u16 len_value;
498 int n=0;
500 if ( skb == NULL) {
501 DEBUG( 0, "insert_param: Got NULL skb\n");
502 return 0;
505 len_param = strlen( param);
506 len_value = 1;
509 * Insert at end of sk-buffer
511 frame = skb->tail;
513 /* Make space for data */
514 if ( skb_tailroom(skb) < (len_param+len_value+3)) {
515 DEBUG( 0, "insert_param: No more space at end of skb\n");
516 return 0;
518 skb_put( skb, len_param+len_value+3);
520 /* Insert parameter length */
521 frame[n++] = len_param;
523 /* Insert parameter */
524 memcpy( frame+n, param, len_param);
525 n += len_param;
527 /* Insert value length ( 2 byte little endian format, LSB first) */
528 frame[n++] = len_value & 0xff;
529 frame[n++] = len_value >> 8;
531 frame[n++] = value;
533 return len_param+len_value+3;
537 * Function insert_string (skb, param, value)
539 * Insert string parameter into frame
542 int insert_string_param( struct sk_buff *skb, char *param, char *value)
544 __u8 *frame;
545 __u8 len_param;
546 __u16 len_value;
547 int n=0;
549 if ( skb == NULL) {
550 DEBUG( 0, "insert_param: Got NULL skb\n");
551 return 0;
553 len_param = strlen( param);
554 len_value = strlen( value);
557 * Insert at end of sk-buffer
559 frame = skb->tail;
561 /* Make space for data */
562 if ( skb_tailroom(skb) < (len_param+len_value+3)) {
563 DEBUG( 0, "insert_param: No more space at end of skb\n");
564 return 0;
566 skb_put( skb, len_param+len_value+3);
568 /* Insert parameter length */
569 frame[n++] = len_param;
571 /* Insert parameter */
572 memcpy( frame+n, param, len_param);
573 n += len_param;
575 /* Insert value length ( 2 byte little endian format, LSB first) */
576 frame[n++] = len_value & 0xff;
577 frame[n++] = len_value >> 8;
579 memcpy( frame+n, value, len_value);
580 n+=len_value;
582 return len_param+len_value+3;
586 * Function insert_array_param( skb, param, value, len_value)
588 * Insert array parameter into frame
591 int insert_array_param( struct sk_buff *skb, char *name, __u8 *value,
592 __u16 value_len)
594 __u8 *frame;
595 __u8 name_len;
596 int n=0;
598 if ( skb == NULL) {
599 DEBUG( 0, __FUNCTION__ "(), Got NULL skb\n");
600 return 0;
602 name_len = strlen( name);
605 * Insert at end of sk-buffer
607 frame = skb->tail;
609 /* Make space for data */
610 if ( skb_tailroom(skb) < (name_len+value_len+3)) {
611 DEBUG( 0, __FUNCTION__ "(), No more space at end of skb\n");
612 return 0;
614 skb_put( skb, name_len+value_len+3);
616 /* Insert parameter length */
617 frame[n++] = name_len;
619 /* Insert parameter */
620 memcpy( frame+n, name, name_len);
621 n += name_len;
623 /* Insert value length ( 2 byte little endian format, LSB first) */
624 /* FIXME: should we use htons() here? */
625 frame[n++] = value_len & 0xff;
626 frame[n++] = value_len >> 8;
628 memcpy( frame+n, value, value_len);
629 n+=value_len;
631 return name_len+value_len+3;
635 * Function insert_param (skb, param, value, byte)
637 * Insert parameter at end of buffer, structure of a parameter is:
639 * -----------------------------------------------------------------------
640 * | Name Length[1] | Param Name[1..255] | Val Length[2] | Value[0..1016]|
641 * -----------------------------------------------------------------------
643 int insert_param( struct sk_buff *skb, char *param, int type, char *value_char,
644 __u8 value_byte, __u16 value_short)
646 __u8 *frame;
647 __u8 len_param;
648 __u16 len_value;
649 int n;
651 if ( skb == NULL) {
652 DEBUG( 0, "insert_param: Got NULL skb\n");
653 return 0;
656 n = 0;
658 len_param = strlen( param);
659 switch ( type) {
660 case 1:
661 ASSERT( value_char != NULL, return 0;);
662 len_value = strlen( value_char);
663 break;
664 case 2:
665 len_value = 1;
666 break;
667 case 3:
668 len_value = 2;
669 break;
670 default:
671 DEBUG( 0, "Error in insert_param!\n");
672 return 0;
673 break;
677 * Insert at end of sk-buffer
679 frame = skb->tail;
681 /* Make space for data */
682 if ( skb_tailroom(skb) < (len_param+len_value+3)) {
683 DEBUG( 0, "insert_param: No more space at end of skb\n");
684 return 0;
686 skb_put( skb, len_param+len_value+3);
688 /* Insert parameter length */
689 frame[n++] = len_param;
691 /* Insert parameter */
692 memcpy( frame+n, param, len_param); n += len_param;
694 /* Insert value length ( 2 byte little endian format, LSB first) */
695 frame[n++] = len_value & 0xff;
696 frame[n++] = len_value >> 8;
698 /* Insert value */
699 switch (type) {
700 case 1:
701 memcpy( frame+n, value_char, len_value); n+=len_value;
702 break;
703 case 2:
704 frame[n++] = value_byte;
705 break;
706 case 3:
707 frame[n++] = value_short & 0xff;
708 frame[n++] = (value_short >> 8) & 0xff;
709 break;
710 default:
711 break;
713 ASSERT( n == (len_param+len_value+3), return 0;);
715 return len_param+len_value+3;
719 * Function irlan_get_response_param (buf, param, value)
721 * Extracts a single parameter name/value pair from buffer and updates
722 * the buffer pointer to point to the next name/value pair.
725 int irlan_get_response_param( __u8 *buf, char *name, char *value, int *len)
727 __u8 name_len;
728 __u16 val_len;
729 int n=0;
731 DEBUG( 4, "irlan_get_response_param()\n");
733 /* get length of parameter name ( 1 byte) */
734 name_len = buf[n++];
736 if (name_len > 254) {
737 DEBUG( 0, __FUNCTION__ "(), name_len > 254\n");
738 return -1;
741 /* get parameter name */
742 memcpy( name, buf+n, name_len);
743 name[ name_len] = '\0';
744 n+=name_len;
747 * Get length of parameter value ( 2 bytes in little endian
748 * format)
750 val_len = buf[n++] & 0xff;
751 val_len |= buf[n++] << 8;
753 if (val_len > 1016) {
754 DEBUG( 0, __FUNCTION__ "(), parameter length to long\n");
755 return -1;
758 *len = val_len;
760 /* get parameter value */
761 memcpy( value, buf+n, val_len);
762 value[ val_len] = '\0';
763 n+=val_len;
765 DEBUG( 4, "Parameter: %s ", name);
766 DEBUG( 4, "Value: %s\n", value);
768 return n;
771 #ifdef CONFIG_PROC_FS
773 * Function irlan_client_proc_read (buf, start, offset, len, unused)
775 * Give some info to the /proc file system
777 static int irlan_proc_read( char *buf, char **start, off_t offset,
778 int len, int unused)
780 struct irlan_cb *self;
782 ASSERT( irlan != NULL, return 0;);
784 len = 0;
786 len += sprintf( buf+len, "IrLAN\n");
788 self = ( struct irlan_cb *) hashbin_get_first( irlan);
789 while ( self != NULL) {
790 ASSERT( self->magic == IRLAN_MAGIC, return len;);
792 len += sprintf( buf+len, "ifname: %s, ",
793 self->ifname);
794 /* len += sprintf( buf+len, "state: %s, ", */
795 /* irlan_client_state[ self->state]); */
796 len += sprintf( buf+len, "saddr: %#08x\n",
797 self->saddr);
798 len += sprintf( buf+len, "daddr: %#08x\n",
799 self->daddr);
800 len += sprintf( buf+len, "tbusy: %s\n", self->dev.tbusy ?
801 "TRUE" : "FALSE");
803 len += sprintf( buf+len, "\n");
805 self = ( struct irlan_cb *) hashbin_get_next( irlan);
806 DEBUG( 4, "self=%p\n", self);
808 return len;
810 #endif
813 * Function print_ret_code (code)
815 * Print return code of request to peer IrLAN layer.
818 void print_ret_code( __u8 code)
820 switch( code) {
821 case 0:
822 printk( KERN_INFO "Success\n");
823 break;
824 case 1:
825 printk( KERN_WARNING "Insufficient resources\n");
826 break;
827 case 2:
828 printk( KERN_WARNING "Invalid command format\n");
829 break;
830 case 3:
831 printk( KERN_WARNING "Command not supported\n");
832 break;
833 case 4:
834 printk( KERN_WARNING "Parameter not supported\n");
835 break;
836 case 5:
837 printk( KERN_WARNING "Value not supported\n");
838 break;
839 case 6:
840 printk( KERN_WARNING "Not open\n");
841 break;
842 case 7:
843 printk( KERN_WARNING "Authentication required\n");
844 break;
845 case 8:
846 printk( KERN_WARNING "Invalid password\n");
847 break;
848 case 9:
849 printk( KERN_WARNING "Protocol error\n");
850 break;
851 case 255:
852 printk( KERN_WARNING "Asynchronous status\n");
853 break;
857 #ifdef MODULE
859 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
860 MODULE_DESCRIPTION("The Linux IrDA LAN protocol");
863 * Function init_module (void)
865 * Initialize the IrLAN module, this function is called by the
866 * modprobe(1) program.
868 int init_module(void)
870 DEBUG( 4, __FUNCTION__ "(), irlan.c\n");
872 irlan_init();
874 return 0;
878 * Function cleanup_module (void)
880 * Remove the IrLAN module, this function is called by the rmmod(1)
881 * program
883 void cleanup_module(void)
885 DEBUG( 4, "--> irlan, cleanup_module\n");
886 /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
888 /* Free some memory */
889 irlan_cleanup();
891 DEBUG( 4, "irlan, cleanup_module -->\n");
894 #endif /* MODULE */