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