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/init.h>
33 
34 #include <net/irda/irda.h>
35 #include <net/irda/irlmp.h>
36 #include <net/irda/iriap.h>
37 #include <net/irda/irttp.h>
38 
39 #include <net/irda/ircomm_event.h>
40 #include <net/irda/ircomm_ttp.h>
41 
42 static int ircomm_ttp_data_indication(void *instance, void *sap,
43 				      struct sk_buff *skb);
44 static void ircomm_ttp_connect_confirm(void *instance, void *sap,
45 				       struct qos_info *qos,
46 				       __u32 max_sdu_size,
47 				       __u8 max_header_size,
48 				       struct sk_buff *skb);
49 static void ircomm_ttp_connect_indication(void *instance, void *sap,
50 					  struct qos_info *qos,
51 					  __u32 max_sdu_size,
52 					  __u8 max_header_size,
53 					  struct sk_buff *skb);
54 static void ircomm_ttp_flow_indication(void *instance, void *sap,
55 				       LOCAL_FLOW cmd);
56 static void ircomm_ttp_disconnect_indication(void *instance, void *sap,
57 					     LM_REASON reason,
58 					     struct sk_buff *skb);
59 static int ircomm_ttp_data_request(struct ircomm_cb *self,
60 				   struct sk_buff *skb,
61 				   int clen);
62 static int ircomm_ttp_connect_request(struct ircomm_cb *self,
63 				      struct sk_buff *userdata,
64 				      struct ircomm_info *info);
65 static int ircomm_ttp_connect_response(struct ircomm_cb *self,
66 				       struct sk_buff *userdata);
67 static int ircomm_ttp_disconnect_request(struct ircomm_cb *self,
68 					 struct sk_buff *userdata,
69 					 struct ircomm_info *info);
70 
71 /*
72  * Function ircomm_open_tsap (self)
73  *
74  *
75  *
76  */
ircomm_open_tsap(struct ircomm_cb * self)77 int ircomm_open_tsap(struct ircomm_cb *self)
78 {
79 	notify_t notify;
80 
81 	IRDA_DEBUG(4, "%s()\n", __func__ );
82 
83 	/* Register callbacks */
84 	irda_notify_init(&notify);
85 	notify.data_indication       = ircomm_ttp_data_indication;
86 	notify.connect_confirm       = ircomm_ttp_connect_confirm;
87 	notify.connect_indication    = ircomm_ttp_connect_indication;
88 	notify.flow_indication       = ircomm_ttp_flow_indication;
89 	notify.disconnect_indication = ircomm_ttp_disconnect_indication;
90 	notify.instance = self;
91 	strlcpy(notify.name, "IrCOMM", sizeof(notify.name));
92 
93 	self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
94 				     &notify);
95 	if (!self->tsap) {
96 		IRDA_DEBUG(0, "%sfailed to allocate tsap\n", __func__ );
97 		return -1;
98 	}
99 	self->slsap_sel = self->tsap->stsap_sel;
100 
101 	/*
102 	 *  Initialize the call-table for issuing commands
103 	 */
104 	self->issue.data_request       = ircomm_ttp_data_request;
105 	self->issue.connect_request    = ircomm_ttp_connect_request;
106 	self->issue.connect_response   = ircomm_ttp_connect_response;
107 	self->issue.disconnect_request = ircomm_ttp_disconnect_request;
108 
109 	return 0;
110 }
111 
112 /*
113  * Function ircomm_ttp_connect_request (self, userdata)
114  *
115  *
116  *
117  */
ircomm_ttp_connect_request(struct ircomm_cb * self,struct sk_buff * userdata,struct ircomm_info * info)118 static int ircomm_ttp_connect_request(struct ircomm_cb *self,
119 				      struct sk_buff *userdata,
120 				      struct ircomm_info *info)
121 {
122 	int ret = 0;
123 
124 	IRDA_DEBUG(4, "%s()\n", __func__ );
125 
126 	/* Don't forget to refcount it - should be NULL anyway */
127 	if(userdata)
128 		skb_get(userdata);
129 
130 	ret = irttp_connect_request(self->tsap, info->dlsap_sel,
131 				    info->saddr, info->daddr, NULL,
132 				    TTP_SAR_DISABLE, userdata);
133 
134 	return ret;
135 }
136 
137 /*
138  * Function ircomm_ttp_connect_response (self, skb)
139  *
140  *
141  *
142  */
ircomm_ttp_connect_response(struct ircomm_cb * self,struct sk_buff * userdata)143 static int ircomm_ttp_connect_response(struct ircomm_cb *self,
144 				       struct sk_buff *userdata)
145 {
146 	int ret;
147 
148 	IRDA_DEBUG(4, "%s()\n", __func__ );
149 
150 	/* Don't forget to refcount it - should be NULL anyway */
151 	if(userdata)
152 		skb_get(userdata);
153 
154 	ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, userdata);
155 
156 	return ret;
157 }
158 
159 /*
160  * Function ircomm_ttp_data_request (self, userdata)
161  *
162  *    Send IrCOMM data to IrTTP layer. Currently we do not try to combine
163  *    control data with pure data, so they will be sent as separate frames.
164  *    Should not be a big problem though, since control frames are rare. But
165  *    some of them are sent after connection establishment, so this can
166  *    increase the latency a bit.
167  */
ircomm_ttp_data_request(struct ircomm_cb * self,struct sk_buff * skb,int clen)168 static int ircomm_ttp_data_request(struct ircomm_cb *self,
169 				   struct sk_buff *skb,
170 				   int clen)
171 {
172 	int ret;
173 
174 	IRDA_ASSERT(skb != NULL, return -1;);
175 
176 	IRDA_DEBUG(2, "%s(), clen=%d\n", __func__ , clen);
177 
178 	/*
179 	 * Insert clen field, currently we either send data only, or control
180 	 * only frames, to make things easier and avoid queueing
181 	 */
182 	IRDA_ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;);
183 
184 	/* Don't forget to refcount it - see ircomm_tty_do_softint() */
185 	skb_get(skb);
186 
187 	skb_push(skb, IRCOMM_HEADER_SIZE);
188 
189 	skb->data[0] = clen;
190 
191 	ret = irttp_data_request(self->tsap, skb);
192 	if (ret) {
193 		IRDA_ERROR("%s(), failed\n", __func__);
194 		/* irttp_data_request already free the packet */
195 	}
196 
197 	return ret;
198 }
199 
200 /*
201  * Function ircomm_ttp_data_indication (instance, sap, skb)
202  *
203  *    Incoming data
204  *
205  */
ircomm_ttp_data_indication(void * instance,void * sap,struct sk_buff * skb)206 static int ircomm_ttp_data_indication(void *instance, void *sap,
207 				      struct sk_buff *skb)
208 {
209 	struct ircomm_cb *self = (struct ircomm_cb *) instance;
210 
211 	IRDA_DEBUG(4, "%s()\n", __func__ );
212 
213 	IRDA_ASSERT(self != NULL, return -1;);
214 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
215 	IRDA_ASSERT(skb != NULL, return -1;);
216 
217 	ircomm_do_event(self, IRCOMM_TTP_DATA_INDICATION, skb, NULL);
218 
219 	/* Drop reference count - see ircomm_tty_data_indication(). */
220 	dev_kfree_skb(skb);
221 
222 	return 0;
223 }
224 
ircomm_ttp_connect_confirm(void * instance,void * sap,struct qos_info * qos,__u32 max_sdu_size,__u8 max_header_size,struct sk_buff * skb)225 static void ircomm_ttp_connect_confirm(void *instance, void *sap,
226 				       struct qos_info *qos,
227 				       __u32 max_sdu_size,
228 				       __u8 max_header_size,
229 				       struct sk_buff *skb)
230 {
231 	struct ircomm_cb *self = (struct ircomm_cb *) instance;
232 	struct ircomm_info info;
233 
234 	IRDA_DEBUG(4, "%s()\n", __func__ );
235 
236 	IRDA_ASSERT(self != NULL, return;);
237 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
238 	IRDA_ASSERT(skb != NULL, return;);
239 	IRDA_ASSERT(qos != NULL, goto out;);
240 
241 	if (max_sdu_size != TTP_SAR_DISABLE) {
242 		IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n",
243 			   __func__);
244 		goto out;
245 	}
246 
247 	info.max_data_size = irttp_get_max_seg_size(self->tsap)
248 		- IRCOMM_HEADER_SIZE;
249 	info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
250 	info.qos = qos;
251 
252 	ircomm_do_event(self, IRCOMM_TTP_CONNECT_CONFIRM, skb, &info);
253 
254 out:
255 	/* Drop reference count - see ircomm_tty_connect_confirm(). */
256 	dev_kfree_skb(skb);
257 }
258 
259 /*
260  * Function ircomm_ttp_connect_indication (instance, sap, qos, max_sdu_size,
261  *                                         max_header_size, skb)
262  *
263  *
264  *
265  */
ircomm_ttp_connect_indication(void * instance,void * sap,struct qos_info * qos,__u32 max_sdu_size,__u8 max_header_size,struct sk_buff * skb)266 static void ircomm_ttp_connect_indication(void *instance, void *sap,
267 					  struct qos_info *qos,
268 					  __u32 max_sdu_size,
269 					  __u8 max_header_size,
270 					  struct sk_buff *skb)
271 {
272 	struct ircomm_cb *self = (struct ircomm_cb *)instance;
273 	struct ircomm_info info;
274 
275 	IRDA_DEBUG(4, "%s()\n", __func__ );
276 
277 	IRDA_ASSERT(self != NULL, return;);
278 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
279 	IRDA_ASSERT(skb != NULL, return;);
280 	IRDA_ASSERT(qos != NULL, goto out;);
281 
282 	if (max_sdu_size != TTP_SAR_DISABLE) {
283 		IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n",
284 			   __func__);
285 		goto out;
286 	}
287 
288 	info.max_data_size = irttp_get_max_seg_size(self->tsap)
289 		- IRCOMM_HEADER_SIZE;
290 	info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE;
291 	info.qos = qos;
292 
293 	ircomm_do_event(self, IRCOMM_TTP_CONNECT_INDICATION, skb, &info);
294 
295 out:
296 	/* Drop reference count - see ircomm_tty_connect_indication(). */
297 	dev_kfree_skb(skb);
298 }
299 
300 /*
301  * Function ircomm_ttp_disconnect_request (self, userdata, info)
302  *
303  *
304  *
305  */
ircomm_ttp_disconnect_request(struct ircomm_cb * self,struct sk_buff * userdata,struct ircomm_info * info)306 static int ircomm_ttp_disconnect_request(struct ircomm_cb *self,
307 					 struct sk_buff *userdata,
308 					 struct ircomm_info *info)
309 {
310 	int ret;
311 
312 	/* Don't forget to refcount it - should be NULL anyway */
313 	if(userdata)
314 		skb_get(userdata);
315 
316 	ret = irttp_disconnect_request(self->tsap, userdata, P_NORMAL);
317 
318 	return ret;
319 }
320 
321 /*
322  * Function ircomm_ttp_disconnect_indication (instance, sap, reason, skb)
323  *
324  *
325  *
326  */
ircomm_ttp_disconnect_indication(void * instance,void * sap,LM_REASON reason,struct sk_buff * skb)327 static void ircomm_ttp_disconnect_indication(void *instance, void *sap,
328 					     LM_REASON reason,
329 					     struct sk_buff *skb)
330 {
331 	struct ircomm_cb *self = (struct ircomm_cb *) instance;
332 	struct ircomm_info info;
333 
334 	IRDA_DEBUG(2, "%s()\n", __func__ );
335 
336 	IRDA_ASSERT(self != NULL, return;);
337 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
338 
339 	info.reason = reason;
340 
341 	ircomm_do_event(self, IRCOMM_TTP_DISCONNECT_INDICATION, skb, &info);
342 
343 	/* Drop reference count - see ircomm_tty_disconnect_indication(). */
344 	if(skb)
345 		dev_kfree_skb(skb);
346 }
347 
348 /*
349  * Function ircomm_ttp_flow_indication (instance, sap, cmd)
350  *
351  *    Layer below is telling us to start or stop the flow of data
352  *
353  */
ircomm_ttp_flow_indication(void * instance,void * sap,LOCAL_FLOW cmd)354 static void ircomm_ttp_flow_indication(void *instance, void *sap,
355 				       LOCAL_FLOW cmd)
356 {
357 	struct ircomm_cb *self = (struct ircomm_cb *) instance;
358 
359 	IRDA_DEBUG(4, "%s()\n", __func__ );
360 
361 	IRDA_ASSERT(self != NULL, return;);
362 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
363 
364 	if (self->notify.flow_indication)
365 		self->notify.flow_indication(self->notify.instance, self, cmd);
366 }
367 
368 
369