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

ircomm_core.c

Go to the documentation of this file.
00001 /*********************************************************************
00002  *                
00003  * Filename:      ircomm_core.c
00004  * Version:       1.0
00005  * Description:   IrCOMM service interface
00006  * Status:        Experimental.
00007  * Author:        Dag Brattli <dagb@cs.uit.no>
00008  * Created at:    Sun Jun  6 20:37:34 1999
00009  * Modified at:   Tue Dec 21 13:26:41 1999
00010  * Modified by:   Dag Brattli <dagb@cs.uit.no>
00011  * 
00012  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
00013  *     
00014  *     This program is free software; you can redistribute it and/or 
00015  *     modify it under the terms of the GNU General Public License as 
00016  *     published by the Free Software Foundation; either version 2 of 
00017  *     the License, or (at your option) any later version.
00018  * 
00019  *     This program is distributed in the hope that it will be useful,
00020  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00022  *     GNU General Public License for more details.
00023  * 
00024  *     You should have received a copy of the GNU General Public License 
00025  *     along with this program; if not, write to the Free Software 
00026  *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
00027  *     MA 02111-1307 USA
00028  *     
00029  ********************************************************************/
00030 
00031 #include <linux/config.h>
00032 #include <linux/module.h>
00033 #include <linux/sched.h>
00034 #include <linux/proc_fs.h>
00035 #include <linux/init.h>
00036 
00037 #include <net/irda/irda.h>
00038 #include <net/irda/irmod.h>
00039 #include <net/irda/irlmp.h>
00040 #include <net/irda/iriap.h>
00041 #include <net/irda/irttp.h>
00042 #include <net/irda/irias_object.h>
00043 
00044 #include <net/irda/ircomm_event.h>
00045 #include <net/irda/ircomm_lmp.h>
00046 #include <net/irda/ircomm_ttp.h>
00047 #include <net/irda/ircomm_param.h>
00048 #include <net/irda/ircomm_core.h>
00049 
00050 static int __ircomm_close(struct ircomm_cb *self);
00051 static void ircomm_control_indication(struct ircomm_cb *self, 
00052                                       struct sk_buff *skb, int clen);
00053 
00054 #ifdef CONFIG_PROC_FS
00055 static int ircomm_proc_read(char *buf, char **start, off_t offset, int len, 
00056                             int unused);
00057 
00058 extern struct proc_dir_entry *proc_irda;
00059 #endif /* CONFIG_PROC_FS */
00060 
00061 hashbin_t *ircomm = NULL;
00062 
00063 int __init ircomm_init(void)
00064 {
00065         ircomm = hashbin_new(HB_LOCAL); 
00066         if (ircomm == NULL) {
00067                 ERROR(__FUNCTION__ "(), can't allocate hashbin!\n");
00068                 return -ENOMEM;
00069         }
00070         
00071 #ifdef CONFIG_PROC_FS
00072         create_proc_entry("ircomm", 0, proc_irda)->get_info = ircomm_proc_read;
00073 #endif /* CONFIG_PROC_FS */
00074         
00075         MESSAGE("IrCOMM protocol (Dag Brattli)\n");
00076                 
00077         return 0;
00078 }
00079 
00080 #ifdef MODULE
00081 void ircomm_cleanup(void)
00082 {
00083         IRDA_DEBUG(2, __FUNCTION__ "()\n");
00084 
00085         hashbin_delete(ircomm, (FREE_FUNC) __ircomm_close);
00086 
00087 #ifdef CONFIG_PROC_FS
00088         remove_proc_entry("ircomm", proc_irda);
00089 #endif /* CONFIG_PROC_FS */
00090 }
00091 #endif /* MODULE */
00092 
00093 /*
00094  * Function ircomm_open (client_notify)
00095  *
00096  *    Start a new IrCOMM instance
00097  *
00098  */
00099 struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line)
00100 {
00101         struct ircomm_cb *self = NULL;
00102         int ret;
00103 
00104         IRDA_DEBUG(2, __FUNCTION__ "(), service_type=0x%02x\n",
00105                    service_type);
00106 
00107         ASSERT(ircomm != NULL, return NULL;);
00108 
00109         self = kmalloc(sizeof(struct ircomm_cb), GFP_ATOMIC);
00110         if (self == NULL)
00111                 return NULL;
00112 
00113         memset(self, 0, sizeof(struct ircomm_cb));
00114 
00115         self->notify = *notify;
00116         self->magic = IRCOMM_MAGIC;
00117 
00118         /* Check if we should use IrLMP or IrTTP */
00119         if (service_type & IRCOMM_3_WIRE_RAW) {
00120                 self->flow_status = FLOW_START;
00121                 ret = ircomm_open_lsap(self);
00122         } else
00123                 ret = ircomm_open_tsap(self);
00124 
00125         if (ret < 0)
00126                 return NULL;
00127 
00128         self->service_type = service_type;
00129         self->line = line;
00130 
00131         hashbin_insert(ircomm, (queue_t *) self, line, NULL);
00132 
00133         ircomm_next_state(self, IRCOMM_IDLE);   
00134 
00135         return self;
00136 }
00137 
00138 /*
00139  * Function ircomm_close_instance (self)
00140  *
00141  *    Remove IrCOMM instance
00142  *
00143  */
00144 static int __ircomm_close(struct ircomm_cb *self)
00145 {
00146         IRDA_DEBUG(2, __FUNCTION__"()\n");
00147 
00148         /* Disconnect link if any */
00149         ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL, NULL);
00150 
00151         /* Remove TSAP */
00152         if (self->tsap) {
00153                 irttp_close_tsap(self->tsap);
00154                 self->tsap = NULL;
00155         }
00156 
00157         /* Remove LSAP */
00158         if (self->lsap) {
00159                 irlmp_close_lsap(self->lsap);
00160                 self->lsap = NULL;
00161         }
00162         self->magic = 0;
00163 
00164         kfree(self);
00165 
00166         return 0;
00167 }
00168 
00169 /*
00170  * Function ircomm_close (self)
00171  *
00172  *    Closes and removes the specified IrCOMM instance
00173  *
00174  */
00175 int ircomm_close(struct ircomm_cb *self)
00176 {
00177         struct ircomm_cb *entry;
00178 
00179         ASSERT(self != NULL, return -EIO;);
00180         ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;);
00181 
00182         IRDA_DEBUG(0, __FUNCTION__ "()\n");
00183 
00184         entry = hashbin_remove(ircomm, self->line, NULL);
00185 
00186         ASSERT(entry == self, return -1;);
00187         
00188         return __ircomm_close(self);
00189 }
00190 
00191 /*
00192  * Function ircomm_connect_request (self, service_type)
00193  *
00194  *    Impl. of this function is differ from one of the reference. This
00195  *    function does discovery as well as sending connect request
00196  * 
00197  */
00198 int ircomm_connect_request(struct ircomm_cb *self, __u8 dlsap_sel, 
00199                            __u32 saddr, __u32 daddr, struct sk_buff *skb,
00200                            __u8 service_type)
00201 {
00202         struct ircomm_info info;
00203         int ret;
00204 
00205         IRDA_DEBUG(2 , __FUNCTION__"()\n");
00206 
00207         ASSERT(self != NULL, return -1;);
00208         ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
00209 
00210         self->service_type= service_type;
00211 
00212         info.dlsap_sel = dlsap_sel;
00213         info.saddr = saddr;
00214         info.daddr = daddr;
00215 
00216         ret = ircomm_do_event(self, IRCOMM_CONNECT_REQUEST, skb, &info);
00217 
00218         return ret;
00219 }
00220 
00221 /*
00222  * Function ircomm_connect_indication (self, qos, skb)
00223  *
00224  *    Notify user layer about the incomming connection
00225  *
00226  */
00227 void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb,
00228                                struct ircomm_info *info)
00229 {
00230         int clen = 0;
00231         
00232         IRDA_DEBUG(2, __FUNCTION__ "()\n");
00233 
00234         /* Check if the packet contains data on the control channel */
00235         if (skb->len > 0)
00236                 clen = skb->data[0];
00237         
00238         /* 
00239          * If there are any data hiding in the control channel, we must 
00240          * deliver it first. The side effect is that the control channel 
00241          * will be removed from the skb
00242          */
00243         if (self->notify.connect_indication)
00244                 self->notify.connect_indication(self->notify.instance, self, 
00245                                                 info->qos, info->max_data_size,
00246                                                 info->max_header_size, skb);
00247         else {
00248                 IRDA_DEBUG(0, __FUNCTION__ "(), missing handler\n");
00249                 dev_kfree_skb(skb);
00250         }
00251 }
00252 
00253 /*
00254  * Function ircomm_connect_response (self, userdata, max_sdu_size)
00255  *
00256  *    User accepts connection
00257  *
00258  */
00259 int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata)
00260 {
00261         int ret;
00262 
00263         ASSERT(self != NULL, return -1;);
00264         ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
00265 
00266         IRDA_DEBUG(4, __FUNCTION__ "()\n");
00267 
00268         ret = ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata, NULL);
00269 
00270         return ret;
00271 }       
00272 
00273 /*
00274  * Function connect_confirm (self, skb)
00275  *
00276  *    Notify user layer that the link is now connected
00277  *
00278  */
00279 void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb,
00280                             struct ircomm_info *info)
00281 {
00282         IRDA_DEBUG(4, __FUNCTION__"()\n");
00283 
00284         if (self->notify.connect_confirm )
00285                 self->notify.connect_confirm(self->notify.instance,
00286                                              self, info->qos, 
00287                                              info->max_data_size,
00288                                              info->max_header_size, skb);
00289         else {
00290                 IRDA_DEBUG(0, __FUNCTION__ "(), missing handler\n");
00291                 dev_kfree_skb(skb);
00292         }
00293 }
00294 
00295 /*
00296  * Function ircomm_data_request (self, userdata)
00297  *
00298  *    Send IrCOMM data to peer device
00299  *
00300  */
00301 int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb)
00302 {
00303         int ret;
00304 
00305         IRDA_DEBUG(4, __FUNCTION__"()\n");
00306 
00307         ASSERT(self != NULL, return -EFAULT;);
00308         ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
00309         ASSERT(skb != NULL, return -EFAULT;);
00310         
00311         ret = ircomm_do_event(self, IRCOMM_DATA_REQUEST, skb, NULL);
00312 
00313         return ret;
00314 }
00315 
00316 /*
00317  * Function ircomm_data_indication (self, skb)
00318  *
00319  *    Data arrived, so deliver it to user
00320  *
00321  */
00322 void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb)
00323 {       
00324         IRDA_DEBUG(4, __FUNCTION__"()\n");
00325 
00326         ASSERT(skb->len > 0, return;);
00327 
00328         if (self->notify.data_indication)
00329                 self->notify.data_indication(self->notify.instance, self, skb);
00330         else {
00331                 IRDA_DEBUG(0, __FUNCTION__ "(), missing handler\n");
00332                 dev_kfree_skb(skb);
00333         }
00334 }
00335 
00336 /*
00337  * Function ircomm_process_data (self, skb)
00338  *
00339  *    Data arrived which may contain control channel data
00340  *
00341  */
00342 void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb)
00343 {
00344         int clen;
00345 
00346         ASSERT(skb->len > 0, return;);
00347 
00348         clen = skb->data[0];
00349 
00350         /* 
00351          * If there are any data hiding in the control channel, we must 
00352          * deliver it first. The side effect is that the control channel 
00353          * will be removed from the skb
00354          */
00355         if (clen > 0)
00356                 ircomm_control_indication(self, skb, clen);
00357 
00358         /* Remove control channel from data channel */
00359         skb_pull(skb, clen+1);
00360 
00361         if (skb->len)
00362                 ircomm_data_indication(self, skb);              
00363         else {
00364                 IRDA_DEBUG(4, __FUNCTION__ 
00365                            "(), data was control info only!\n");
00366                 dev_kfree_skb(skb);
00367         }
00368 }
00369 
00370 /*
00371  * Function ircomm_control_request (self, params)
00372  *
00373  *    Send control data to peer device
00374  *
00375  */
00376 int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb)
00377 {
00378         int ret;
00379         
00380         IRDA_DEBUG(2, __FUNCTION__"()\n");
00381 
00382         ASSERT(self != NULL, return -EFAULT;);
00383         ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
00384         ASSERT(skb != NULL, return -EFAULT;);
00385         
00386         ret = ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb, NULL);
00387 
00388         return ret;
00389 }
00390 
00391 /*
00392  * Function ircomm_control_indication (self, skb)
00393  *
00394  *    Data has arrived on the control channel
00395  *
00396  */
00397 static void ircomm_control_indication(struct ircomm_cb *self, 
00398                                       struct sk_buff *skb, int clen)
00399 {
00400         struct sk_buff *ctrl_skb;
00401 
00402         IRDA_DEBUG(2, __FUNCTION__"()\n");      
00403 
00404         ctrl_skb = skb_clone(skb, GFP_ATOMIC);
00405         if (!ctrl_skb)
00406                 return;
00407 
00408         /* Remove data channel from control channel */
00409         skb_trim(ctrl_skb, clen+1);
00410         
00411         /* Use udata for delivering data on the control channel */
00412         if (self->notify.udata_indication)
00413                 self->notify.udata_indication(self->notify.instance, self, 
00414                                               ctrl_skb);
00415         else {
00416                 IRDA_DEBUG(0, __FUNCTION__ "(), missing handler\n");
00417                 dev_kfree_skb(skb);
00418         }
00419 }
00420 
00421 /*
00422  * Function ircomm_disconnect_request (self, userdata, priority)
00423  *
00424  *    User layer wants to disconnect the IrCOMM connection
00425  *
00426  */
00427 int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata)
00428 {
00429         struct ircomm_info info;
00430         int ret;
00431 
00432         IRDA_DEBUG(2, __FUNCTION__"()\n");
00433 
00434         ASSERT(self != NULL, return -1;);
00435         ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
00436 
00437         ret = ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, userdata, 
00438                               &info);
00439         return ret;
00440 }
00441 
00442 /*
00443  * Function disconnect_indication (self, skb)
00444  *
00445  *    Tell user that the link has been disconnected
00446  *
00447  */
00448 void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
00449                                   struct ircomm_info *info)
00450 {
00451         IRDA_DEBUG(2, __FUNCTION__ "()\n");
00452        
00453         ASSERT(info != NULL, return;);
00454 
00455         if (self->notify.disconnect_indication) {
00456                 self->notify.disconnect_indication(self->notify.instance, self,
00457                                                    info->reason, skb);
00458         } else {
00459                 IRDA_DEBUG(0, __FUNCTION__ "(), missing handler\n");
00460                 dev_kfree_skb(skb);
00461         }
00462 }
00463 
00464 /*
00465  * Function ircomm_flow_request (self, flow)
00466  *
00467  *    
00468  *
00469  */
00470 void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow)
00471 {
00472         IRDA_DEBUG(2, __FUNCTION__ "()\n");
00473 
00474         ASSERT(self != NULL, return;);
00475         ASSERT(self->magic == IRCOMM_MAGIC, return;);
00476 
00477         if (self->service_type == IRCOMM_3_WIRE_RAW)
00478                 return;
00479 
00480         irttp_flow_request(self->tsap, flow);
00481 }
00482 
00483 #ifdef CONFIG_PROC_FS
00484 /*
00485  * Function ircomm_proc_read (buf, start, offset, len, unused)
00486  *
00487  *    
00488  *
00489  */
00490 int ircomm_proc_read(char *buf, char **start, off_t offset, int len, 
00491                      int unused)
00492 {       
00493         struct ircomm_cb *self;
00494         unsigned long flags;
00495         int i=0;
00496         
00497         save_flags(flags);
00498         cli();
00499 
00500         len = 0;
00501 
00502         len += sprintf(buf+len, "Instance %d:\n", i++);
00503 
00504         self = (struct ircomm_cb *) hashbin_get_first(ircomm);
00505         while (self != NULL) {
00506                 ASSERT(self->magic == IRCOMM_MAGIC, return len;);
00507 
00508                 self = (struct ircomm_cb *) hashbin_get_next(ircomm);
00509         } 
00510         restore_flags(flags);
00511 
00512         return len;
00513 }
00514 #endif /* CONFIG_PROC_FS */
00515 
00516 #ifdef MODULE
00517 int init_module(void) 
00518 {
00519         return ircomm_init();
00520 }
00521         
00522 void cleanup_module(void)
00523 {
00524         ircomm_cleanup();
00525 }
00526 #endif /* MODULE */
00527