ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / net / irda / ircomm / ircomm_ttp.c
1 /*********************************************************************
2  *                
3  * Filename:      ircomm_ttp.c
4  * Version:       1.0
5  * Description:   Interface between IrCOMM and IrTTP
6  * Status:        Stable
7  * Author:        Dag Brattli <dagb@cs.uit.no>
8  * Created at:    Sun Jun  6 20:48:27 1999
9  * Modified at:   Mon Dec 13 11:35:13 1999
10  * Modified by:   Dag Brattli <dagb@cs.uit.no>
11  * 
12  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
13  *     Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.com>
14  *     
15  *     This program is free software; you can redistribute it and/or 
16  *     modify it under the terms of the GNU General Public License as 
17  *     published by the Free Software Foundation; either version 2 of 
18  *     the License, or (at your option) any later version.
19  * 
20  *     This program is distributed in the hope that it will be useful,
21  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
22  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  *     GNU General Public License for more details.
24  * 
25  *     You should have received a copy of the GNU General Public License 
26  *     along with this program; if not, write to the Free Software 
27  *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
28  *     MA 02111-1307 USA
29  *     
30  ********************************************************************/
31
32 #include <linux/sched.h>
33 #include <linux/init.h>
34
35 #include <net/irda/irda.h>
36 #include <net/irda/irlmp.h>
37 #include <net/irda/iriap.h>
38 #include <net/irda/irttp.h>
39
40 #include <net/irda/ircomm_event.h>
41 #include <net/irda/ircomm_ttp.h>
42
43 /*
44  * Function ircomm_open_tsap (self)
45  *
46  *    
47  *
48  */
49 int ircomm_open_tsap(struct ircomm_cb *self)
50 {
51         notify_t notify;
52
53         IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
54
55         /* Register callbacks */
56         irda_notify_init(&notify);
57         notify.data_indication       = ircomm_ttp_data_indication;
58         notify.connect_confirm       = ircomm_ttp_connect_confirm;
59         notify.connect_indication    = ircomm_ttp_connect_indication;
60         notify.flow_indication       = ircomm_ttp_flow_indication;
61         notify.disconnect_indication = ircomm_ttp_disconnect_indication;
62         notify.instance = self;
63         strlcpy(notify.name, "IrCOMM", sizeof(notify.name));
64
65         self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
66                                      &notify);
67         if (!self->tsap) {
68                 IRDA_DEBUG(0, "%sfailed to allocate tsap\n", __FUNCTION__ );
69                 return -1;
70         }
71         self->slsap_sel = self->tsap->stsap_sel;
72
73         /*
74          *  Initialize the call-table for issuing commands
75          */
76         self->issue.data_request       = ircomm_ttp_data_request;
77         self->issue.connect_request    = ircomm_ttp_connect_request;
78         self->issue.connect_response   = ircomm_ttp_connect_response;
79         self->issue.disconnect_request = ircomm_ttp_disconnect_request;
80
81         return 0;
82 }
83
84 /*
85  * Function ircomm_ttp_connect_request (self, userdata)
86  *
87  *    
88  *
89  */
90 int ircomm_ttp_connect_request(struct ircomm_cb *self, 
91                                struct sk_buff *userdata, 
92                                struct ircomm_info *info)
93 {
94         int ret = 0;
95
96         IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
97
98         /* Don't forget to refcount it - should be NULL anyway */
99         if(userdata)
100                 skb_get(userdata);
101
102         ret = irttp_connect_request(self->tsap, info->dlsap_sel,
103                                     info->saddr, info->daddr, NULL, 
104                                     TTP_SAR_DISABLE, userdata); 
105
106         return ret;
107 }       
108
109 /*
110  * Function ircomm_ttp_connect_response (self, skb)
111  *
112  *    
113  *
114  */
115 int ircomm_ttp_connect_response(struct ircomm_cb *self,
116                                 struct sk_buff *userdata)
117 {
118         int ret;
119
120         IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
121         
122         /* Don't forget to refcount it - should be NULL anyway */
123         if(userdata)
124                 skb_get(userdata);
125
126         ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, userdata);
127
128         return ret;
129 }
130
131 /*
132  * Function ircomm_ttp_data_request (self, userdata)
133  *
134  *    Send IrCOMM data to IrTTP layer. Currently we do not try to combine 
135  *    control data with pure data, so they will be sent as separate frames. 
136  *    Should not be a big problem though, since control frames are rare. But
137  *    some of them are sent after connection establishment, so this can 
138  *    increase the latency a bit.
139  */
140 int ircomm_ttp_data_request(struct ircomm_cb *self,
141                             struct sk_buff *skb, 
142                             int clen)
143 {
144         int ret;
145
146         ASSERT(skb != NULL, return -1;);
147
148         IRDA_DEBUG(2, "%s(), clen=%d\n", __FUNCTION__ , clen);
149
150         /* 
151          * Insert clen field, currently we either send data only, or control
152          * only frames, to make things easier and avoid queueing
153          */
154         ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;);
155
156         /* Don't forget to refcount it - see ircomm_tty_do_softint() */
157         skb_get(skb);
158
159         skb_push(skb, IRCOMM_HEADER_SIZE);
160
161         skb->data[0] = clen;
162
163         ret = irttp_data_request(self->tsap, skb);
164         if (ret) {
165                 ERROR("%s(), failed\n", __FUNCTION__);
166                 /* irttp_data_request already free the packet */
167         }
168
169         return ret;
170 }
171
172 /*
173  * Function ircomm_ttp_data_indication (instance, sap, skb)
174  *
175  *    Incoming data
176  *
177  */
178 int ircomm_ttp_data_indication(void *instance, void *sap,
179                                struct sk_buff *skb)
180 {
181         struct ircomm_cb *self = (struct ircomm_cb *) instance;
182
183         IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
184         
185         ASSERT(self != NULL, return -1;);
186         ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
187         ASSERT(skb != NULL, return -1;);
188
189         ircomm_do_event(self, IRCOMM_TTP_DATA_INDICATION, skb, NULL);
190
191         /* Drop reference count - see ircomm_tty_data_indication(). */
192         dev_kfree_skb(skb);
193
194         return 0;
195 }
196
197 void ircomm_ttp_connect_confirm(void *instance, void *sap,
198                                 struct qos_info *qos, 
199                                 __u32 max_sdu_size, 
200                                 __u8 max_header_size,
201                                 struct sk_buff *skb)
202 {
203         struct ircomm_cb *self = (struct ircomm_cb *) instance;
204         struct ircomm_info info;
205
206         IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
207
208         ASSERT(self != NULL, return;);
209         ASSERT(self->magic == IRCOMM_MAGIC, return;);
210         ASSERT(skb != NULL, return;);
211         ASSERT(qos != NULL, goto out;);
212
213         if (max_sdu_size != TTP_SAR_DISABLE) {
214                 ERROR("%s(), SAR not allowed for IrCOMM!\n", __FUNCTION__);
215                 goto out;
216         }
217
218         info.max_data_size = irttp_get_max_seg_size(self->tsap)
219                 - IRCOMM_HEADER_SIZE;
220         info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
221         info.qos = qos;
222
223         ircomm_do_event(self, IRCOMM_TTP_CONNECT_CONFIRM, skb, &info);
224
225 out:
226         /* Drop reference count - see ircomm_tty_connect_confirm(). */
227         dev_kfree_skb(skb);
228 }
229
230 /*
231  * Function ircomm_ttp_connect_indication (instance, sap, qos, max_sdu_size,
232  *                                         max_header_size, skb)
233  *
234  *    
235  *
236  */
237 void ircomm_ttp_connect_indication(void *instance, void *sap,
238                                    struct qos_info *qos,
239                                    __u32 max_sdu_size,
240                                    __u8 max_header_size,
241                                    struct sk_buff *skb)
242 {
243         struct ircomm_cb *self = (struct ircomm_cb *)instance;
244         struct ircomm_info info;
245
246         IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
247
248         ASSERT(self != NULL, return;);
249         ASSERT(self->magic == IRCOMM_MAGIC, return;);
250         ASSERT(skb != NULL, return;);
251         ASSERT(qos != NULL, goto out;);
252
253         if (max_sdu_size != TTP_SAR_DISABLE) {
254                 ERROR("%s(), SAR not allowed for IrCOMM!\n", __FUNCTION__);
255                 goto out;
256         }
257
258         info.max_data_size = irttp_get_max_seg_size(self->tsap)
259                 - IRCOMM_HEADER_SIZE;
260         info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
261         info.qos = qos;
262
263         ircomm_do_event(self, IRCOMM_TTP_CONNECT_INDICATION, skb, &info);
264
265 out:
266         /* Drop reference count - see ircomm_tty_connect_indication(). */
267         dev_kfree_skb(skb);
268 }
269
270 /*
271  * Function ircomm_ttp_disconnect_request (self, userdata, info)
272  *
273  *    
274  *
275  */
276 int ircomm_ttp_disconnect_request(struct ircomm_cb *self, 
277                                   struct sk_buff *userdata, 
278                                   struct ircomm_info *info)
279 {
280         int ret;
281
282         /* Don't forget to refcount it - should be NULL anyway */
283         if(userdata)
284                 skb_get(userdata);
285
286         ret = irttp_disconnect_request(self->tsap, userdata, P_NORMAL);
287
288         return ret;
289 }
290
291 /*
292  * Function ircomm_ttp_disconnect_indication (instance, sap, reason, skb)
293  *
294  *    
295  *
296  */
297 void ircomm_ttp_disconnect_indication(void *instance, void *sap, 
298                                       LM_REASON reason,
299                                       struct sk_buff *skb)
300 {
301         struct ircomm_cb *self = (struct ircomm_cb *) instance;
302         struct ircomm_info info;
303
304         IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
305
306         ASSERT(self != NULL, return;);
307         ASSERT(self->magic == IRCOMM_MAGIC, return;);
308
309         info.reason = reason;
310
311         ircomm_do_event(self, IRCOMM_TTP_DISCONNECT_INDICATION, skb, &info);
312
313         /* Drop reference count - see ircomm_tty_disconnect_indication(). */
314         if(skb)
315                 dev_kfree_skb(skb);
316 }
317
318 /*
319  * Function ircomm_ttp_flow_indication (instance, sap, cmd)
320  *
321  *    Layer below is telling us to start or stop the flow of data
322  *
323  */
324 void ircomm_ttp_flow_indication(void *instance, void *sap, LOCAL_FLOW cmd)
325 {
326         struct ircomm_cb *self = (struct ircomm_cb *) instance;
327
328         IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
329
330         ASSERT(self != NULL, return;);
331         ASSERT(self->magic == IRCOMM_MAGIC, return;);
332         
333         if (self->notify.flow_indication)
334                 self->notify.flow_indication(self->notify.instance, self, cmd);
335 }
336
337