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