This source file includes following definitions.
- l2cap_init
- l2cap_setmode
- l2cap_request_alloc
- l2cap_request_lookup
- l2cap_request_free
- l2cap_rtx
- l2cap_cid_alloc
- l2cap_cid_lookup
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 #include <sys/cdefs.h>
35
36 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/mbuf.h>
39 #include <sys/proc.h>
40 #include <sys/queue.h>
41 #include <sys/systm.h>
42
43 #include <netbt/bluetooth.h>
44 #include <netbt/hci.h>
45 #include <netbt/l2cap.h>
46
47 struct l2cap_channel_list
48 l2cap_active_list = LIST_HEAD_INITIALIZER(l2cap_active_list);
49 struct l2cap_channel_list
50 l2cap_listen_list = LIST_HEAD_INITIALIZER(l2cap_listen_list);
51
52 struct pool l2cap_req_pool;
53 struct pool l2cap_pdu_pool;
54
55 const l2cap_qos_t l2cap_default_qos = {
56 0,
57 L2CAP_QOS_BEST_EFFORT,
58 0x00000000,
59 0x00000000,
60 0x00000000,
61 0xffffffff,
62 0xffffffff
63 };
64
65
66
67
68 int l2cap_response_timeout = 30;
69 int l2cap_response_extended_timeout = 180;
70
71 void
72 l2cap_init(void)
73 {
74 pool_init(&l2cap_req_pool, sizeof(struct l2cap_req), 0, 0, 0,
75 "l2cap_req", NULL);
76 pool_init(&l2cap_pdu_pool, sizeof(struct l2cap_pdu), 0, 0, 0,
77 "l2cap_pdu", NULL);
78 }
79
80
81
82
83 int
84 l2cap_setmode(struct l2cap_channel *chan)
85 {
86
87 KASSERT(chan != NULL);
88 KASSERT(chan->lc_link != NULL);
89
90 DPRINTF("CID #%d, auth %s, encrypt %s, secure %s\n", chan->lc_lcid,
91 (chan->lc_mode & L2CAP_LM_AUTH ? "yes" : "no"),
92 (chan->lc_mode & L2CAP_LM_ENCRYPT ? "yes" : "no"),
93 (chan->lc_mode & L2CAP_LM_SECURE ? "yes" : "no"));
94
95 if (chan->lc_mode & L2CAP_LM_AUTH)
96 chan->lc_link->hl_flags |= HCI_LINK_AUTH_REQ;
97
98 if (chan->lc_mode & L2CAP_LM_ENCRYPT)
99 chan->lc_link->hl_flags |= HCI_LINK_ENCRYPT_REQ;
100
101 if (chan->lc_mode & L2CAP_LM_SECURE)
102 chan->lc_link->hl_flags |= HCI_LINK_SECURE_REQ;
103
104 return hci_acl_setmode(chan->lc_link);
105 }
106
107
108
109
110 int
111 l2cap_request_alloc(struct l2cap_channel *chan, uint8_t code)
112 {
113 struct hci_link *link = chan->lc_link;
114 struct l2cap_req *req;
115 int next_id;
116
117 if (link == NULL)
118 return ENETDOWN;
119
120
121 next_id = link->hl_lastid + 1;
122 if (next_id > 0xff)
123 next_id = 1;
124
125
126 req = TAILQ_FIRST(&link->hl_reqs);
127 if (req && req->lr_id == next_id)
128 return ENFILE;
129
130 req = pool_get(&l2cap_req_pool, PR_NOWAIT);
131 if (req == NULL)
132 return ENOMEM;
133
134 req->lr_id = link->hl_lastid = next_id;
135
136 req->lr_code = code;
137 req->lr_chan = chan;
138 req->lr_link = link;
139
140 timeout_set(&req->lr_rtx, l2cap_rtx, req);
141 timeout_add(&req->lr_rtx, l2cap_response_timeout*hz);
142
143 TAILQ_INSERT_TAIL(&link->hl_reqs, req, lr_next);
144
145 return 0;
146 }
147
148
149
150
151 struct l2cap_req *
152 l2cap_request_lookup(struct hci_link *link, uint8_t id)
153 {
154 struct l2cap_req *req;
155
156 TAILQ_FOREACH(req, &link->hl_reqs, lr_next) {
157 if (req->lr_id == id)
158 return req;
159 }
160
161 return NULL;
162 }
163
164
165
166
167 void
168 l2cap_request_free(struct l2cap_req *req)
169 {
170 struct hci_link *link = req->lr_link;
171
172 timeout_del(&req->lr_rtx);
173 if (timeout_triggered(&req->lr_rtx))
174 return;
175
176 TAILQ_REMOVE(&link->hl_reqs, req, lr_next);
177 pool_put(&l2cap_req_pool, req);
178 }
179
180
181
182
183
184
185
186
187 void
188 l2cap_rtx(void *arg)
189 {
190 struct l2cap_req *req = arg;
191 struct l2cap_channel *chan;
192 int s;
193
194 s = splsoftnet();
195
196 chan = req->lr_chan;
197 l2cap_request_free(req);
198
199 DPRINTF("cid %d, ident %d\n", (chan ? chan->lc_lcid : 0), req->lr_id);
200
201 if (chan && chan->lc_state != L2CAP_CLOSED)
202 l2cap_close(chan, ETIMEDOUT);
203
204 splx(s);
205 }
206
207
208
209
210
211
212
213
214 int
215 l2cap_cid_alloc(struct l2cap_channel *chan)
216 {
217 struct l2cap_channel *used, *prev = NULL;
218 uint16_t cid = L2CAP_FIRST_CID;
219
220 if (chan->lc_lcid != L2CAP_NULL_CID || chan->lc_state != L2CAP_CLOSED)
221 return EISCONN;
222
223 LIST_FOREACH(used, &l2cap_active_list, lc_ncid) {
224 if (used->lc_lcid > cid)
225 break;
226
227 KASSERT(used->lc_lcid == cid);
228 cid++;
229
230 if (cid == L2CAP_LAST_CID)
231 return ENFILE;
232
233 prev = used;
234 }
235
236 chan->lc_lcid = cid;
237
238 if (prev)
239 LIST_INSERT_AFTER(prev, chan, lc_ncid);
240 else
241 LIST_INSERT_HEAD(&l2cap_active_list, chan, lc_ncid);
242
243 return 0;
244 }
245
246
247
248
249 struct l2cap_channel *
250 l2cap_cid_lookup(uint16_t cid)
251 {
252 struct l2cap_channel *chan;
253
254 LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) {
255 if (chan->lc_lcid == cid)
256 return chan;
257
258 if (chan->lc_lcid > cid)
259 return NULL;
260 }
261
262 return NULL;
263 }