Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

irlan_common.c

Go to the documentation of this file.
00001 /*********************************************************************
00002  *                
00003  * Filename:      irlan_common.c
00004  * Version:       0.9
00005  * Description:   IrDA LAN Access Protocol Implementation
00006  * Status:        Experimental.
00007  * Author:        Dag Brattli <dagb@cs.uit.no>
00008  * Created at:    Sun Aug 31 20:14:37 1997
00009  * Modified at:   Fri Apr 21 14:55:31 2000
00010  * Modified by:   Dag Brattli <dagb@cs.uit.no>
00011  * 
00012  *     Copyright (c) 1997, 1999-2000 Dag Brattli <dagb@cs.uit.no>, 
00013  *     All Rights Reserved.
00014  *     
00015  *     This program is free software; you can redistribute it and/or 
00016  *     modify it under the terms of the GNU General Public License as 
00017  *     published by the Free Software Foundation; either version 2 of 
00018  *     the License, or (at your option) any later version.
00019  *
00020  *     Neither Dag Brattli nor University of Tromsų admit liability nor
00021  *     provide warranty for any of this software. This material is 
00022  *     provided "AS-IS" and at no charge.
00023  *
00024  ********************************************************************/
00025 
00026 #include <linux/config.h>
00027 #include <linux/module.h>
00028 
00029 #include <linux/kernel.h>
00030 #include <linux/string.h>
00031 #include <linux/init.h>
00032 #include <linux/errno.h>
00033 #include <linux/proc_fs.h>
00034 #include <linux/netdevice.h>
00035 #include <linux/etherdevice.h>
00036 
00037 #include <asm/system.h>
00038 #include <asm/bitops.h>
00039 #include <asm/byteorder.h>
00040 
00041 #include <net/irda/irda.h>
00042 #include <net/irda/irttp.h>
00043 #include <net/irda/irlmp.h>
00044 #include <net/irda/iriap.h>
00045 #include <net/irda/timer.h>
00046 
00047 #include <net/irda/irlan_common.h>
00048 #include <net/irda/irlan_client.h>
00049 #include <net/irda/irlan_provider.h> 
00050 #include <net/irda/irlan_eth.h>
00051 #include <net/irda/irlan_filter.h>
00052 
00053 /* 
00054  * Send gratuitous ARP when connected to a new AP or not. May be a clever
00055  * thing to do, but for some reason the machine crashes if you use DHCP. So
00056  * lets not use it by default.
00057  */
00058 #undef CONFIG_IRLAN_SEND_GRATUITOUS_ARP
00059 
00060 /* extern char sysctl_devname[]; */
00061 
00062 /*
00063  *  Master structure
00064  */
00065 hashbin_t *irlan = NULL;
00066 static __u32 ckey, skey;
00067 
00068 /* Module parameters */
00069 static int eth = 0; /* Use "eth" or "irlan" name for devices */
00070 static int access = ACCESS_PEER; /* PEER, DIRECT or HOSTED */
00071 
00072 static char *irlan_state[] = {
00073         "IRLAN_IDLE",
00074         "IRLAN_QUERY",
00075         "IRLAN_CONN",
00076         "IRLAN_INFO",
00077         "IRLAN_MEDIA",
00078         "IRLAN_OPEN",
00079         "IRLAN_WAIT",
00080         "IRLAN_ARB", 
00081         "IRLAN_DATA",
00082         "IRLAN_CLOSE",
00083         "IRLAN_SYNC"
00084 };
00085 
00086 static char *irlan_access[] = {
00087         "UNKNOWN",
00088         "DIRECT",
00089         "PEER",
00090         "HOSTED"
00091 };
00092 
00093 static char *irlan_media[] = {
00094         "UNKNOWN",
00095         "802.3",
00096         "802.5"
00097 };
00098 
00099 static void __irlan_close(struct irlan_cb *self);
00100 static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, 
00101                                 __u8 value_byte, __u16 value_short, 
00102                                 __u8 *value_array, __u16 value_len);
00103 void irlan_close_tsaps(struct irlan_cb *self);
00104 
00105 #ifdef CONFIG_PROC_FS
00106 static int irlan_proc_read(char *buf, char **start, off_t offset, int len, 
00107                            int unused);
00108 
00109 extern struct proc_dir_entry *proc_irda;
00110 #endif /* CONFIG_PROC_FS */
00111 
00112 /*
00113  * Function irlan_init (void)
00114  *
00115  *    Initialize IrLAN layer
00116  *
00117  */
00118 int __init irlan_init(void)
00119 {
00120         struct irlan_cb *new;
00121         __u16 hints;
00122 
00123         IRDA_DEBUG(4, __FUNCTION__"()\n");
00124 
00125         /* Allocate master structure */
00126         irlan = hashbin_new(HB_LOCAL); 
00127         if (irlan == NULL) {
00128                 printk(KERN_WARNING "IrLAN: Can't allocate hashbin!\n");
00129                 return -ENOMEM;
00130         }
00131 #ifdef CONFIG_PROC_FS
00132         create_proc_entry("irlan", 0, proc_irda)->get_info = irlan_proc_read;
00133 #endif /* CONFIG_PROC_FS */
00134 
00135         hints = irlmp_service_to_hint(S_LAN);
00136 
00137         /* Register with IrLMP as a client */
00138         ckey = irlmp_register_client(hints, irlan_client_discovery_indication,
00139                                      NULL);
00140         
00141         /* Register with IrLMP as a service */
00142         skey = irlmp_register_service(hints);
00143 
00144         /* Start the master IrLAN instance (the only one for now) */
00145         new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY);
00146 
00147         /* The master will only open its (listen) control TSAP */
00148         irlan_provider_open_ctrl_tsap(new);
00149 
00150         /* Do some fast discovery! */
00151         irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
00152 
00153         return 0;
00154 }
00155 
00156 void irlan_cleanup(void) 
00157 {
00158         IRDA_DEBUG(4, __FUNCTION__ "()\n");
00159 
00160         irlmp_unregister_client(ckey);
00161         irlmp_unregister_service(skey);
00162 
00163 #ifdef CONFIG_PROC_FS
00164         remove_proc_entry("irlan", proc_irda);
00165 #endif /* CONFIG_PROC_FS */
00166         /*
00167          *  Delete hashbin and close all irlan client instances in it
00168          */
00169         hashbin_delete(irlan, (FREE_FUNC) __irlan_close);
00170 }
00171 
00172 /*
00173  * Function irlan_register_netdev (self)
00174  *
00175  *    Registers the network device to be used. We should don't register until
00176  *    we have been binded to a particular provider or client.
00177  */
00178 int irlan_register_netdev(struct irlan_cb *self)
00179 {
00180         int i=0;
00181 
00182         IRDA_DEBUG(0, __FUNCTION__ "()\n");
00183 
00184         /* Check if we should call the device eth<x> or irlan<x> */
00185         if (!eth) {
00186                 /* Get the first free irlan<x> name */
00187                 do {
00188                         sprintf(self->ifname, "%s%d", "irlan", i++);
00189                 } while (dev_get(self->ifname));
00190         }
00191         self->dev.name = self->ifname;
00192         
00193         if (register_netdev(&self->dev) != 0) {
00194                 IRDA_DEBUG(2, __FUNCTION__ "(), register_netdev() failed!\n");
00195                 return -1;
00196         }
00197         return 0;
00198 }
00199 
00200 /*
00201  * Function irlan_open (void)
00202  *
00203  *    Open new instance of a client/provider, we should only register the 
00204  *    network device if this instance is ment for a particular client/provider
00205  */
00206 struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr)
00207 {
00208         struct irlan_cb *self;
00209 
00210         IRDA_DEBUG(2, __FUNCTION__ "()\n");
00211 
00212         /* 
00213          *  Initialize the irlan structure. 
00214          */
00215         self = kmalloc(sizeof(struct irlan_cb), GFP_ATOMIC);
00216         if (self == NULL)
00217                 return NULL;
00218         
00219         memset(self, 0, sizeof(struct irlan_cb));
00220 
00221         /*
00222          *  Initialize local device structure
00223          */
00224         self->magic = IRLAN_MAGIC;
00225 
00226         ASSERT(irlan != NULL, return NULL;);
00227         
00228         sprintf(self->ifname, "%s", "unknown");
00229 
00230         self->dev.priv = (void *) self;
00231         self->dev.next = NULL;
00232         self->dev.init = irlan_eth_init;
00233         
00234         self->saddr = saddr;
00235         self->daddr = daddr;
00236 
00237         /* Provider access can only be PEER, DIRECT, or HOSTED */
00238         self->provider.access_type = access;
00239         self->media = MEDIA_802_3;
00240 
00241         init_timer(&self->watchdog_timer);
00242         init_timer(&self->client.kick_timer);
00243 
00244         hashbin_insert(irlan, (queue_t *) self, daddr, NULL);
00245         
00246         skb_queue_head_init(&self->client.txq);
00247         
00248         irlan_next_client_state(self, IRLAN_IDLE);
00249         irlan_next_provider_state(self, IRLAN_IDLE);
00250 
00251         irlan_register_netdev(self);
00252 
00253         return self;
00254 }
00255 /*
00256  * Function __irlan_close (self)
00257  *
00258  *    This function closes and deallocates the IrLAN client instances. Be 
00259  *    aware that other functions which calles client_close() must call 
00260  *    hashbin_remove() first!!!
00261  */
00262 static void __irlan_close(struct irlan_cb *self)
00263 {
00264         struct sk_buff *skb;
00265 
00266         IRDA_DEBUG(2, __FUNCTION__ "()\n");
00267         
00268         ASSERT(self != NULL, return;);
00269         ASSERT(self->magic == IRLAN_MAGIC, return;);
00270 
00271         del_timer(&self->watchdog_timer);
00272         del_timer(&self->client.kick_timer);
00273 
00274         /* Close all open connections and remove TSAPs */
00275         irlan_close_tsaps(self);
00276         
00277         if (self->client.iriap) 
00278                 iriap_close(self->client.iriap);
00279 
00280         /* Remove frames queued on the control channel */
00281         while ((skb = skb_dequeue(&self->client.txq)))
00282                 dev_kfree_skb(skb);
00283         
00284         unregister_netdev(&self->dev);
00285         
00286         self->magic = 0;
00287         kfree(self);
00288 }
00289 
00290 /*
00291  * Function irlan_connect_indication (instance, sap, qos, max_sdu_size, skb)
00292  *
00293  *    Here we receive the connect indication for the data channel
00294  *
00295  */
00296 void irlan_connect_indication(void *instance, void *sap, struct qos_info *qos,
00297                               __u32 max_sdu_size, __u8 max_header_size, 
00298                               struct sk_buff *skb)
00299 {
00300         struct irlan_cb *self;
00301         struct tsap_cb *tsap;
00302 
00303         IRDA_DEBUG(2, __FUNCTION__ "()\n");
00304         
00305         self = (struct irlan_cb *) instance;
00306         tsap = (struct tsap_cb *) sap;
00307         
00308         ASSERT(self != NULL, return;);
00309         ASSERT(self->magic == IRLAN_MAGIC, return;);
00310         ASSERT(tsap == self->tsap_data,return;);
00311 
00312         self->max_sdu_size = max_sdu_size;
00313         self->max_header_size = max_header_size;
00314 
00315         IRDA_DEBUG(0, "IrLAN, We are now connected!\n");
00316 
00317         del_timer(&self->watchdog_timer);
00318 
00319         irlan_do_provider_event(self, IRLAN_DATA_CONNECT_INDICATION, skb);
00320         irlan_do_client_event(self, IRLAN_DATA_CONNECT_INDICATION, skb);
00321 
00322         if (self->provider.access_type == ACCESS_PEER) {
00323                 /* 
00324                  * Data channel is open, so we are now allowed to
00325                  * configure the remote filter 
00326                  */
00327                 irlan_get_unicast_addr(self);
00328                 irlan_open_unicast_addr(self);
00329         }
00330         /* Ready to transfer Ethernet frames (at last) */
00331         self->dev.tbusy = 0;
00332         self->disconnect_reason = 0; /* Clear reason */
00333 }
00334 
00335 void irlan_connect_confirm(void *instance, void *sap, struct qos_info *qos, 
00336                            __u32 max_sdu_size, __u8 max_header_size, 
00337                            struct sk_buff *skb) 
00338 {
00339         struct irlan_cb *self;
00340 
00341         self = (struct irlan_cb *) instance;
00342 
00343         ASSERT(self != NULL, return;);
00344         ASSERT(self->magic == IRLAN_MAGIC, return;);
00345 
00346         self->max_sdu_size = max_sdu_size;
00347         self->max_header_size = max_header_size;
00348 
00349         /* TODO: we could set the MTU depending on the max_sdu_size */
00350 
00351         IRDA_DEBUG(2, "IrLAN, We are now connected!\n");
00352         del_timer(&self->watchdog_timer);
00353 
00354         /* 
00355          * Data channel is open, so we are now allowed to configure the remote
00356          * filter 
00357          */
00358         irlan_get_unicast_addr(self);
00359         irlan_open_unicast_addr(self);
00360         
00361         /* Open broadcast and multicast filter by default */
00362         irlan_set_broadcast_filter(self, TRUE);
00363         irlan_set_multicast_filter(self, TRUE);
00364 
00365         /* Ready to transfer Ethernet frames */
00366         self->dev.tbusy = 0;
00367         self->dev.start = 1;
00368         self->disconnect_reason = 0; /* Clear reason */
00369 
00370 #ifdef CONFIG_IRLAN_SEND_GRATUITOUS_ARP
00371         irlan_eth_send_gratuitous_arp(&self->dev);
00372 #endif
00373 }
00374 
00375 /*
00376  * Function irlan_client_disconnect_indication (handle)
00377  *
00378  *    Callback function for the IrTTP layer. Indicates a disconnection of
00379  *    the specified connection (handle)
00380  */
00381 void irlan_disconnect_indication(void *instance, void *sap, LM_REASON reason, 
00382                                  struct sk_buff *userdata) 
00383 {
00384         struct irlan_cb *self;
00385         struct tsap_cb *tsap;
00386 
00387         IRDA_DEBUG(0, __FUNCTION__ "(), reason=%d\n", reason);
00388         
00389         self = (struct irlan_cb *) instance;
00390         tsap = (struct tsap_cb *) sap;
00391 
00392         ASSERT(self != NULL, return;);
00393         ASSERT(self->magic == IRLAN_MAGIC, return;);    
00394         ASSERT(tsap != NULL, return;);
00395         ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;);
00396         
00397         ASSERT(tsap == self->tsap_data, return;);
00398 
00399         IRDA_DEBUG(2, "IrLAN, data channel disconnected by peer!\n");
00400 
00401         /* Save reason, so we know if we should try to reconnect or not */
00402         self->disconnect_reason = reason;
00403 
00404         switch (reason) {
00405         case LM_USER_REQUEST: /* User request */
00406                 IRDA_DEBUG(2, __FUNCTION__ "(), user request\n");
00407                 break;
00408         case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */
00409                 IRDA_DEBUG(2, __FUNCTION__ "(), Unexpected IrLAP disconnect\n");
00410                 break;
00411         case LM_CONNECT_FAILURE: /* Failed to establish IrLAP connection */
00412                 IRDA_DEBUG(2, __FUNCTION__ "(), IrLAP connect failed\n");
00413                 break;
00414         case LM_LAP_RESET:  /* IrLAP reset */
00415                 IRDA_DEBUG(2, __FUNCTION__ "(), IrLAP reset\n");
00416                 break;
00417         case LM_INIT_DISCONNECT:
00418                 IRDA_DEBUG(2, __FUNCTION__ "(), IrLMP connect failed\n");
00419                 break;
00420         default:
00421                 ERROR(__FUNCTION__ "(), Unknown disconnect reason\n");
00422                 break;
00423         }       
00424         irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
00425         irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
00426 }
00427 
00428 void irlan_open_data_tsap(struct irlan_cb *self)
00429 {
00430         struct tsap_cb *tsap;
00431         notify_t notify;
00432 
00433         IRDA_DEBUG(2, __FUNCTION__ "()\n");
00434 
00435         ASSERT(self != NULL, return;);
00436         ASSERT(self->magic == IRLAN_MAGIC, return;);
00437 
00438         /* Check if already open */
00439         if (self->tsap_data)
00440                 return;
00441 
00442         irda_notify_init(&notify);
00443         
00444         notify.data_indication       = irlan_eth_receive;
00445         notify.udata_indication      = irlan_eth_receive;
00446         notify.connect_indication    = irlan_connect_indication;
00447         notify.connect_confirm       = irlan_connect_confirm;
00448         /*notify.flow_indication       = irlan_eth_flow_indication;*/
00449         notify.disconnect_indication = irlan_disconnect_indication;
00450         notify.instance              = self;
00451         strncpy(notify.name, "IrLAN data", NOTIFY_MAX_NAME);
00452 
00453         tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, &notify);
00454         if (!tsap) {
00455                 IRDA_DEBUG(2, __FUNCTION__ "(), Got no tsap!\n");
00456                 return;
00457         }
00458         self->tsap_data = tsap;
00459 
00460         /* 
00461          *  This is the data TSAP selector which we will pass to the client
00462          *  when the client ask for it.
00463          */
00464         self->stsap_sel_data = self->tsap_data->stsap_sel;
00465 }
00466 
00467 void irlan_close_tsaps(struct irlan_cb *self)
00468 {
00469         IRDA_DEBUG(4, __FUNCTION__ "()\n");
00470 
00471         ASSERT(self != NULL, return;);
00472         ASSERT(self->magic == IRLAN_MAGIC, return;);
00473 
00474         /* Disconnect and close all open TSAP connections */
00475         if (self->tsap_data) {
00476                 irttp_disconnect_request(self->tsap_data, NULL, P_NORMAL);
00477                 irttp_close_tsap(self->tsap_data);
00478                 self->tsap_data = NULL;
00479         }
00480         if (self->client.tsap_ctrl) {
00481                 irttp_disconnect_request(self->client.tsap_ctrl, NULL, 
00482                                          P_NORMAL);
00483                 irttp_close_tsap(self->client.tsap_ctrl);
00484                 self->client.tsap_ctrl = NULL;
00485         }
00486         if (self->provider.tsap_ctrl) {
00487                 irttp_disconnect_request(self->provider.tsap_ctrl, NULL, 
00488                                          P_NORMAL);
00489                 irttp_close_tsap(self->provider.tsap_ctrl);
00490                 self->provider.tsap_ctrl = NULL;
00491         }
00492 }
00493 
00494 /*
00495  * Function irlan_ias_register (self, tsap_sel)
00496  *
00497  *    Register with LM-IAS
00498  *
00499  */
00500 void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel)
00501 {
00502         struct ias_object *obj;
00503         struct ias_value *new_value;
00504 
00505         ASSERT(self != NULL, return;);
00506         ASSERT(self->magic == IRLAN_MAGIC, return;);
00507         
00508         /* 
00509          * Check if object has already been registred by a previous provider.
00510          * If that is the case, we just change the value of the attribute
00511          */
00512         if (!irias_find_object("IrLAN")) {
00513                 obj = irias_new_object("IrLAN", IAS_IRLAN_ID);
00514                 irias_add_integer_attrib(obj, "IrDA:TinyTP:LsapSel", tsap_sel);
00515                 irias_insert_object(obj);
00516         } else {
00517                 new_value = irias_new_integer_value(tsap_sel);
00518                 irias_object_change_attribute("IrLAN", "IrDA:TinyTP:LsapSel",
00519                                               new_value);
00520         }
00521         
00522         /* Register PnP object only if not registred before */
00523         if (!irias_find_object("PnP")) {
00524                 obj = irias_new_object("PnP", IAS_PNP_ID);
00525 #if 0
00526                 irias_add_string_attrib(obj, "Name", sysctl_devname);
00527 #else
00528                 irias_add_string_attrib(obj, "Name", "Linux");
00529 #endif
00530                 irias_add_string_attrib(obj, "DeviceID", "HWP19F0");
00531                 irias_add_integer_attrib(obj, "CompCnt", 1);
00532                 if (self->provider.access_type == ACCESS_PEER)
00533                         irias_add_string_attrib(obj, "Comp#01", "PNP8389");
00534                 else
00535                         irias_add_string_attrib(obj, "Comp#01", "PNP8294");
00536 
00537                 irias_add_string_attrib(obj, "Manufacturer", "Linux-IrDA Project");
00538                 irias_insert_object(obj);
00539         }
00540 }
00541 
00542 /*
00543  * Function irlan_run_ctrl_tx_queue (self)
00544  *
00545  *    Try to send the next command in the control transmit queue
00546  *
00547  */
00548 int irlan_run_ctrl_tx_queue(struct irlan_cb *self)
00549 {
00550         struct sk_buff *skb;
00551 
00552         IRDA_DEBUG(2, __FUNCTION__ "()\n");
00553 
00554         if (irda_lock(&self->client.tx_busy) == FALSE)
00555                 return -EBUSY;
00556 
00557         skb = skb_dequeue(&self->client.txq);
00558         if (!skb) {
00559                 self->client.tx_busy = FALSE;
00560                 return 0;
00561         }
00562         
00563         /* Check that it's really possible to send commands */
00564         if ((self->client.tsap_ctrl == NULL) || 
00565             (self->client.state == IRLAN_IDLE)) 
00566         {
00567                 self->client.tx_busy = FALSE;
00568                 dev_kfree_skb(skb);
00569                 return -1;
00570         }
00571         IRDA_DEBUG(2, __FUNCTION__ "(), sending ...\n");
00572 
00573         return irttp_data_request(self->client.tsap_ctrl, skb);
00574 }
00575 
00576 /*
00577  * Function irlan_ctrl_data_request (self, skb)
00578  *
00579  *    This function makes sure that commands on the control channel is being
00580  *    sent in a command/response fashion
00581  */
00582 void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb)
00583 {
00584         IRDA_DEBUG(2, __FUNCTION__ "()\n");
00585 
00586         /* Queue command */
00587         skb_queue_tail(&self->client.txq, skb);
00588 
00589         /* Try to send command */
00590         irlan_run_ctrl_tx_queue(self);
00591 }
00592 
00593 /*
00594  * Function irlan_get_provider_info (self)
00595  *
00596  *    Send Get Provider Information command to peer IrLAN layer
00597  *
00598  */
00599 void irlan_get_provider_info(struct irlan_cb *self)
00600 {
00601         struct sk_buff *skb;
00602         __u8 *frame;
00603 
00604         IRDA_DEBUG(4, __FUNCTION__ "()\n");
00605         
00606         ASSERT(self != NULL, return;);
00607         ASSERT(self->magic == IRLAN_MAGIC, return;);
00608 
00609         skb = dev_alloc_skb(64);
00610         if (!skb)
00611                 return;
00612 
00613         /* Reserve space for TTP, LMP, and LAP header */
00614         skb_reserve(skb, self->client.max_header_size);
00615         skb_put(skb, 2);
00616         
00617         frame = skb->data;
00618         
00619         frame[0] = CMD_GET_PROVIDER_INFO;
00620         frame[1] = 0x00;                 /* Zero parameters */
00621         
00622         irlan_ctrl_data_request(self, skb);
00623 }
00624 
00625 /*
00626  * Function irlan_open_data_channel (self)
00627  *
00628  *    Send an Open Data Command to provider
00629  *
00630  */
00631 void irlan_open_data_channel(struct irlan_cb *self) 
00632 {
00633         struct sk_buff *skb;
00634         __u8 *frame;
00635         
00636         IRDA_DEBUG(4, __FUNCTION__ "()\n");
00637 
00638         ASSERT(self != NULL, return;);
00639         ASSERT(self->magic == IRLAN_MAGIC, return;);
00640         
00641         skb = dev_alloc_skb(64);
00642         if (!skb)
00643                 return;
00644 
00645         skb_reserve(skb, self->client.max_header_size);
00646         skb_put(skb, 2);
00647         
00648         frame = skb->data;
00649         
00650         /* Build frame */
00651         frame[0] = CMD_OPEN_DATA_CHANNEL;
00652         frame[1] = 0x02; /* Two parameters */
00653 
00654         irlan_insert_string_param(skb, "MEDIA", "802.3");
00655         irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT");
00656         /* irlan_insert_string_param(skb, "MODE", "UNRELIABLE"); */
00657 
00658 /*      self->use_udata = TRUE; */
00659 
00660         irlan_ctrl_data_request(self, skb);
00661 }
00662 
00663 void irlan_close_data_channel(struct irlan_cb *self) 
00664 {
00665         struct sk_buff *skb;
00666         __u8 *frame;
00667         
00668         IRDA_DEBUG(4, __FUNCTION__ "()\n");
00669 
00670         ASSERT(self != NULL, return;);
00671         ASSERT(self->magic == IRLAN_MAGIC, return;);
00672 
00673         /* Check if the TSAP is still there */
00674         if (self->client.tsap_ctrl == NULL)
00675                 return;
00676 
00677         skb = dev_alloc_skb(64);
00678         if (!skb)
00679                 return;
00680 
00681         skb_reserve(skb, self->client.max_header_size);
00682         skb_put(skb, 2);
00683         
00684         frame = skb->data;
00685         
00686         /* Build frame */
00687         frame[0] = CMD_CLOSE_DATA_CHAN;
00688         frame[1] = 0x01; /* Two parameters */
00689 
00690         irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
00691 
00692         irlan_ctrl_data_request(self, skb);
00693 }
00694 
00695 /*
00696  * Function irlan_open_unicast_addr (self)
00697  *
00698  *    Make IrLAN provider accept ethernet frames addressed to the unicast 
00699  *    address.
00700  *
00701  */
00702 void irlan_open_unicast_addr(struct irlan_cb *self) 
00703 {
00704         struct sk_buff *skb;
00705         __u8 *frame;
00706         
00707         IRDA_DEBUG(4, __FUNCTION__ "()\n");
00708 
00709         ASSERT(self != NULL, return;);
00710         ASSERT(self->magic == IRLAN_MAGIC, return;);    
00711         
00712         skb = dev_alloc_skb(128);
00713         if (!skb)
00714                 return;
00715 
00716         /* Reserve space for TTP, LMP, and LAP header */
00717         skb_reserve(skb, self->max_header_size);
00718         skb_put(skb, 2);
00719         
00720         frame = skb->data;
00721         
00722         frame[0] = CMD_FILTER_OPERATION;
00723         frame[1] = 0x03;                 /* Three parameters */
00724         irlan_insert_byte_param(skb, "DATA_CHAN" , self->dtsap_sel_data);
00725         irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
00726         irlan_insert_string_param(skb, "FILTER_MODE", "FILTER"); 
00727         
00728         irlan_ctrl_data_request(self, skb);
00729 }
00730 
00731 /*
00732  * Function irlan_set_broadcast_filter (self, status)
00733  *
00734  *    Make IrLAN provider accept ethernet frames addressed to the broadcast
00735  *    address. Be careful with the use of this one, since there may be a lot
00736  *    of broadcast traffic out there. We can still function without this
00737  *    one but then _we_ have to initiate all communication with other
00738  *    hosts, since ARP request for this host will not be answered.
00739  */
00740 void irlan_set_broadcast_filter(struct irlan_cb *self, int status) 
00741 {
00742         struct sk_buff *skb;
00743         __u8 *frame;
00744         
00745         IRDA_DEBUG(2, __FUNCTION__ "()\n");
00746 
00747         ASSERT(self != NULL, return;);
00748         ASSERT(self->magic == IRLAN_MAGIC, return;);
00749         
00750         skb = dev_alloc_skb(128);
00751         if (!skb)
00752                 return;
00753 
00754         /* Reserve space for TTP, LMP, and LAP header */
00755         skb_reserve(skb, self->client.max_header_size);
00756         skb_put(skb, 2);
00757         
00758         frame = skb->data;
00759         
00760         frame[0] = CMD_FILTER_OPERATION;
00761         frame[1] = 0x03;                 /* Three parameters */
00762         irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
00763         irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST");
00764         if (status)
00765                 irlan_insert_string_param(skb, "FILTER_MODE", "FILTER"); 
00766         else
00767                 irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); 
00768 
00769         irlan_ctrl_data_request(self, skb);
00770 }
00771 
00772 /*
00773  * Function irlan_set_multicast_filter (self, status)
00774  *
00775  *    Make IrLAN provider accept ethernet frames addressed to the multicast
00776  *    address. 
00777  *
00778  */
00779 void irlan_set_multicast_filter(struct irlan_cb *self, int status) 
00780 {
00781         struct sk_buff *skb;
00782         __u8 *frame;
00783         
00784         IRDA_DEBUG(2, __FUNCTION__ "()\n");
00785 
00786         ASSERT(self != NULL, return;);
00787         ASSERT(self->magic == IRLAN_MAGIC, return;);
00788 
00789         skb = dev_alloc_skb(128);
00790         if (!skb)
00791                 return;
00792         
00793         /* Reserve space for TTP, LMP, and LAP header */
00794         skb_reserve(skb, self->client.max_header_size);
00795         skb_put(skb, 2);
00796         
00797         frame = skb->data;
00798         
00799         frame[0] = CMD_FILTER_OPERATION;
00800         frame[1] = 0x03;                 /* Three parameters */
00801         irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
00802         irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST");
00803         if (status)
00804                 irlan_insert_string_param(skb, "FILTER_MODE", "ALL"); 
00805         else
00806                 irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); 
00807 
00808         irlan_ctrl_data_request(self, skb);
00809 }
00810 
00811 /*
00812  * Function irlan_get_unicast_addr (self)
00813  *
00814  *    Retrives the unicast address from the IrLAN provider. This address
00815  *    will be inserted into the devices structure, so the ethernet layer
00816  *    can construct its packets.
00817  *
00818  */
00819 void irlan_get_unicast_addr(struct irlan_cb *self) 
00820 {
00821         struct sk_buff *skb;
00822         __u8 *frame;
00823                 
00824         IRDA_DEBUG(2, __FUNCTION__ "()\n");
00825 
00826         ASSERT(self != NULL, return;);
00827         ASSERT(self->magic == IRLAN_MAGIC, return;);
00828         
00829         skb = dev_alloc_skb(128);
00830         if (!skb)
00831                 return;
00832 
00833         /* Reserve space for TTP, LMP, and LAP header */
00834         skb_reserve(skb, self->client.max_header_size);
00835         skb_put(skb, 2);
00836         
00837         frame = skb->data;
00838         
00839         frame[0] = CMD_FILTER_OPERATION;
00840         frame[1] = 0x03;                 /* Three parameters */
00841         irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
00842         irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
00843         irlan_insert_string_param(skb, "FILTER_OPERATION", "DYNAMIC"); 
00844         
00845         irlan_ctrl_data_request(self, skb);
00846 }
00847 
00848 /*
00849  * Function irlan_get_media_char (self)
00850  *
00851  *    
00852  *
00853  */
00854 void irlan_get_media_char(struct irlan_cb *self) 
00855 {
00856         struct sk_buff *skb;
00857         __u8 *frame;
00858         
00859         IRDA_DEBUG(4, __FUNCTION__ "()\n");
00860 
00861         ASSERT(self != NULL, return;);
00862         ASSERT(self->magic == IRLAN_MAGIC, return;);
00863         
00864         skb = dev_alloc_skb(64);
00865         if (!skb)
00866                 return;
00867 
00868         /* Reserve space for TTP, LMP, and LAP header */
00869         skb_reserve(skb, self->client.max_header_size);
00870         skb_put(skb, 2);
00871         
00872         frame = skb->data;
00873         
00874         /* Build frame */
00875         frame[0] = CMD_GET_MEDIA_CHAR;
00876         frame[1] = 0x01; /* One parameter */
00877         
00878         irlan_insert_string_param(skb, "MEDIA", "802.3");
00879         
00880         irlan_ctrl_data_request(self, skb);
00881 }
00882 
00883 /*
00884  * Function insert_byte_param (skb, param, value)
00885  *
00886  *    Insert byte parameter into frame
00887  *
00888  */
00889 int irlan_insert_byte_param(struct sk_buff *skb, char *param, __u8 value)
00890 {
00891         return __irlan_insert_param(skb, param, IRLAN_BYTE, value, 0, NULL, 0);
00892 }
00893 
00894 int irlan_insert_short_param(struct sk_buff *skb, char *param, __u16 value)
00895 {
00896         return __irlan_insert_param(skb, param, IRLAN_SHORT, 0, value, NULL, 0);
00897 }
00898 
00899 /*
00900  * Function insert_string (skb, param, value)
00901  *
00902  *    Insert string parameter into frame
00903  *
00904  */
00905 int irlan_insert_string_param(struct sk_buff *skb, char *param, char *string)
00906 {
00907         int string_len = strlen(string);
00908 
00909         return __irlan_insert_param(skb, param, IRLAN_ARRAY, 0, 0, string, 
00910                                     string_len);
00911 }
00912 
00913 /*
00914  * Function insert_array_param(skb, param, value, len_value)
00915  *
00916  *    Insert array parameter into frame
00917  *
00918  */
00919 int irlan_insert_array_param(struct sk_buff *skb, char *name, __u8 *array,
00920                              __u16 array_len)
00921 {
00922         return __irlan_insert_param(skb, name, IRLAN_ARRAY, 0, 0, array, 
00923                                     array_len);
00924 }
00925 
00926 /*
00927  * Function insert_param (skb, param, value, byte)
00928  *
00929  *    Insert parameter at end of buffer, structure of a parameter is:
00930  *
00931  *    -----------------------------------------------------------------------
00932  *    | Name Length[1] | Param Name[1..255] | Val Length[2] | Value[0..1016]|
00933  *    -----------------------------------------------------------------------
00934  */
00935 static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, 
00936                                 __u8 value_byte, __u16 value_short, 
00937                                 __u8 *value_array, __u16 value_len)
00938 {
00939         __u8 *frame;
00940         __u8 param_len;
00941         __u16 tmp_le; /* Temporary value in little endian format */
00942         int n=0;
00943         
00944         if (skb == NULL) {
00945                 IRDA_DEBUG(2, __FUNCTION__ "(), Got NULL skb\n");
00946                 return 0;
00947         }       
00948 
00949         param_len = strlen(param);
00950         switch (type) {
00951         case IRLAN_BYTE:
00952                 value_len = 1;
00953                 break;
00954         case IRLAN_SHORT:
00955                 value_len = 2;
00956                 break;
00957         case IRLAN_ARRAY:
00958                 ASSERT(value_array != NULL, return 0;);
00959                 ASSERT(value_len > 0, return 0;);
00960                 break;
00961         default:
00962                 IRDA_DEBUG(2, __FUNCTION__ "(), Unknown parameter type!\n");
00963                 return 0;
00964                 break;
00965         }
00966         
00967         /* Insert at end of sk-buffer */
00968         frame = skb->tail;
00969 
00970         /* Make space for data */
00971         if (skb_tailroom(skb) < (param_len+value_len+3)) {
00972                 IRDA_DEBUG(2, __FUNCTION__ "(), No more space at end of skb\n");
00973                 return 0;
00974         }       
00975         skb_put(skb, param_len+value_len+3);
00976         
00977         /* Insert parameter length */
00978         frame[n++] = param_len;
00979         
00980         /* Insert parameter */
00981         memcpy(frame+n, param, param_len); n += param_len;
00982         
00983         /* Insert value length (2 byte little endian format, LSB first) */
00984         tmp_le = cpu_to_le16(value_len);
00985         memcpy(frame+n, &tmp_le, 2); n += 2; /* To avoid alignment problems */
00986 
00987         /* Insert value */
00988         switch (type) {
00989         case IRLAN_BYTE:
00990                 frame[n++] = value_byte;
00991                 break;
00992         case IRLAN_SHORT:
00993                 tmp_le = cpu_to_le16(value_short);
00994                 memcpy(frame+n, &tmp_le, 2); n += 2;
00995                 break;
00996         case IRLAN_ARRAY:
00997                 memcpy(frame+n, value_array, value_len); n+=value_len;
00998                 break;
00999         default:
01000                 break;
01001         }
01002         ASSERT(n == (param_len+value_len+3), return 0;);
01003 
01004         return param_len+value_len+3;
01005 }
01006 
01007 /*
01008  * Function irlan_extract_param (buf, name, value, len)
01009  *
01010  *    Extracts a single parameter name/value pair from buffer and updates
01011  *    the buffer pointer to point to the next name/value pair. 
01012  */
01013 int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len)
01014 {
01015         __u8 name_len;
01016         __u16 val_len;
01017         int n=0;
01018         
01019         IRDA_DEBUG(4, __FUNCTION__ "()\n");
01020         
01021         /* get length of parameter name (1 byte) */
01022         name_len = buf[n++];
01023         
01024         if (name_len > 254) {
01025                 IRDA_DEBUG(2, __FUNCTION__ "(), name_len > 254\n");
01026                 return -RSP_INVALID_COMMAND_FORMAT;
01027         }
01028         
01029         /* get parameter name */
01030         memcpy(name, buf+n, name_len);
01031         name[name_len] = '\0';
01032         n+=name_len;
01033         
01034         /*  
01035          *  Get length of parameter value (2 bytes in little endian 
01036          *  format) 
01037          */
01038         memcpy(&val_len, buf+n, 2); /* To avoid alignment problems */
01039         le16_to_cpus(&val_len); n+=2;
01040         
01041         if (val_len > 1016) {
01042                 IRDA_DEBUG(2, __FUNCTION__ "(), parameter length to long\n");
01043                 return -RSP_INVALID_COMMAND_FORMAT;
01044         }
01045         *len = val_len;
01046 
01047         /* get parameter value */
01048         memcpy(value, buf+n, val_len);
01049         value[val_len] = '\0';
01050         n+=val_len;
01051         
01052         IRDA_DEBUG(4, "Parameter: %s ", name); 
01053         IRDA_DEBUG(4, "Value: %s\n", value); 
01054 
01055         return n;
01056 }
01057 
01058 #ifdef CONFIG_PROC_FS
01059 /*
01060  * Function irlan_client_proc_read (buf, start, offset, len, unused)
01061  *
01062  *    Give some info to the /proc file system
01063  */
01064 static int irlan_proc_read(char *buf, char **start, off_t offset, int len, 
01065                            int unused)
01066 {
01067         struct irlan_cb *self;
01068         unsigned long flags;
01069      
01070         save_flags(flags);
01071         cli();
01072 
01073         ASSERT(irlan != NULL, return 0;);
01074         
01075         len = 0;
01076         
01077         len += sprintf(buf+len, "IrLAN instances:\n");
01078         
01079         self = (struct irlan_cb *) hashbin_get_first(irlan);
01080         while (self != NULL) {
01081                 ASSERT(self->magic == IRLAN_MAGIC, return len;);
01082                 
01083                 len += sprintf(buf+len, "ifname: %s,\n",
01084                                self->ifname);
01085                 len += sprintf(buf+len, "client state: %s, ",
01086                                irlan_state[ self->client.state]);
01087                 len += sprintf(buf+len, "provider state: %s,\n",
01088                                irlan_state[ self->provider.state]);
01089                 len += sprintf(buf+len, "saddr: %#08x, ",
01090                                self->saddr);
01091                 len += sprintf(buf+len, "daddr: %#08x\n",
01092                                self->daddr);
01093                 len += sprintf(buf+len, "version: %d.%d,\n",
01094                                self->version[1], self->version[0]);
01095                 len += sprintf(buf+len, "access type: %s\n", 
01096                                irlan_access[self->client.access_type]);
01097                 len += sprintf(buf+len, "media: %s\n", 
01098                                irlan_media[self->media]);
01099                 
01100                 len += sprintf(buf+len, "local filter:\n");
01101                 len += sprintf(buf+len, "remote filter: ");
01102                 len += irlan_print_filter(self->client.filter_type, 
01103                                           buf+len);
01104                 
01105                 len += sprintf(buf+len, "client tx busy: %s\n", 
01106                                self->client.tx_busy ? "TRUE" : "FALSE");
01107                 
01108                 len += sprintf(buf+len, "dev tx busy: %s\n", 
01109                                self->dev.tbusy ? "TRUE" : "FALSE");
01110                 
01111                 len += sprintf(buf+len, "\n");
01112 
01113                 self = (struct irlan_cb *) hashbin_get_next(irlan);
01114         } 
01115         restore_flags(flags);
01116 
01117         return len;
01118 }
01119 #endif
01120 
01121 /*
01122  * Function print_ret_code (code)
01123  *
01124  *    Print return code of request to peer IrLAN layer.
01125  *
01126  */
01127 void print_ret_code(__u8 code) 
01128 {
01129         switch(code) {
01130         case 0:
01131                 printk(KERN_INFO "Success\n");
01132                 break;
01133         case 1:
01134                 WARNING("IrLAN: Insufficient resources\n");
01135                 break;
01136         case 2:
01137                 WARNING("IrLAN: Invalid command format\n");
01138                 break;
01139         case 3:
01140                 WARNING("IrLAN: Command not supported\n");
01141                 break;
01142         case 4:
01143                 WARNING("IrLAN: Parameter not supported\n");
01144                 break;
01145         case 5:
01146                 WARNING("IrLAN: Value not supported\n");
01147                 break;
01148         case 6:
01149                 WARNING("IrLAN: Not open\n");
01150                 break;
01151         case 7:
01152                 WARNING("IrLAN: Authentication required\n");
01153                 break;
01154         case 8:
01155                 WARNING("IrLAN: Invalid password\n");
01156                 break;
01157         case 9:
01158                 WARNING("IrLAN: Protocol error\n");
01159                 break;
01160         case 255:
01161                 WARNING("IrLAN: Asynchronous status\n");
01162                 break;
01163         }
01164 }
01165 
01166 void irlan_mod_inc_use_count(void)
01167 {
01168 #ifdef MODULE
01169         MOD_INC_USE_COUNT;
01170 #endif
01171 }
01172 
01173 void irlan_mod_dec_use_count(void)
01174 {
01175 #ifdef MODULE
01176         MOD_DEC_USE_COUNT;
01177 #endif
01178 }
01179 
01180 #ifdef MODULE
01181 
01182 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
01183 MODULE_DESCRIPTION("The Linux IrDA LAN protocol"); 
01184 
01185 MODULE_PARM(eth, "i");
01186 MODULE_PARM(access, "i");
01187 MODULE_PARM(timeout, "i");
01188 
01189 /*
01190  * Function init_module (void)
01191  *
01192  *    Initialize the IrLAN module, this function is called by the
01193  *    modprobe(1) program.
01194  */
01195 int init_module(void) 
01196 {
01197         return irlan_init();
01198 }
01199 
01200 /*
01201  * Function cleanup_module (void)
01202  *
01203  *    Remove the IrLAN module, this function is called by the rmmod(1)
01204  *    program
01205  */
01206 void cleanup_module(void) 
01207 {
01208         /* Free some memory */
01209         irlan_cleanup();
01210 }
01211 
01212 #endif /* MODULE */
01213