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 <harti@freebsd.org>
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 */
110typedef 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)							\
126static void								\
127T##_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/*
138 * Message queues
139 */
140typedef TAILQ_ENTRY(sscop_msg) sscop_msgq_link_t;
141typedef TAILQ_HEAD(sscop_msgq, sscop_msg) sscop_msgq_head_t;
142#define	MSGQ_EMPTY(Q)		TAILQ_EMPTY(Q)
143#define	MSGQ_INIT(Q)		TAILQ_INIT(Q)
144#define	MSGQ_FOREACH(P, Q)	TAILQ_FOREACH(P, Q, link)
145#define	MSGQ_REMOVE(Q, M)	TAILQ_REMOVE(Q, M, link)
146#define	MSGQ_INSERT_BEFORE(B, M) TAILQ_INSERT_BEFORE(B, M, link)
147#define	MSGQ_APPEND(Q, M)	TAILQ_INSERT_TAIL(Q, M, link)
148#define	MSGQ_PEEK(Q)		TAILQ_FIRST((Q))
149
150#define	MSGQ_GET(Q) ng_sscop_msgq_get((Q))
151
152#define DECL_MSGQ_GET							\
153static __inline struct sscop_msg *					\
154ng_sscop_msgq_get(struct sscop_msgq *q)					\
155{									\
156	struct sscop_msg *m;						\
157									\
158	m = TAILQ_FIRST(q);						\
159	if (m != NULL)							\
160		TAILQ_REMOVE(q, m, link);				\
161	return (m);							\
162}
163
164#define	MSGQ_CLEAR(Q)							\
165	do {								\
166		struct sscop_msg *_m1, *_m2;				\
167									\
168		_m1 = TAILQ_FIRST(Q);					\
169		while (_m1 != NULL) {					\
170			_m2 = TAILQ_NEXT(_m1, link);			\
171			SSCOP_MSG_FREE(_m1);				\
172			_m1 = _m2;					\
173		}							\
174		TAILQ_INIT((Q));					\
175	} while (0)
176
177/*
178 * Signal queues
179 */
180typedef TAILQ_ENTRY(sscop_sig) sscop_sigq_link_t;
181typedef TAILQ_HEAD(sscop_sigq, sscop_sig) sscop_sigq_head_t;
182#define	SIGQ_INIT(Q) 		TAILQ_INIT(Q)
183#define	SIGQ_APPEND(Q, S)	TAILQ_INSERT_TAIL(Q, S, link)
184#define	SIGQ_EMPTY(Q)		TAILQ_EMPTY(Q)
185
186#define	SIGQ_GET(Q)	ng_sscop_sigq_get((Q))
187#define	DECL_SIGQ_GET							\
188static __inline struct sscop_sig *					\
189ng_sscop_sigq_get(struct sscop_sigq *q)					\
190{									\
191	struct sscop_sig *s;						\
192									\
193	s = TAILQ_FIRST(q);						\
194	if (s != NULL)							\
195		TAILQ_REMOVE(q, s, link);				\
196	return (s);							\
197}
198
199#define	SIGQ_MOVE(F, T)							\
200    do {								\
201	struct sscop_sig *_s;						\
202									\
203	while (!TAILQ_EMPTY(F)) {					\
204		_s = TAILQ_FIRST(F);					\
205		TAILQ_REMOVE(F, _s, link);				\
206		TAILQ_INSERT_TAIL(T, _s, link);				\
207	}								\
208    } while (0)
209
210#define	SIGQ_PREPEND(F, T)						\
211    do {								\
212	struct sscop_sig *_s;						\
213									\
214	while (!TAILQ_EMPTY(F)) {					\
215		_s = TAILQ_LAST(F, sscop_sigq);				\
216		TAILQ_REMOVE(F, _s, link);				\
217		TAILQ_INSERT_HEAD(T, _s, link);				\
218	}								\
219    } while (0)
220
221#define	SIGQ_CLEAR(Q)							\
222    do {								\
223	struct sscop_sig *_s1, *_s2;					\
224									\
225	_s1 = TAILQ_FIRST(Q);						\
226	while (_s1 != NULL) {						\
227		_s2 = TAILQ_NEXT(_s1, link);				\
228		SSCOP_MSG_FREE(_s1->msg);				\
229		SIG_FREE(_s1);						\
230		_s1 = _s2;						\
231	}								\
232	TAILQ_INIT(Q);							\
233    } while (0)
234
235/*
236 * Message buffers
237 */
238#define	MBUF_FREE(M)	do { if ((M)) m_freem((M)); } while(0)
239#define	MBUF_DUP(M)	m_copypacket((M), M_NOWAIT)
240#define	MBUF_LEN(M) 	((size_t)(M)->m_pkthdr.len)
241
242/*
243 * Return the i-th word counted from the end of the buffer.
244 * i=-1 will return the last 32bit word, i=-2 the 2nd last.
245 * Assumes that there is enough space.
246 */
247#define	MBUF_TRAIL32(M ,I) ng_sscop_mbuf_trail32((M), (I))
248
249static uint32_t __inline
250ng_sscop_mbuf_trail32(const struct mbuf *m, int i)
251{
252	uint32_t w;
253
254	m_copydata(m, m->m_pkthdr.len + 4 * i, 4, (caddr_t)&w);
255	return (ntohl(w));
256}
257
258/*
259 * Strip 32bit value from the end
260 */
261#define	MBUF_STRIP32(M) ng_sscop_mbuf_strip32((M))
262
263static uint32_t __inline
264ng_sscop_mbuf_strip32(struct mbuf *m)
265{
266	uint32_t w;
267
268	m_copydata(m, m->m_pkthdr.len - 4, 4, (caddr_t)&w);
269	m_adj(m, -4);
270	return (ntohl(w));
271}
272
273#define	MBUF_GET32(M) ng_sscop_mbuf_get32((M))
274
275static uint32_t __inline
276ng_sscop_mbuf_get32(struct mbuf *m)
277{
278	uint32_t w;
279
280	m_copydata(m, 0, 4, (caddr_t)&w);
281	m_adj(m, 4);
282	return (ntohl(w));
283}
284
285/*
286 * Append a 32bit value to an mbuf. Failures are ignored.
287 */
288#define	MBUF_APPEND32(M, W)						\
289     do {								\
290	uint32_t _w = (W);						\
291									\
292	_w = htonl(_w);							\
293	m_copyback((M), (M)->m_pkthdr.len, 4, (caddr_t)&_w);		\
294    } while (0)
295
296/*
297 * Pad a message to a multiple of four byte and return the amount of padding
298 * Failures are ignored.
299 */
300#define	MBUF_PAD4(M) ng_sscop_mbuf_pad4((M))
301
302static u_int __inline
303ng_sscop_mbuf_pad4(struct mbuf *m)
304{
305	static u_char pad[4] = { 0, 0, 0, 0 };
306	int len = m->m_pkthdr.len;
307	int npad = 3 - ((len + 3) & 3);
308
309	if (npad != 0)
310		m_copyback(m, len, npad, (caddr_t)pad);
311	return (npad);
312}
313
314#define	MBUF_UNPAD(M, P) do { if( (P) > 0) m_adj((M), -(P)); } while (0)
315
316/*
317 * Allocate a message that will probably hold N bytes.
318 */
319#define	MBUF_ALLOC(N) ng_sscop_mbuf_alloc((N))
320
321#define	DECL_MBUF_ALLOC							\
322static __inline struct mbuf *						\
323ng_sscop_mbuf_alloc(size_t n)						\
324{									\
325	struct mbuf *m;							\
326									\
327	MGETHDR(m, M_NOWAIT, MT_DATA);					\
328	if (m != NULL) {						\
329		m->m_len = 0;						\
330		m->m_pkthdr.len = 0;					\
331		if (n > MHLEN) {					\
332			if (!(MCLGET(m, M_NOWAIT))){			\
333				m_free(m);				\
334				m = NULL;				\
335			}						\
336		}							\
337	}								\
338	return (m);							\
339}
340
341#ifdef SSCOP_DEBUG
342#define	ASSERT(X)	KASSERT(X, (#X))
343#else
344#define	ASSERT(X)
345#endif
346