1 /*
2  * ng_l2cap_cmds.h
3  */
4 
5 /*-
6  * SPDX-License-Identifier: BSD-2-Clause
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  */
34 
35 #ifndef _NETGRAPH_L2CAP_CMDS_H_
36 #define _NETGRAPH_L2CAP_CMDS_H_
37 
38 /******************************************************************************
39  ******************************************************************************
40  **                L2CAP to L2CAP signaling command macros
41  ******************************************************************************
42  ******************************************************************************/
43 
44 /*
45  * Note: All L2CAP implementations are required to support minimal signaling
46  *       MTU of 48 bytes. In order to simplify things we will send one command
47  *       per one L2CAP packet. Given evrything above we can assume that one
48  *       signaling packet will fit into single mbuf.
49  */
50 
51 /* L2CAP_CommandRej */
52 #define	_ng_l2cap_cmd_rej(_m, _ident, _reason, _mtu, _scid, _dcid)	\
53 do {									\
54 	struct _cmd_rej {						\
55 		ng_l2cap_cmd_hdr_t	 hdr;				\
56 		ng_l2cap_cmd_rej_cp	 param;				\
57 		ng_l2cap_cmd_rej_data_t	 data;				\
58 	} __attribute__ ((packed))	*c = NULL;			\
59 									\
60 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
61 	if ((_m) == NULL) 						\
62 		break;							\
63 									\
64 	c = mtod((_m), struct _cmd_rej *);				\
65 	c->hdr.code = NG_L2CAP_CMD_REJ;					\
66 	c->hdr.ident = (_ident);					\
67 	c->hdr.length = sizeof(c->param);				\
68 									\
69 	c->param.reason = htole16((_reason));				\
70 									\
71 	if ((_reason) == NG_L2CAP_REJ_MTU_EXCEEDED) {			\
72 		c->data.mtu.mtu = htole16((_mtu));			\
73 		c->hdr.length += sizeof(c->data.mtu);			\
74 	} else if ((_reason) == NG_L2CAP_REJ_INVALID_CID) {		\
75 		c->data.cid.scid = htole16((_scid));			\
76 		c->data.cid.dcid = htole16((_dcid));			\
77 		c->hdr.length += sizeof(c->data.cid);			\
78 	}								\
79 									\
80 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(c->hdr) + 		\
81 					c->hdr.length;			\
82 									\
83 	c->hdr.length = htole16(c->hdr.length);				\
84 } while (0)
85 
86 /* L2CAP_ConnectReq */
87 #define	_ng_l2cap_con_req(_m, _ident, _psm, _scid)			\
88 do {									\
89 	struct _con_req {						\
90 		ng_l2cap_cmd_hdr_t	 hdr;				\
91 		ng_l2cap_con_req_cp	 param;				\
92 	} __attribute__ ((packed)) 	*c = NULL;			\
93 									\
94 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
95 	if ((_m) == NULL) 						\
96 		break;							\
97 									\
98 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
99 									\
100 	c = mtod((_m), struct _con_req *);				\
101 	c->hdr.code = NG_L2CAP_CON_REQ;					\
102 	c->hdr.ident = (_ident);					\
103 	c->hdr.length = htole16(sizeof(c->param));			\
104 									\
105 	c->param.psm = htole16((_psm));					\
106 	c->param.scid = htole16((_scid));				\
107 } while (0)
108 
109 /* L2CAP_ConnectRsp */
110 #define _ng_l2cap_con_rsp(_m, _ident, _dcid, _scid, _result, _status)	\
111 do {									\
112 	struct _con_rsp {						\
113 		ng_l2cap_cmd_hdr_t	 hdr;				\
114 		ng_l2cap_con_rsp_cp	 param;				\
115 	} __attribute__ ((packed))	*c = NULL;			\
116 									\
117 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
118 	if ((_m) == NULL) 						\
119 		break;							\
120 									\
121 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
122 									\
123 	c = mtod((_m), struct _con_rsp *);				\
124 	c->hdr.code = NG_L2CAP_CON_RSP;					\
125 	c->hdr.ident = (_ident);					\
126 	c->hdr.length = htole16(sizeof(c->param));			\
127 									\
128 	c->param.dcid = htole16((_dcid));				\
129 	c->param.scid = htole16((_scid));				\
130 	c->param.result = htole16((_result));				\
131 	c->param.status = htole16((_status));				\
132 } while (0)
133 
134 /* L2CAP_ConfigReq */
135 #define	_ng_l2cap_cfg_req(_m, _ident, _dcid, _flags, _data)		\
136 do {									\
137 	struct _cfg_req {						\
138 		ng_l2cap_cmd_hdr_t	 hdr;				\
139 		ng_l2cap_cfg_req_cp	 param;				\
140 	} __attribute__ ((packed))	*c = NULL;			\
141 									\
142 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
143 	if ((_m) == NULL) { 						\
144 		NG_FREE_M((_data));					\
145 		break;							\
146 	}								\
147 									\
148 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
149 									\
150 	c = mtod((_m), struct _cfg_req *);				\
151 	c->hdr.code = NG_L2CAP_CFG_REQ;					\
152 	c->hdr.ident = (_ident);					\
153 	c->hdr.length = sizeof(c->param);				\
154 									\
155 	c->param.dcid = htole16((_dcid));				\
156 	c->param.flags = htole16((_flags));				\
157 	if ((_data) != NULL) {						\
158 		int	l = (_data)->m_pkthdr.len;			\
159 									\
160 		m_cat((_m), (_data));					\
161 		c->hdr.length += l;					\
162 		(_m)->m_pkthdr.len += l;				\
163 	}								\
164 									\
165 	c->hdr.length = htole16(c->hdr.length);				\
166 } while (0)
167 
168 /* L2CAP_ConfigRsp */
169 #define _ng_l2cap_cfg_rsp(_m, _ident, _scid, _flags, _result, _data)	\
170 do {									\
171 	struct _cfg_rsp {						\
172 		ng_l2cap_cmd_hdr_t	 hdr;				\
173 		ng_l2cap_cfg_rsp_cp	 param;				\
174 	} __attribute__ ((packed))	*c = NULL;			\
175 									\
176 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
177 	if ((_m) == NULL) { 						\
178 		NG_FREE_M((_data));					\
179 		break;							\
180 	}								\
181 									\
182 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
183 									\
184 	c = mtod((_m), struct _cfg_rsp *);				\
185 	c->hdr.code = NG_L2CAP_CFG_RSP;					\
186 	c->hdr.ident = (_ident);					\
187 	c->hdr.length = sizeof(c->param);				\
188 									\
189 	c->param.scid = htole16((_scid));				\
190 	c->param.flags = htole16((_flags));				\
191 	c->param.result = htole16((_result));				\
192 	if ((_data) != NULL) {						\
193 		int	l = (_data)->m_pkthdr.len;			\
194 									\
195 		m_cat((_m), (_data));					\
196 		c->hdr.length += l;					\
197 		(_m)->m_pkthdr.len += l;				\
198 	}								\
199 									\
200 	c->hdr.length = htole16(c->hdr.length);				\
201 } while (0)
202 
203 #define _ng_l2cap_cmd_urs(_m, _ident, _result)	\
204 do {									\
205 	struct  _cmd_urs{						\
206 		ng_l2cap_cmd_hdr_t	 hdr;				\
207 		uint16_t	 result;				\
208 	} __attribute__ ((packed))	*c = NULL;			\
209 									\
210 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
211 									\
212 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
213 									\
214 	c = mtod((_m), struct _cmd_urs *);				\
215 	c->hdr.code = NG_L2CAP_CMD_PARAM_UPDATE_RESPONSE;		\
216 	c->hdr.ident = (_ident);					\
217 	c->hdr.length = sizeof(c->result);				\
218 									\
219 	c->result = htole16((_result));				\
220 } while (0)
221 
222 /* Build configuration options */
223 #define _ng_l2cap_build_cfg_options(_m, _mtu, _flush_timo, _flow)	\
224 do {									\
225 	u_int8_t	*p = NULL;					\
226 									\
227 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
228 	if ((_m) == NULL)						\
229 		break;							\
230 									\
231 	(_m)->m_pkthdr.len = (_m)->m_len = 0;				\
232 	p = mtod((_m), u_int8_t *);					\
233 									\
234 	if ((_mtu) != NULL) {						\
235 		struct _cfg_opt_mtu {					\
236 			ng_l2cap_cfg_opt_t	 hdr;			\
237 			u_int16_t		 val;			\
238 		} __attribute__ ((packed))	*o = NULL;		\
239 									\
240 		o = (struct _cfg_opt_mtu *) p;				\
241 		o->hdr.type = NG_L2CAP_OPT_MTU;				\
242 		o->hdr.length = sizeof(o->val);				\
243 		o->val = htole16(*(u_int16_t *)(_mtu));			\
244 									\
245 		(_m)->m_pkthdr.len += sizeof(*o);			\
246 		p += sizeof(*o);					\
247 	}								\
248 									\
249 	if ((_flush_timo) != NULL) {					\
250 		struct _cfg_opt_flush {					\
251 			ng_l2cap_cfg_opt_t	 hdr;			\
252 			u_int16_t		 val;			\
253 		} __attribute__ ((packed))	*o = NULL;		\
254 									\
255 		o = (struct _cfg_opt_flush *) p;			\
256 		o->hdr.type = NG_L2CAP_OPT_FLUSH_TIMO;			\
257 		o->hdr.length = sizeof(o->val);				\
258 		o->val = htole16(*(u_int16_t *)(_flush_timo));		\
259 									\
260 		(_m)->m_pkthdr.len += sizeof(*o);			\
261 		p += sizeof(*o);					\
262 	}								\
263 									\
264 	if ((_flow) != NULL) {						\
265 		struct _cfg_opt_flow {					\
266 			ng_l2cap_cfg_opt_t	 hdr;			\
267 			ng_l2cap_flow_t		 val;			\
268 		} __attribute__ ((packed))	*o = NULL;		\
269 									\
270 		o = (struct _cfg_opt_flow *) p;				\
271 		o->hdr.type = NG_L2CAP_OPT_QOS;				\
272 		o->hdr.length = sizeof(o->val);				\
273 		o->val.flags = ((ng_l2cap_flow_p)(_flow))->flags;	\
274 		o->val.service_type = ((ng_l2cap_flow_p)		\
275 				(_flow))->service_type;			\
276 		o->val.token_rate =					\
277 			htole32(((ng_l2cap_flow_p)(_flow))->token_rate);\
278 		o->val.token_bucket_size =				\
279 			htole32(((ng_l2cap_flow_p)			\
280 				(_flow))->token_bucket_size);		\
281 		o->val.peak_bandwidth = 				\
282 			htole32(((ng_l2cap_flow_p)			\
283 				(_flow))->peak_bandwidth);		\
284 		o->val.latency = htole32(((ng_l2cap_flow_p)		\
285 				(_flow))->latency);			\
286 		o->val.delay_variation = 				\
287 			htole32(((ng_l2cap_flow_p)			\
288 				(_flow))->delay_variation);		\
289 									\
290 		(_m)->m_pkthdr.len += sizeof(*o);			\
291 	}								\
292 									\
293 	(_m)->m_len = (_m)->m_pkthdr.len;				\
294 } while (0)
295 
296 /* L2CAP_DisconnectReq */
297 #define	_ng_l2cap_discon_req(_m, _ident, _dcid, _scid)			\
298 do {									\
299 	struct _discon_req {						\
300 		ng_l2cap_cmd_hdr_t	 hdr;				\
301 		ng_l2cap_discon_req_cp	 param;				\
302 	} __attribute__ ((packed))	*c = NULL;			\
303 									\
304 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
305 	if ((_m) == NULL)						\
306 		break;							\
307 									\
308 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
309 									\
310 	c = mtod((_m), struct _discon_req *);				\
311 	c->hdr.code = NG_L2CAP_DISCON_REQ;				\
312 	c->hdr.ident = (_ident);					\
313 	c->hdr.length = htole16(sizeof(c->param));			\
314 									\
315 	c->param.dcid = htole16((_dcid));				\
316 	c->param.scid = htole16((_scid));				\
317 } while (0)
318 
319 /* L2CA_DisconnectRsp */
320 #define	_ng_l2cap_discon_rsp(_m, _ident, _dcid, _scid)			\
321 do {									\
322 	struct _discon_rsp {						\
323 		ng_l2cap_cmd_hdr_t	 hdr;				\
324 		ng_l2cap_discon_rsp_cp	 param;				\
325 	} __attribute__ ((packed))	*c = NULL;			\
326 									\
327 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
328 	if ((_m) == NULL)						\
329 		break;							\
330 									\
331 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
332 									\
333 	c = mtod((_m), struct _discon_rsp *);				\
334 	c->hdr.code = NG_L2CAP_DISCON_RSP;				\
335 	c->hdr.ident = (_ident);					\
336 	c->hdr.length = htole16(sizeof(c->param));			\
337 									\
338 	c->param.dcid = htole16((_dcid));				\
339 	c->param.scid = htole16((_scid));				\
340 } while (0)
341 
342 /* L2CAP_EchoReq */
343 #define	_ng_l2cap_echo_req(_m, _ident, _data, _size)			\
344 do {									\
345 	ng_l2cap_cmd_hdr_t	*c = NULL;				\
346 									\
347 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
348 	if ((_m) == NULL) 						\
349 		break;							\
350 									\
351 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
352 									\
353 	c = mtod((_m), ng_l2cap_cmd_hdr_t *);				\
354 	c->code = NG_L2CAP_ECHO_REQ;					\
355 	c->ident = (_ident);						\
356 	c->length = 0;							\
357 									\
358 	if ((_data) != NULL) {						\
359 		m_copyback((_m), sizeof(*c), (_size), (_data));		\
360 		c->length += (_size);					\
361 	}								\
362 									\
363 	c->length = htole16(c->length);					\
364 } while (0)
365 
366 /* L2CAP_InfoReq */
367 #define	_ng_l2cap_info_req(_m, _ident, _type)				\
368 do {									\
369 	struct _info_req {						\
370 		ng_l2cap_cmd_hdr_t	 hdr;				\
371 		ng_l2cap_info_req_cp	 param;				\
372 	} __attribute__ ((packed))	*c = NULL;			\
373 									\
374 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
375 	if ((_m) == NULL)						\
376 		break;							\
377 									\
378 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(*c);			\
379 									\
380 	c = mtod((_m), struct _info_req *);				\
381 	c->hdr.code = NG_L2CAP_INFO_REQ;				\
382 	c->hdr.ident = (_ident);					\
383 	c->hdr.length = htole16(sizeof(c->param));			\
384 									\
385 	c->param.type = htole16((_type));				\
386 } while (0)
387 
388 /* L2CAP_InfoRsp */
389 #define	_ng_l2cap_info_rsp(_m, _ident, _type, _result, _mtu)		\
390 do {									\
391 	struct _info_rsp {						\
392 		ng_l2cap_cmd_hdr_t	 hdr;				\
393 		ng_l2cap_info_rsp_cp	 param;				\
394 		ng_l2cap_info_rsp_data_t data;				\
395 	} __attribute__ ((packed))	*c = NULL;			\
396 									\
397 	MGETHDR((_m), M_NOWAIT, MT_DATA);				\
398 	if ((_m) == NULL) 						\
399 		break;							\
400 									\
401 	c = mtod((_m), struct _info_rsp *);				\
402 	c->hdr.code = NG_L2CAP_INFO_RSP;				\
403 	c->hdr.ident = (_ident);					\
404 	c->hdr.length = sizeof(c->param);				\
405 									\
406 	c->param.type = htole16((_type));				\
407 	c->param.result = htole16((_result));				\
408 									\
409 	if ((_result) == NG_L2CAP_SUCCESS) {				\
410 		switch ((_type)) {					\
411 		case NG_L2CAP_CONNLESS_MTU:				\
412 			c->data.mtu.mtu = htole16((_mtu));		\
413 			c->hdr.length += sizeof((c->data.mtu.mtu));	\
414 			break;						\
415 		}							\
416 	}								\
417 									\
418 	(_m)->m_pkthdr.len = (_m)->m_len = sizeof(c->hdr) +		\
419 					c->hdr.length;			\
420 									\
421 	c->hdr.length = htole16(c->hdr.length);		 		\
422 } while (0)
423 
424 void ng_l2cap_con_wakeup              (ng_l2cap_con_p);
425 void ng_l2cap_con_fail                (ng_l2cap_con_p, u_int16_t);
426 void ng_l2cap_process_command_timeout (node_p, hook_p, void *, int);
427 
428 #endif /* ndef _NETGRAPH_L2CAP_CMDS_H_ */
429