Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/irda/ircomm/ircomm_lmp.c
15111 views
1
/*********************************************************************
2
*
3
* Filename: ircomm_lmp.c
4
* Version: 1.0
5
* Description: Interface between IrCOMM and IrLMP
6
* Status: Stable
7
* Author: Dag Brattli <[email protected]>
8
* Created at: Sun Jun 6 20:48:27 1999
9
* Modified at: Sun Dec 12 13:44:17 1999
10
* Modified by: Dag Brattli <[email protected]>
11
* Sources: Previous IrLPT work by Thomas Davis
12
*
13
* Copyright (c) 1999 Dag Brattli, All Rights Reserved.
14
* Copyright (c) 2000-2003 Jean Tourrilhes <[email protected]>
15
*
16
* This program is free software; you can redistribute it and/or
17
* modify it under the terms of the GNU General Public License as
18
* published by the Free Software Foundation; either version 2 of
19
* the License, or (at your option) any later version.
20
*
21
* This program is distributed in the hope that it will be useful,
22
* but WITHOUT ANY WARRANTY; without even the implied warranty of
23
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
* GNU General Public License for more details.
25
*
26
* You should have received a copy of the GNU General Public License
27
* along with this program; if not, write to the Free Software
28
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
29
* MA 02111-1307 USA
30
*
31
********************************************************************/
32
33
#include <linux/init.h>
34
#include <linux/gfp.h>
35
36
#include <net/irda/irda.h>
37
#include <net/irda/irlmp.h>
38
#include <net/irda/iriap.h>
39
#include <net/irda/irda_device.h> /* struct irda_skb_cb */
40
41
#include <net/irda/ircomm_event.h>
42
#include <net/irda/ircomm_lmp.h>
43
44
45
/*
46
* Function ircomm_lmp_connect_request (self, userdata)
47
*
48
*
49
*
50
*/
51
static int ircomm_lmp_connect_request(struct ircomm_cb *self,
52
struct sk_buff *userdata,
53
struct ircomm_info *info)
54
{
55
int ret = 0;
56
57
IRDA_DEBUG(0, "%s()\n", __func__ );
58
59
/* Don't forget to refcount it - should be NULL anyway */
60
if(userdata)
61
skb_get(userdata);
62
63
ret = irlmp_connect_request(self->lsap, info->dlsap_sel,
64
info->saddr, info->daddr, NULL, userdata);
65
return ret;
66
}
67
68
/*
69
* Function ircomm_lmp_connect_response (self, skb)
70
*
71
*
72
*
73
*/
74
static int ircomm_lmp_connect_response(struct ircomm_cb *self,
75
struct sk_buff *userdata)
76
{
77
struct sk_buff *tx_skb;
78
79
IRDA_DEBUG(0, "%s()\n", __func__ );
80
81
/* Any userdata supplied? */
82
if (userdata == NULL) {
83
tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
84
if (!tx_skb)
85
return -ENOMEM;
86
87
/* Reserve space for MUX and LAP header */
88
skb_reserve(tx_skb, LMP_MAX_HEADER);
89
} else {
90
/*
91
* Check that the client has reserved enough space for
92
* headers
93
*/
94
IRDA_ASSERT(skb_headroom(userdata) >= LMP_MAX_HEADER,
95
return -1;);
96
97
/* Don't forget to refcount it - should be NULL anyway */
98
skb_get(userdata);
99
tx_skb = userdata;
100
}
101
102
return irlmp_connect_response(self->lsap, tx_skb);
103
}
104
105
static int ircomm_lmp_disconnect_request(struct ircomm_cb *self,
106
struct sk_buff *userdata,
107
struct ircomm_info *info)
108
{
109
struct sk_buff *tx_skb;
110
int ret;
111
112
IRDA_DEBUG(0, "%s()\n", __func__ );
113
114
if (!userdata) {
115
tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
116
if (!tx_skb)
117
return -ENOMEM;
118
119
/* Reserve space for MUX and LAP header */
120
skb_reserve(tx_skb, LMP_MAX_HEADER);
121
userdata = tx_skb;
122
} else {
123
/* Don't forget to refcount it - should be NULL anyway */
124
skb_get(userdata);
125
}
126
127
ret = irlmp_disconnect_request(self->lsap, userdata);
128
129
return ret;
130
}
131
132
/*
133
* Function ircomm_lmp_flow_control (skb)
134
*
135
* This function is called when a data frame we have sent to IrLAP has
136
* been deallocated. We do this to make sure we don't flood IrLAP with
137
* frames, since we are not using the IrTTP flow control mechanism
138
*/
139
static void ircomm_lmp_flow_control(struct sk_buff *skb)
140
{
141
struct irda_skb_cb *cb;
142
struct ircomm_cb *self;
143
int line;
144
145
IRDA_ASSERT(skb != NULL, return;);
146
147
cb = (struct irda_skb_cb *) skb->cb;
148
149
IRDA_DEBUG(2, "%s()\n", __func__ );
150
151
line = cb->line;
152
153
self = (struct ircomm_cb *) hashbin_lock_find(ircomm, line, NULL);
154
if (!self) {
155
IRDA_DEBUG(2, "%s(), didn't find myself\n", __func__ );
156
return;
157
}
158
159
IRDA_ASSERT(self != NULL, return;);
160
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
161
162
self->pkt_count--;
163
164
if ((self->pkt_count < 2) && (self->flow_status == FLOW_STOP)) {
165
IRDA_DEBUG(2, "%s(), asking TTY to start again!\n", __func__ );
166
self->flow_status = FLOW_START;
167
if (self->notify.flow_indication)
168
self->notify.flow_indication(self->notify.instance,
169
self, FLOW_START);
170
}
171
}
172
173
/*
174
* Function ircomm_lmp_data_request (self, userdata)
175
*
176
* Send data frame to peer device
177
*
178
*/
179
static int ircomm_lmp_data_request(struct ircomm_cb *self,
180
struct sk_buff *skb,
181
int not_used)
182
{
183
struct irda_skb_cb *cb;
184
int ret;
185
186
IRDA_ASSERT(skb != NULL, return -1;);
187
188
cb = (struct irda_skb_cb *) skb->cb;
189
190
cb->line = self->line;
191
192
IRDA_DEBUG(4, "%s(), sending frame\n", __func__ );
193
194
/* Don't forget to refcount it - see ircomm_tty_do_softint() */
195
skb_get(skb);
196
197
skb_orphan(skb);
198
skb->destructor = ircomm_lmp_flow_control;
199
200
if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) {
201
IRDA_DEBUG(2, "%s(), asking TTY to slow down!\n", __func__ );
202
self->flow_status = FLOW_STOP;
203
if (self->notify.flow_indication)
204
self->notify.flow_indication(self->notify.instance,
205
self, FLOW_STOP);
206
}
207
ret = irlmp_data_request(self->lsap, skb);
208
if (ret) {
209
IRDA_ERROR("%s(), failed\n", __func__);
210
/* irlmp_data_request already free the packet */
211
}
212
213
return ret;
214
}
215
216
/*
217
* Function ircomm_lmp_data_indication (instance, sap, skb)
218
*
219
* Incoming data which we must deliver to the state machine, to check
220
* we are still connected.
221
*/
222
static int ircomm_lmp_data_indication(void *instance, void *sap,
223
struct sk_buff *skb)
224
{
225
struct ircomm_cb *self = (struct ircomm_cb *) instance;
226
227
IRDA_DEBUG(4, "%s()\n", __func__ );
228
229
IRDA_ASSERT(self != NULL, return -1;);
230
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
231
IRDA_ASSERT(skb != NULL, return -1;);
232
233
ircomm_do_event(self, IRCOMM_LMP_DATA_INDICATION, skb, NULL);
234
235
/* Drop reference count - see ircomm_tty_data_indication(). */
236
dev_kfree_skb(skb);
237
238
return 0;
239
}
240
241
/*
242
* Function ircomm_lmp_connect_confirm (instance, sap, qos, max_sdu_size,
243
* max_header_size, skb)
244
*
245
* Connection has been confirmed by peer device
246
*
247
*/
248
static void ircomm_lmp_connect_confirm(void *instance, void *sap,
249
struct qos_info *qos,
250
__u32 max_seg_size,
251
__u8 max_header_size,
252
struct sk_buff *skb)
253
{
254
struct ircomm_cb *self = (struct ircomm_cb *) instance;
255
struct ircomm_info info;
256
257
IRDA_DEBUG(0, "%s()\n", __func__ );
258
259
IRDA_ASSERT(self != NULL, return;);
260
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
261
IRDA_ASSERT(skb != NULL, return;);
262
IRDA_ASSERT(qos != NULL, return;);
263
264
info.max_data_size = max_seg_size;
265
info.max_header_size = max_header_size;
266
info.qos = qos;
267
268
ircomm_do_event(self, IRCOMM_LMP_CONNECT_CONFIRM, skb, &info);
269
270
/* Drop reference count - see ircomm_tty_connect_confirm(). */
271
dev_kfree_skb(skb);
272
}
273
274
/*
275
* Function ircomm_lmp_connect_indication (instance, sap, qos, max_sdu_size,
276
* max_header_size, skb)
277
*
278
* Peer device wants to make a connection with us
279
*
280
*/
281
static void ircomm_lmp_connect_indication(void *instance, void *sap,
282
struct qos_info *qos,
283
__u32 max_seg_size,
284
__u8 max_header_size,
285
struct sk_buff *skb)
286
{
287
struct ircomm_cb *self = (struct ircomm_cb *)instance;
288
struct ircomm_info info;
289
290
IRDA_DEBUG(0, "%s()\n", __func__ );
291
292
IRDA_ASSERT(self != NULL, return;);
293
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
294
IRDA_ASSERT(skb != NULL, return;);
295
IRDA_ASSERT(qos != NULL, return;);
296
297
info.max_data_size = max_seg_size;
298
info.max_header_size = max_header_size;
299
info.qos = qos;
300
301
ircomm_do_event(self, IRCOMM_LMP_CONNECT_INDICATION, skb, &info);
302
303
/* Drop reference count - see ircomm_tty_connect_indication(). */
304
dev_kfree_skb(skb);
305
}
306
307
/*
308
* Function ircomm_lmp_disconnect_indication (instance, sap, reason, skb)
309
*
310
* Peer device has closed the connection, or the link went down for some
311
* other reason
312
*/
313
static void ircomm_lmp_disconnect_indication(void *instance, void *sap,
314
LM_REASON reason,
315
struct sk_buff *skb)
316
{
317
struct ircomm_cb *self = (struct ircomm_cb *) instance;
318
struct ircomm_info info;
319
320
IRDA_DEBUG(0, "%s()\n", __func__ );
321
322
IRDA_ASSERT(self != NULL, return;);
323
IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
324
325
info.reason = reason;
326
327
ircomm_do_event(self, IRCOMM_LMP_DISCONNECT_INDICATION, skb, &info);
328
329
/* Drop reference count - see ircomm_tty_disconnect_indication(). */
330
if(skb)
331
dev_kfree_skb(skb);
332
}
333
/*
334
* Function ircomm_open_lsap (self)
335
*
336
* Open LSAP. This function will only be used when using "raw" services
337
*
338
*/
339
int ircomm_open_lsap(struct ircomm_cb *self)
340
{
341
notify_t notify;
342
343
IRDA_DEBUG(0, "%s()\n", __func__ );
344
345
/* Register callbacks */
346
irda_notify_init(&notify);
347
notify.data_indication = ircomm_lmp_data_indication;
348
notify.connect_confirm = ircomm_lmp_connect_confirm;
349
notify.connect_indication = ircomm_lmp_connect_indication;
350
notify.disconnect_indication = ircomm_lmp_disconnect_indication;
351
notify.instance = self;
352
strlcpy(notify.name, "IrCOMM", sizeof(notify.name));
353
354
self->lsap = irlmp_open_lsap(LSAP_ANY, &notify, 0);
355
if (!self->lsap) {
356
IRDA_DEBUG(0,"%sfailed to allocate tsap\n", __func__ );
357
return -1;
358
}
359
self->slsap_sel = self->lsap->slsap_sel;
360
361
/*
362
* Initialize the call-table for issuing commands
363
*/
364
self->issue.data_request = ircomm_lmp_data_request;
365
self->issue.connect_request = ircomm_lmp_connect_request;
366
self->issue.connect_response = ircomm_lmp_connect_response;
367
self->issue.disconnect_request = ircomm_lmp_disconnect_request;
368
369
return 0;
370
}
371
372