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

ircomm_lmp.c

Go to the documentation of this file.
00001 /*********************************************************************
00002  *                
00003  * Filename:      ircomm_lmp.c
00004  * Version:       1.0
00005  * Description:   Interface between IrCOMM and IrLMP
00006  * Status:        Stable
00007  * Author:        Dag Brattli <dagb@cs.uit.no>
00008  * Created at:    Sun Jun  6 20:48:27 1999
00009  * Modified at:   Sun Dec 12 13:44:17 1999
00010  * Modified by:   Dag Brattli <dagb@cs.uit.no>
00011  * Sources:       Previous IrLPT work by Thomas Davis
00012  * 
00013  *     Copyright (c) 1999 Dag Brattli, 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  *     This program is distributed in the hope that it will be useful,
00021  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00023  *     GNU General Public License for more details.
00024  * 
00025  *     You should have received a copy of the GNU General Public License 
00026  *     along with this program; if not, write to the Free Software 
00027  *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
00028  *     MA 02111-1307 USA
00029  *     
00030  ********************************************************************/
00031 
00032 #include <linux/sched.h>
00033 #include <linux/init.h>
00034 
00035 #include <net/irda/irda.h>
00036 #include <net/irda/irlmp.h>
00037 #include <net/irda/iriap.h>
00038 
00039 #include <net/irda/ircomm_event.h>
00040 #include <net/irda/ircomm_lmp.h>
00041 
00042 /*
00043  * Function ircomm_open_lsap (self)
00044  *
00045  *    Open LSAP. This function will only be used when using "raw" services
00046  *
00047  */
00048 int ircomm_open_lsap(struct ircomm_cb *self)
00049 {
00050         notify_t notify;
00051         
00052         IRDA_DEBUG(0, __FUNCTION__ "()\n");
00053         
00054         /* Register callbacks */
00055         irda_notify_init(&notify);
00056         notify.data_indication       = ircomm_lmp_data_indication;
00057         notify.connect_confirm       = ircomm_lmp_connect_confirm;
00058         notify.connect_indication    = ircomm_lmp_connect_indication;
00059         notify.disconnect_indication = ircomm_lmp_disconnect_indication;
00060         notify.instance = self;
00061         strncpy(notify.name, "IrCOMM", NOTIFY_MAX_NAME);
00062 
00063         self->lsap = irlmp_open_lsap(LSAP_ANY, &notify, 0);
00064         if (!self->lsap) {
00065                 IRDA_DEBUG(0,__FUNCTION__"failed to allocate tsap\n");
00066                 return -1;
00067         }
00068         self->slsap_sel = self->lsap->slsap_sel;
00069 
00070         /*
00071          *  Initialize the call-table for issuing commands
00072          */
00073         self->issue.data_request       = ircomm_lmp_data_request;
00074         self->issue.connect_request    = ircomm_lmp_connect_request;
00075         self->issue.connect_response   = ircomm_lmp_connect_response;
00076         self->issue.disconnect_request = ircomm_lmp_disconnect_request;
00077 
00078         return 0;
00079 }
00080 
00081 /*
00082  * Function ircomm_lmp_connect_request (self, userdata)
00083  *
00084  *    
00085  *
00086  */
00087 int ircomm_lmp_connect_request(struct ircomm_cb *self, 
00088                                struct sk_buff *userdata, 
00089                                struct ircomm_info *info)
00090 {
00091         int ret = 0;
00092 
00093         IRDA_DEBUG(0, __FUNCTION__ "()\n");
00094 
00095         ret = irlmp_connect_request(self->lsap, info->dlsap_sel,
00096                                     info->saddr, info->daddr, NULL, userdata); 
00097         return ret;
00098 }       
00099 
00100 /*
00101  * Function ircomm_lmp_connect_response (self, skb)
00102  *
00103  *    
00104  *
00105  */
00106 int ircomm_lmp_connect_response(struct ircomm_cb *self, struct sk_buff *skb)
00107 {
00108         int ret;
00109 
00110         IRDA_DEBUG(0, __FUNCTION__"()\n");
00111         
00112         ret = irlmp_connect_response(self->lsap, skb);
00113 
00114         return 0;
00115 }
00116 
00117 int ircomm_lmp_disconnect_request(struct ircomm_cb *self, 
00118                                   struct sk_buff *userdata, 
00119                                   struct ircomm_info *info)
00120 {
00121         struct sk_buff *skb;
00122         int ret;
00123 
00124         IRDA_DEBUG(0, __FUNCTION__ "()\n");
00125 
00126         if (!userdata) {
00127                 skb = dev_alloc_skb(64);
00128                 if (!skb)
00129                         return -ENOMEM;
00130                 
00131                 /*  Reserve space for MUX and LAP header */
00132                 skb_reserve(skb, LMP_MAX_HEADER);               
00133                 userdata = skb;
00134         }
00135         ret = irlmp_disconnect_request(self->lsap, userdata);
00136 
00137         return ret;
00138 }
00139 
00140 /*
00141  * Function ircomm_lmp_flow_control (skb)
00142  *
00143  *    This function is called when a data frame we have sent to IrLAP has
00144  *    been deallocated. We do this to make sure we don't flood IrLAP with 
00145  *    frames, since we are not using the IrTTP flow control mechanism
00146  */
00147 void ircomm_lmp_flow_control(struct sk_buff *skb)
00148 {
00149         struct irda_skb_cb *cb;
00150         struct ircomm_cb *self;
00151         int line;
00152 
00153         ASSERT(skb != NULL, return;);
00154 
00155         cb = (struct irda_skb_cb *) skb->cb;
00156 
00157         IRDA_DEBUG(2, __FUNCTION__ "()\n");
00158  
00159         line = cb->line;
00160 
00161         self = (struct ircomm_cb *) hashbin_find(ircomm, line, NULL);
00162         if (!self) {
00163                 IRDA_DEBUG(2, __FUNCTION__ "(), didn't find myself\n");
00164                 return;
00165         }
00166 
00167         ASSERT(self != NULL, return;);
00168         ASSERT(self->magic == IRCOMM_MAGIC, return;);
00169 
00170         self->pkt_count--;
00171 
00172         if ((self->pkt_count < 2) && (self->flow_status == FLOW_STOP)) {
00173                 IRDA_DEBUG(2, __FUNCTION__ "(), asking TTY to start again!\n");
00174                 self->flow_status = FLOW_START;
00175                 if (self->notify.flow_indication)
00176                         self->notify.flow_indication(self->notify.instance, 
00177                                                      self, FLOW_START);
00178         }
00179 }
00180     
00181 /*
00182  * Function ircomm_lmp_data_request (self, userdata)
00183  *
00184  *    Send data frame to peer device
00185  *
00186  */
00187 int ircomm_lmp_data_request(struct ircomm_cb *self, struct sk_buff *skb, 
00188                             int not_used)
00189 {
00190         struct irda_skb_cb *cb;
00191         int ret;
00192 
00193         ASSERT(skb != NULL, return -1;);
00194 
00195         cb = (struct irda_skb_cb *) skb->cb;
00196         
00197         cb->line = self->line;
00198 
00199         IRDA_DEBUG(4, __FUNCTION__"(), sending frame\n");
00200 
00201         skb->destructor = ircomm_lmp_flow_control;
00202         
00203         if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) {
00204                 IRDA_DEBUG(2, __FUNCTION__ "(), asking TTY to slow down!\n");
00205                 self->flow_status = FLOW_STOP;
00206                 if (self->notify.flow_indication)
00207                         self->notify.flow_indication(self->notify.instance, 
00208                                                      self, FLOW_STOP);
00209         }
00210         ret = irlmp_data_request(self->lsap, skb);
00211         if (ret) {
00212                 ERROR(__FUNCTION__ "(), failed\n");
00213                 dev_kfree_skb(skb);
00214         }
00215 
00216         return ret;
00217 }
00218 
00219 /*
00220  * Function ircomm_lmp_data_indication (instance, sap, skb)
00221  *
00222  *    Incomming data which we must deliver to the state machine, to check
00223  *    we are still connected.
00224  */
00225 int ircomm_lmp_data_indication(void *instance, void *sap,
00226                                struct sk_buff *skb)
00227 {
00228         struct ircomm_cb *self = (struct ircomm_cb *) instance;
00229 
00230         IRDA_DEBUG(4, __FUNCTION__"()\n");
00231         
00232         ASSERT(self != NULL, return -1;);
00233         ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
00234         ASSERT(skb != NULL, return -1;);
00235         
00236         ircomm_do_event(self, IRCOMM_LMP_DATA_INDICATION, skb, NULL);
00237 
00238         return 0;
00239 }
00240 
00241 /*
00242  * Function ircomm_lmp_connect_confirm (instance, sap, qos, max_sdu_size, 
00243  *                                       max_header_size, skb)
00244  *
00245  *    Connection has been confirmed by peer device
00246  *
00247  */
00248 void ircomm_lmp_connect_confirm(void *instance, void *sap,
00249                                 struct qos_info *qos, 
00250                                 __u32 max_seg_size, 
00251                                 __u8 max_header_size,
00252                                 struct sk_buff *skb)
00253 {
00254         struct ircomm_cb *self = (struct ircomm_cb *) instance;
00255         struct ircomm_info info;
00256 
00257         IRDA_DEBUG(0, __FUNCTION__"()\n");
00258 
00259         ASSERT(self != NULL, return;);
00260         ASSERT(self->magic == IRCOMM_MAGIC, return;);
00261         ASSERT(skb != NULL, return;);
00262         ASSERT(qos != NULL, return;);
00263 
00264         info.max_data_size = max_seg_size;
00265         info.max_header_size = max_header_size;
00266         info.qos = qos;
00267 
00268         ircomm_do_event(self, IRCOMM_LMP_CONNECT_CONFIRM, skb, &info);
00269 }
00270 
00271 /*
00272  * Function ircomm_lmp_connect_indication (instance, sap, qos, max_sdu_size,
00273  *                                         max_header_size, skb)
00274  *
00275  *    Peer device wants to make a connection with us
00276  *
00277  */
00278 void ircomm_lmp_connect_indication(void *instance, void *sap,
00279                                    struct qos_info *qos,
00280                                    __u32 max_seg_size,
00281                                    __u8 max_header_size,
00282                                    struct sk_buff *skb)
00283 {
00284         struct ircomm_cb *self = (struct ircomm_cb *)instance;
00285         struct ircomm_info info;
00286 
00287         IRDA_DEBUG(0, __FUNCTION__"()\n");
00288 
00289         ASSERT(self != NULL, return;);
00290         ASSERT(self->magic == IRCOMM_MAGIC, return;);
00291         ASSERT(skb != NULL, return;);
00292         ASSERT(qos != NULL, return;);
00293 
00294         info.max_data_size = max_seg_size;
00295         info.max_header_size = max_header_size;
00296         info.qos = qos;
00297 
00298         ircomm_do_event(self, IRCOMM_LMP_CONNECT_INDICATION, skb, &info);
00299 }
00300 
00301 /*
00302  * Function ircomm_lmp_disconnect_indication (instance, sap, reason, skb)
00303  *
00304  *    Peer device has closed the connection, or the link went down for some
00305  *    other reason
00306  */
00307 void ircomm_lmp_disconnect_indication(void *instance, void *sap, 
00308                                       LM_REASON reason,
00309                                       struct sk_buff *skb)
00310 {
00311         struct ircomm_cb *self = (struct ircomm_cb *) instance;
00312         struct ircomm_info info;
00313 
00314         IRDA_DEBUG(0, __FUNCTION__"()\n");
00315 
00316         ASSERT(self != NULL, return;);
00317         ASSERT(self->magic == IRCOMM_MAGIC, return;);
00318 
00319         info.reason = reason;
00320 
00321         ircomm_do_event(self, IRCOMM_LMP_DISCONNECT_INDICATION, skb, &info);
00322 }