1 /*
2  * ng_l2cap_cmds.h
3  */
4 
5 /*-
6  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
7  *
8  * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Id: ng_l2cap_cmds.h,v 1.4 2003/04/01 18:15:26 max Exp $
33  * $FreeBSD$
34  */
35 
36 #ifndef _NETGRAPH_L2CAP_CMDS_H_
37 #define _NETGRAPH_L2CAP_CMDS_H_
38 
39 /******************************************************************************
40  ******************************************************************************
41  **                L2CAP to L2CAP signaling command macros
42  ******************************************************************************
43  ******************************************************************************/
44 
45 /*
46  * Note: All L2CAP implementations are required to support minimal signaling
47  *       MTU of 48 bytes. In order to simplify things we will send one command
48  *       per one L2CAP packet. Given evrything above we can assume that one
49  *       signaling packet will fit into single mbuf.
50  */
51 
52 /* L2CAP_CommandRej */
53 #define	_ng_l2cap_cmd_rej(_m, _ident, _reason, _mtu, _scid, _dcid)	\
54 do {									\
55 	struct _cmd_rej {						\
56 		ng_l2cap_cmd_hdr_t	 hdr;				\
57 		ng_l2cap_cmd_rej_cp	 param;				\
58 		ng_l2cap_cmd_rej_data_t	 data;				\
59 	} __attribute__ ((packed))	*c = NULL;			\
60 									\
61 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
62 	if ((_m) == NULL) 						\
63 		break;							\
64 									\
65 	c = mtod((_m), struct _cmd_rej *);				\
66 	c->hdr.code = NG_L2CAP_CMD_REJ;					\
67 	c->hdr.ident = (_ident);					\
68 	c->hdr.length = sizeof(c->param);				\
69 									\
70 	c->param.reason = htole16((_reason));				\
71 									\
72 	if ((_reason) == NG_L2CAP_REJ_MTU_EXCEEDED) {			\
73 		c->data.mtu.mtu = htole16((_mtu));			\
74 		c->hdr.length += sizeof(c->data.mtu);			\
75 	} else if ((_reason) == NG_L2CAP_REJ_INVALID_CID) {		\
76 		c->data.cid.scid = htole16((_scid));			\
77 		c->data.cid.dcid = htole16((_dcid));			\
78 		c->hdr.length += sizeof(c->data.cid);			\
79 	}								\
80 									\
81 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(c->hdr) + 		\
82 					c->hdr.length;			\
83 									\
84 	c->hdr.length = htole16(c->hdr.length);				\
85 } while (0)
86 
87 /* L2CAP_ConnectReq */
88 #define	_ng_l2cap_con_req(_m, _ident, _psm, _scid)			\
89 do {									\
90 	struct _con_req {						\
91 		ng_l2cap_cmd_hdr_t	 hdr;				\
92 		ng_l2cap_con_req_cp	 param;				\
93 	} __attribute__ ((packed)) 	*c = NULL;			\
94 									\
95 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
96 	if ((_m) == NULL) 						\
97 		break;							\
98 									\
99 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
100 									\
101 	c = mtod((_m), struct _con_req *);				\
102 	c->hdr.code = NG_L2CAP_CON_REQ;					\
103 	c->hdr.ident = (_ident);					\
104 	c->hdr.length = htole16(sizeof(c->param));			\
105 									\
106 	c->param.psm = htole16((_psm));					\
107 	c->param.scid = htole16((_scid));				\
108 } while (0)
109 
110 /* L2CAP_ConnectRsp */
111 #define _ng_l2cap_con_rsp(_m, _ident, _dcid, _scid, _result, _status)	\
112 do {									\
113 	struct _con_rsp {						\
114 		ng_l2cap_cmd_hdr_t	 hdr;				\
115 		ng_l2cap_con_rsp_cp	 param;				\
116 	} __attribute__ ((packed))	*c = NULL;			\
117 									\
118 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
119 	if ((_m) == NULL) 						\
120 		break;							\
121 									\
122 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
123 									\
124 	c = mtod((_m), struct _con_rsp *);				\
125 	c->hdr.code = NG_L2CAP_CON_RSP;					\
126 	c->hdr.ident = (_ident);					\
127 	c->hdr.length = htole16(sizeof(c->param));			\
128 									\
129 	c->param.dcid = htole16((_dcid));				\
130 	c->param.scid = htole16((_scid));				\
131 	c->param.result = htole16((_result));				\
132 	c->param.status = htole16((_status));				\
133 } while (0)
134 
135 /* L2CAP_ConfigReq */
136 #define	_ng_l2cap_cfg_req(_m, _ident, _dcid, _flags, _data)		\
137 do {									\
138 	struct _cfg_req {						\
139 		ng_l2cap_cmd_hdr_t	 hdr;				\
140 		ng_l2cap_cfg_req_cp	 param;				\
141 	} __attribute__ ((packed))	*c = NULL;			\
142 									\
143 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
144 	if ((_m) == NULL) { 						\
145 		NG_FREE_M((_data));					\
146 		break;							\
147 	}								\
148 									\
149 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
150 									\
151 	c = mtod((_m), struct _cfg_req *);				\
152 	c->hdr.code = NG_L2CAP_CFG_REQ;					\
153 	c->hdr.ident = (_ident);					\
154 	c->hdr.length = sizeof(c->param);				\
155 									\
156 	c->param.dcid = htole16((_dcid));				\
157 	c->param.flags = htole16((_flags));				\
158 	if ((_data) != NULL) {						\
159 		int	l = (_data)->m_pkthdr.len;			\
160 									\
161 		m_cat((_m), (_data));					\
162 		c->hdr.length += l;					\
163 		(_m)->m_pkthdr.len += l;				\
164 	}								\
165 									\
166 	c->hdr.length = htole16(c->hdr.length);				\
167 } while (0)
168 
169 /* L2CAP_ConfigRsp */
170 #define _ng_l2cap_cfg_rsp(_m, _ident, _scid, _flags, _result, _data)	\
171 do {									\
172 	struct _cfg_rsp {						\
173 		ng_l2cap_cmd_hdr_t	 hdr;				\
174 		ng_l2cap_cfg_rsp_cp	 param;				\
175 	} __attribute__ ((packed))	*c = NULL;			\
176 									\
177 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
178 	if ((_m) == NULL) { 						\
179 		NG_FREE_M((_data));					\
180 		break;							\
181 	}								\
182 									\
183 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
184 									\
185 	c = mtod((_m), struct _cfg_rsp *);				\
186 	c->hdr.code = NG_L2CAP_CFG_RSP;					\
187 	c->hdr.ident = (_ident);					\
188 	c->hdr.length = sizeof(c->param);				\
189 									\
190 	c->param.scid = htole16((_scid));				\
191 	c->param.flags = htole16((_flags));				\
192 	c->param.result = htole16((_result));				\
193 	if ((_data) != NULL) {						\
194 		int	l = (_data)->m_pkthdr.len;			\
195 									\
196 		m_cat((_m), (_data));					\
197 		c->hdr.length += l;					\
198 		(_m)->m_pkthdr.len += l;				\
199 	}								\
200 									\
201 	c->hdr.length = htole16(c->hdr.length);				\
202 } while (0)
203 
204 #define _ng_l2cap_cmd_urs(_m, _ident, _result)	\
205 do {									\
206 	struct  _cmd_urs{						\
207 		ng_l2cap_cmd_hdr_t	 hdr;				\
208 		uint16_t	 result;				\
209 	} __attribute__ ((packed))	*c = NULL;			\
210 									\
211 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
212 									\
213 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
214 									\
215 	c = mtod((_m), struct _cmd_urs *);				\
216 	c->hdr.code = NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE;		\
217 	c->hdr.ident = (_ident);					\
218 	c->hdr.length = sizeof(c->result);				\
219 									\
220 	c->result = htole16((_result));				\
221 } while (0)
222 
223 /* Build configuration options */
224 #define _ng_l2cap_build_cfg_options(_m, _mtu, _flush_timo, _flow)	\
225 do {									\
226 	u_int8_t	*p = NULL;					\
227 									\
228 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
229 	if ((_m) == NULL)						\
230 		break;							\
231 									\
232 	(_m)->m_pkthdr.len = (_m)->m_len = 0;				\
233 	p = mtod((_m), u_int8_t *);					\
234 									\
235 	if ((_mtu) != NULL) {						\
236 		struct _cfg_opt_mtu {					\
237 			ng_l2cap_cfg_opt_t	 hdr;			\
238 			u_int16_t		 val;			\
239 		} __attribute__ ((packed))	*o = NULL;		\
240 									\
241 		o = (struct _cfg_opt_mtu *) p;				\
242 		o->hdr.type = NG_L2CAP_OPT_MTU;				\
243 		o->hdr.length = sizeof(o->val);				\
244 		o->val = htole16(*(u_int16_t *)(_mtu));			\
245 									\
246 		(_m)->m_pkthdr.len += sizeof(*o);			\
247 		p += sizeof(*o);					\
248 	}								\
249 									\
250 	if ((_flush_timo) != NULL) {					\
251 		struct _cfg_opt_flush {					\
252 			ng_l2cap_cfg_opt_t	 hdr;			\
253 			u_int16_t		 val;			\
254 		} __attribute__ ((packed))	*o = NULL;		\
255 									\
256 		o = (struct _cfg_opt_flush *) p;			\
257 		o->hdr.type = NG_L2CAP_OPT_FLUSH_TIMO;			\
258 		o->hdr.length = sizeof(o->val);				\
259 		o->val = htole16(*(u_int16_t *)(_flush_timo));		\
260 									\
261 		(_m)->m_pkthdr.len += sizeof(*o);			\
262 		p += sizeof(*o);					\
263 	}								\
264 									\
265 	if ((_flow) != NULL) {						\
266 		struct _cfg_opt_flow {					\
267 			ng_l2cap_cfg_opt_t	 hdr;			\
268 			ng_l2cap_flow_t		 val;			\
269 		} __attribute__ ((packed))	*o = NULL;		\
270 									\
271 		o = (struct _cfg_opt_flow *) p;				\
272 		o->hdr.type = NG_L2CAP_OPT_QOS;				\
273 		o->hdr.length = sizeof(o->val);				\
274 		o->val.flags = ((ng_l2cap_flow_p)(_flow))->flags;	\
275 		o->val.service_type = ((ng_l2cap_flow_p)		\
276 				(_flow))->service_type;			\
277 		o->val.token_rate =					\
278 			htole32(((ng_l2cap_flow_p)(_flow))->token_rate);\
279 		o->val.token_bucket_size =				\
280 			htole32(((ng_l2cap_flow_p)			\
281 				(_flow))->token_bucket_size);		\
282 		o->val.peak_bandwidth = 				\
283 			htole32(((ng_l2cap_flow_p)			\
284 				(_flow))->peak_bandwidth);		\
285 		o->val.latency = htole32(((ng_l2cap_flow_p)		\
286 				(_flow))->latency);			\
287 		o->val.delay_variation = 				\
288 			htole32(((ng_l2cap_flow_p)			\
289 				(_flow))->delay_variation);		\
290 									\
291 		(_m)->m_pkthdr.len += sizeof(*o);			\
292 	}								\
293 									\
294 	(_m)->m_len = (_m)->m_pkthdr.len;				\
295 } while (0)
296 
297 /* L2CAP_DisconnectReq */
298 #define	_ng_l2cap_discon_req(_m, _ident, _dcid, _scid)			\
299 do {									\
300 	struct _discon_req {						\
301 		ng_l2cap_cmd_hdr_t	 hdr;				\
302 		ng_l2cap_discon_req_cp	 param;				\
303 	} __attribute__ ((packed))	*c = NULL;			\
304 									\
305 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
306 	if ((_m) == NULL)						\
307 		break;							\
308 									\
309 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
310 									\
311 	c = mtod((_m), struct _discon_req *);				\
312 	c->hdr.code = NG_L2CAP_DISCON_REQ;				\
313 	c->hdr.ident = (_ident);					\
314 	c->hdr.length = htole16(sizeof(c->param));			\
315 									\
316 	c->param.dcid = htole16((_dcid));				\
317 	c->param.scid = htole16((_scid));				\
318 } while (0)
319 
320 /* L2CA_DisconnectRsp */
321 #define	_ng_l2cap_discon_rsp(_m, _ident, _dcid, _scid)			\
322 do {									\
323 	struct _discon_rsp {						\
324 		ng_l2cap_cmd_hdr_t	 hdr;				\
325 		ng_l2cap_discon_rsp_cp	 param;				\
326 	} __attribute__ ((packed))	*c = NULL;			\
327 									\
328 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
329 	if ((_m) == NULL)						\
330 		break;							\
331 									\
332 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
333 									\
334 	c = mtod((_m), struct _discon_rsp *);				\
335 	c->hdr.code = NG_L2CAP_DISCON_RSP;				\
336 	c->hdr.ident = (_ident);					\
337 	c->hdr.length = htole16(sizeof(c->param));			\
338 									\
339 	c->param.dcid = htole16((_dcid));				\
340 	c->param.scid = htole16((_scid));				\
341 } while (0)
342 
343 /* L2CAP_EchoReq */
344 #define	_ng_l2cap_echo_req(_m, _ident, _data, _size)			\
345 do {									\
346 	ng_l2cap_cmd_hdr_t	*c = NULL;				\
347 									\
348 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
349 	if ((_m) == NULL) 						\
350 		break;							\
351 									\
352 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
353 									\
354 	c = mtod((_m), ng_l2cap_cmd_hdr_t *);				\
355 	c->code = NG_L2CAP_ECHO_REQ;					\
356 	c->ident = (_ident);						\
357 	c->length = 0;							\
358 									\
359 	if ((_data) != NULL) {						\
360 		m_copyback((_m), sizeof(*c), (_size), (_data));		\
361 		c->length += (_size);					\
362 	}								\
363 									\
364 	c->length = htole16(c->length);					\
365 } while (0)
366 
367 /* L2CAP_InfoReq */
368 #define	_ng_l2cap_info_req(_m, _ident, _type)				\
369 do {									\
370 	struct _info_req {						\
371 		ng_l2cap_cmd_hdr_t	 hdr;				\
372 		ng_l2cap_info_req_cp	 param;				\
373 	} __attribute__ ((packed))	*c = NULL;			\
374 									\
375 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
376 	if ((_m) == NULL)						\
377 		break;							\
378 									\
379 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
380 									\
381 	c = mtod((_m), struct _info_req *);				\
382 	c->hdr.code = NG_L2CAP_INFO_REQ;				\
383 	c->hdr.ident = (_ident);					\
384 	c->hdr.length = htole16(sizeof(c->param));			\
385 									\
386 	c->param.type = htole16((_type));				\
387 } while (0)
388 
389 /* L2CAP_InfoRsp */
390 #define	_ng_l2cap_info_rsp(_m, _ident, _type, _result, _mtu)		\
391 do {									\
392 	struct _info_rsp {						\
393 		ng_l2cap_cmd_hdr_t	 hdr;				\
394 		ng_l2cap_info_rsp_cp	 param;				\
395 		ng_l2cap_info_rsp_data_t data;				\
396 	} __attribute__ ((packed))	*c = NULL;			\
397 									\
398 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
399 	if ((_m) == NULL) 						\
400 		break;							\
401 									\
402 	c = mtod((_m), struct _info_rsp *);				\
403 	c->hdr.code = NG_L2CAP_INFO_RSP;				\
404 	c->hdr.ident = (_ident);					\
405 	c->hdr.length = sizeof(c->param);				\
406 									\
407 	c->param.type = htole16((_type));				\
408 	c->param.result = htole16((_result));				\
409 									\
410 	if ((_result) == NG_L2CAP_SUCCESS) {				\
411 		switch ((_type)) {					\
412 		case NG_L2CAP_CONNLESS_MTU:				\
413 			c->data.mtu.mtu = htole16((_mtu));		\
414 			c->hdr.length += sizeof((c->data.mtu.mtu));	\
415 			break;						\
416 		}							\
417 	}								\
418 									\
419 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(c->hdr) +		\
420 					c->hdr.length;			\
421 									\
422 	c->hdr.length = htole16(c->hdr.length);		 		\
423 } while (0)
424 
425 void ng_l2cap_con_wakeup              (ng_l2cap_con_p);
426 void ng_l2cap_con_fail                (ng_l2cap_con_p, u_int16_t);
427 void ng_l2cap_process_command_timeout (node_p, hook_p, void *, int);
428 
429 #endif /* ndef _NETGRAPH_L2CAP_CMDS_H_ */
430 
431