1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2001-2003
5  *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6  * 	All rights reserved.
7  *
8  * Author: Harti Brandt <[email protected]>
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  *
33  * Customisation of the SSCOP code to ng_sscop.
34  */
35 
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/kernel.h>
39 #include <sys/lock.h>
40 #include <sys/mutex.h>
41 #include <sys/mbuf.h>
42 #include <sys/queue.h>
43 #include <sys/systm.h>
44 #include <sys/malloc.h>
45 #include <netgraph/ng_message.h>
46 #include <netgraph/netgraph.h>
47 #include <machine/stdarg.h>
48 
49 #include <netnatm/saal/sscopdef.h>
50 
51 /*
52  * Allocate zeroed or non-zeroed memory of some size and cast it.
53  * Return NULL on failure.
54  */
55 #ifndef SSCOP_DEBUG
56 
57 #define	MEMINIT() \
58 	MALLOC_DECLARE(M_NG_SSCOP); \
59 	DECL_MSGQ_GET \
60 	DECL_SIGQ_GET \
61 	DECL_MBUF_ALLOC
62 
63 #define	MEMZALLOC(PTR, CAST, SIZE) \
64 	((PTR) = (CAST)malloc((SIZE), M_NG_SSCOP, M_NOWAIT | M_ZERO))
65 #define	MEMFREE(PTR) \
66 	free((PTR), M_NG_SSCOP)
67 
68 #define	MSG_ALLOC(PTR) \
69 	MEMZALLOC(PTR, struct sscop_msg *, sizeof(struct sscop_msg))
70 #define	MSG_FREE(PTR) \
71 	MEMFREE(PTR)
72 
73 #define	SIG_ALLOC(PTR) \
74 	MEMZALLOC(PTR, struct sscop_sig *, sizeof(struct sscop_sig))
75 #define	SIG_FREE(PTR) \
76 	MEMFREE(PTR)
77 
78 #else
79 
80 #define	MEMINIT() 							\
81 	MALLOC_DEFINE(M_NG_SSCOP_INS, "sscop_ins", "SSCOP instances");	\
82 	MALLOC_DEFINE(M_NG_SSCOP_MSG, "sscop_msg", "SSCOP buffers");	\
83 	MALLOC_DEFINE(M_NG_SSCOP_SIG, "sscop_sig", "SSCOP signals");	\
84 	DECL_MSGQ_GET \
85 	DECL_SIGQ_GET \
86 	DECL_MBUF_ALLOC
87 
88 #define	MEMZALLOC(PTR, CAST, SIZE)					\
89 	((PTR) = (CAST)malloc((SIZE), M_NG_SSCOP_INS, M_NOWAIT | M_ZERO))
90 #define	MEMFREE(PTR)							\
91 	free((PTR), M_NG_SSCOP_INS)
92 
93 #define	MSG_ALLOC(PTR)							\
94 	((PTR) = malloc(sizeof(struct sscop_msg),			\
95 	    M_NG_SSCOP_MSG, M_NOWAIT | M_ZERO))
96 #define	MSG_FREE(PTR)							\
97 	free((PTR), M_NG_SSCOP_MSG)
98 
99 #define	SIG_ALLOC(PTR)							\
100 	((PTR) = malloc(sizeof(struct sscop_sig),			\
101 	    M_NG_SSCOP_SIG, M_NOWAIT | M_ZERO))
102 #define	SIG_FREE(PTR)							\
103 	free((PTR), M_NG_SSCOP_SIG)
104 
105 #endif
106 
107 /*
108  * Timer support.
109  */
110 typedef struct callout sscop_timer_t;
111 #define	TIMER_INIT(S, T)	ng_callout_init(&(S)->t_##T)
112 #define	TIMER_STOP(S,T)	do {						\
113 	ng_uncallout(&(S)->t_##T, (S)->aarg);				\
114     } while (0)
115 #define	TIMER_RESTART(S, T) do {					\
116 	TIMER_STOP(S, T);						\
117 	ng_callout(&(S)->t_##T, (S)->aarg, NULL,			\
118 	    hz * (S)->timer##T / 1000, T##_func, (S), 0);		\
119     } while (0)
120 #define	TIMER_ISACT(S, T) (callout_pending(&(S)->t_##T))
121 
122 /*
123  * This assumes, that the user argument is the node pointer.
124  */
125 #define	TIMER_FUNC(T,N)							\
126 static void								\
127 T##_func(node_p node, hook_p hook, void *arg1, int arg2)		\
128 {									\
129 	struct sscop *sscop = arg1;					\
130 									\
131 	VERBOSE(sscop, SSCOP_DBG_TIMER, (sscop, sscop->aarg,		\
132 	    "timer_" #T " expired"));					\
133 	sscop_signal(sscop, SIG_T_##N, NULL);				\
134 }
135 
136 /*
137  * Message queues
138  */
139 typedef TAILQ_ENTRY(sscop_msg) sscop_msgq_link_t;
140 typedef TAILQ_HEAD(sscop_msgq, sscop_msg) sscop_msgq_head_t;
141 #define	MSGQ_EMPTY(Q)		TAILQ_EMPTY(Q)
142 #define	MSGQ_INIT(Q)		TAILQ_INIT(Q)
143 #define	MSGQ_FOREACH(P, Q)	TAILQ_FOREACH(P, Q, link)
144 #define	MSGQ_REMOVE(Q, M)	TAILQ_REMOVE(Q, M, link)
145 #define	MSGQ_INSERT_BEFORE(B, M) TAILQ_INSERT_BEFORE(B, M, link)
146 #define	MSGQ_APPEND(Q, M)	TAILQ_INSERT_TAIL(Q, M, link)
147 #define	MSGQ_PEEK(Q)		TAILQ_FIRST((Q))
148 
149 #define	MSGQ_GET(Q) ng_sscop_msgq_get((Q))
150 
151 #define DECL_MSGQ_GET							\
152 static __inline struct sscop_msg *					\
153 ng_sscop_msgq_get(struct sscop_msgq *q)					\
154 {									\
155 	struct sscop_msg *m;						\
156 									\
157 	m = TAILQ_FIRST(q);						\
158 	if (m != NULL)							\
159 		TAILQ_REMOVE(q, m, link);				\
160 	return (m);							\
161 }
162 
163 #define	MSGQ_CLEAR(Q)							\
164 	do {								\
165 		struct sscop_msg *_m1, *_m2;				\
166 									\
167 		_m1 = TAILQ_FIRST(Q);					\
168 		while (_m1 != NULL) {					\
169 			_m2 = TAILQ_NEXT(_m1, link);			\
170 			SSCOP_MSG_FREE(_m1);				\
171 			_m1 = _m2;					\
172 		}							\
173 		TAILQ_INIT((Q));					\
174 	} while (0)
175 
176 /*
177  * Signal queues
178  */
179 typedef TAILQ_ENTRY(sscop_sig) sscop_sigq_link_t;
180 typedef TAILQ_HEAD(sscop_sigq, sscop_sig) sscop_sigq_head_t;
181 #define	SIGQ_INIT(Q) 		TAILQ_INIT(Q)
182 #define	SIGQ_APPEND(Q, S)	TAILQ_INSERT_TAIL(Q, S, link)
183 #define	SIGQ_EMPTY(Q)		TAILQ_EMPTY(Q)
184 
185 #define	SIGQ_GET(Q)	ng_sscop_sigq_get((Q))
186 #define	DECL_SIGQ_GET							\
187 static __inline struct sscop_sig *					\
188 ng_sscop_sigq_get(struct sscop_sigq *q)					\
189 {									\
190 	struct sscop_sig *s;						\
191 									\
192 	s = TAILQ_FIRST(q);						\
193 	if (s != NULL)							\
194 		TAILQ_REMOVE(q, s, link);				\
195 	return (s);							\
196 }
197 
198 #define	SIGQ_MOVE(F, T)							\
199     do {								\
200 	struct sscop_sig *_s;						\
201 									\
202 	while (!TAILQ_EMPTY(F)) {					\
203 		_s = TAILQ_FIRST(F);					\
204 		TAILQ_REMOVE(F, _s, link);				\
205 		TAILQ_INSERT_TAIL(T, _s, link);				\
206 	}								\
207     } while (0)
208 
209 #define	SIGQ_PREPEND(F, T)						\
210     do {								\
211 	struct sscop_sig *_s;						\
212 									\
213 	while (!TAILQ_EMPTY(F)) {					\
214 		_s = TAILQ_LAST(F, sscop_sigq);				\
215 		TAILQ_REMOVE(F, _s, link);				\
216 		TAILQ_INSERT_HEAD(T, _s, link);				\
217 	}								\
218     } while (0)
219 
220 #define	SIGQ_CLEAR(Q)							\
221     do {								\
222 	struct sscop_sig *_s1, *_s2;					\
223 									\
224 	_s1 = TAILQ_FIRST(Q);						\
225 	while (_s1 != NULL) {						\
226 		_s2 = TAILQ_NEXT(_s1, link);				\
227 		SSCOP_MSG_FREE(_s1->msg);				\
228 		SIG_FREE(_s1);						\
229 		_s1 = _s2;						\
230 	}								\
231 	TAILQ_INIT(Q);							\
232     } while (0)
233 
234 /*
235  * Message buffers
236  */
237 #define	MBUF_FREE(M)	do { if ((M)) m_freem((M)); } while(0)
238 #define	MBUF_DUP(M)	m_copypacket((M), M_NOWAIT)
239 #define	MBUF_LEN(M) 	((size_t)(M)->m_pkthdr.len)
240 
241 /*
242  * Return the i-th word counted from the end of the buffer.
243  * i=-1 will return the last 32bit word, i=-2 the 2nd last.
244  * Assumes that there is enough space.
245  */
246 #define	MBUF_TRAIL32(M ,I) ng_sscop_mbuf_trail32((M), (I))
247 
248 static uint32_t __inline
ng_sscop_mbuf_trail32(const struct mbuf * m,int i)249 ng_sscop_mbuf_trail32(const struct mbuf *m, int i)
250 {
251 	uint32_t w;
252 
253 	m_copydata(m, m->m_pkthdr.len + 4 * i, 4, (caddr_t)&w);
254 	return (ntohl(w));
255 }
256 
257 /*
258  * Strip 32bit value from the end
259  */
260 #define	MBUF_STRIP32(M) ng_sscop_mbuf_strip32((M))
261 
262 static uint32_t __inline
ng_sscop_mbuf_strip32(struct mbuf * m)263 ng_sscop_mbuf_strip32(struct mbuf *m)
264 {
265 	uint32_t w;
266 
267 	m_copydata(m, m->m_pkthdr.len - 4, 4, (caddr_t)&w);
268 	m_adj(m, -4);
269 	return (ntohl(w));
270 }
271 
272 #define	MBUF_GET32(M) ng_sscop_mbuf_get32((M))
273 
274 static uint32_t __inline
ng_sscop_mbuf_get32(struct mbuf * m)275 ng_sscop_mbuf_get32(struct mbuf *m)
276 {
277 	uint32_t w;
278 
279 	m_copydata(m, 0, 4, (caddr_t)&w);
280 	m_adj(m, 4);
281 	return (ntohl(w));
282 }
283 
284 /*
285  * Append a 32bit value to an mbuf. Failures are ignored.
286  */
287 #define	MBUF_APPEND32(M, W)						\
288      do {								\
289 	uint32_t _w = (W);						\
290 									\
291 	_w = htonl(_w);							\
292 	m_copyback((M), (M)->m_pkthdr.len, 4, (caddr_t)&_w);		\
293     } while (0)
294 
295 /*
296  * Pad a message to a multiple of four byte and return the amount of padding
297  * Failures are ignored.
298  */
299 #define	MBUF_PAD4(M) ng_sscop_mbuf_pad4((M))
300 
301 static u_int __inline
ng_sscop_mbuf_pad4(struct mbuf * m)302 ng_sscop_mbuf_pad4(struct mbuf *m)
303 {
304 	static u_char pad[4] = { 0, 0, 0, 0 };
305 	int len = m->m_pkthdr.len;
306 	int npad = 3 - ((len + 3) & 3);
307 
308 	if (npad != 0)
309 		m_copyback(m, len, npad, (caddr_t)pad);
310 	return (npad);
311 }
312 
313 #define	MBUF_UNPAD(M, P) do { if( (P) > 0) m_adj((M), -(P)); } while (0)
314 
315 /*
316  * Allocate a message that will probably hold N bytes.
317  */
318 #define	MBUF_ALLOC(N) ng_sscop_mbuf_alloc((N))
319 
320 #define	DECL_MBUF_ALLOC							\
321 static __inline struct mbuf *						\
322 ng_sscop_mbuf_alloc(size_t n)						\
323 {									\
324 	struct mbuf *m;							\
325 									\
326 	MGETHDR(m, M_NOWAIT, MT_DATA);					\
327 	if (m != NULL) {						\
328 		m->m_len = 0;						\
329 		m->m_pkthdr.len = 0;					\
330 		if (n > MHLEN) {					\
331 			if (!(MCLGET(m, M_NOWAIT))){			\
332 				m_free(m);				\
333 				m = NULL;				\
334 			}						\
335 		}							\
336 	}								\
337 	return (m);							\
338 }
339 
340 #ifdef SSCOP_DEBUG
341 #define	ASSERT(X)	KASSERT(X, (#X))
342 #else
343 #define	ASSERT(X)
344 #endif
345