1/*
2 * Copyright 2007, Hugo Santos. All Rights Reserved.
3 * Copyright 2004, Marcus Overhagen. All Rights Reserved.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "device.h"
9
10#include <stdint.h>
11#include <string.h>
12#include <slab/Slab.h>
13
14#include <compat/sys/malloc.h>
15#include <compat/sys/mbuf.h>
16#include <compat/sys/kernel.h>
17
18
19static object_cache *sMBufCache;
20static object_cache *sChunkCache;
21static object_cache *sJumbo9ChunkCache;
22static object_cache *sJumboPageSizeCache;
23
24
25int max_linkhdr = 16;
26int max_protohdr = 40 + 20; /* ip6 + tcp */
27
28/* max_linkhdr + max_protohdr, but that's not allowed by gcc. */
29int max_hdr = 16 + 40 + 20;
30
31/* MHLEN - max_hdr */
32int max_datalen = MHLEN - (16 + 40 + 20);
33
34
35static int
36m_to_oc_flags(int how)
37{
38	if (how & M_NOWAIT)
39		return CACHE_DONT_WAIT_FOR_MEMORY;
40
41	return 0;
42}
43
44
45static int
46construct_mbuf(struct mbuf *memoryBuffer, short type, int flags)
47{
48	memoryBuffer->m_next = NULL;
49	memoryBuffer->m_nextpkt = NULL;
50	memoryBuffer->m_len = 0;
51	memoryBuffer->m_flags = flags;
52	memoryBuffer->m_type = type;
53
54	if (flags & M_PKTHDR) {
55		memoryBuffer->m_data = memoryBuffer->m_pktdat;
56		memset(&memoryBuffer->m_pkthdr, 0, sizeof(memoryBuffer->m_pkthdr));
57		SLIST_INIT(&memoryBuffer->m_pkthdr.tags);
58	} else {
59		memoryBuffer->m_data = memoryBuffer->m_dat;
60	}
61
62	return 0;
63}
64
65
66static int
67construct_ext_sized_mbuf(struct mbuf *memoryBuffer, int how, int size)
68{
69	object_cache *cache;
70	int extType;
71	if (size != MCLBYTES && size != MJUM9BYTES && size != MJUMPAGESIZE)
72		panic("unsupported size");
73
74	if (size == MCLBYTES) {
75		cache = sChunkCache;
76		extType = EXT_CLUSTER;
77	} else if (size == MJUM9BYTES) {
78		cache = sJumbo9ChunkCache;
79		extType = EXT_JUMBO9;
80	} else {
81		cache = sJumboPageSizeCache;
82		extType = EXT_JUMBOP;
83	}
84
85	memoryBuffer->m_ext.ext_buf = object_cache_alloc(cache, m_to_oc_flags(how));
86	if (memoryBuffer->m_ext.ext_buf == NULL)
87		return B_NO_MEMORY;
88
89	memoryBuffer->m_data = memoryBuffer->m_ext.ext_buf;
90	memoryBuffer->m_flags |= M_EXT;
91	/* mb->m_ext.ext_free = NULL; */
92	/* mb->m_ext.ext_args = NULL; */
93	memoryBuffer->m_ext.ext_size = size;
94	memoryBuffer->m_ext.ext_type = extType;
95	/* mb->m_ext.ref_cnt = NULL; */
96
97	return 0;
98}
99
100
101static inline int
102construct_ext_mbuf(struct mbuf *memoryBuffer, int how)
103{
104	return construct_ext_sized_mbuf(memoryBuffer, how, MCLBYTES);
105}
106
107
108static int
109construct_pkt_mbuf(int how, struct mbuf *memoryBuffer, short type, int flags)
110{
111	construct_mbuf(memoryBuffer, type, flags);
112	if (construct_ext_mbuf(memoryBuffer, how) < 0)
113		return -1;
114	memoryBuffer->m_ext.ext_type = EXT_CLUSTER;
115	return 0;
116}
117
118
119struct mbuf *
120m_getcl(int how, short type, int flags)
121{
122	struct mbuf *memoryBuffer =
123		(struct mbuf *)object_cache_alloc(sMBufCache, m_to_oc_flags(how));
124	if (memoryBuffer == NULL)
125		return NULL;
126
127	if (construct_pkt_mbuf(how, memoryBuffer, type, flags) < 0) {
128		object_cache_free(sMBufCache, memoryBuffer, 0);
129		return NULL;
130	}
131
132	return memoryBuffer;
133}
134
135
136static struct mbuf *
137_m_get(int how, short type, int flags)
138{
139	struct mbuf *memoryBuffer =
140		(struct mbuf *)object_cache_alloc(sMBufCache, m_to_oc_flags(how));
141	if (memoryBuffer == NULL)
142		return NULL;
143
144	construct_mbuf(memoryBuffer, type, flags);
145
146	return memoryBuffer;
147}
148
149
150struct mbuf *
151m_get(int how, short type)
152{
153	return _m_get(how, type, 0);
154}
155
156
157struct mbuf *
158m_gethdr(int how, short type)
159{
160	return _m_get(how, type, M_PKTHDR);
161}
162
163
164struct mbuf *
165m_getjcl(int how, short type, int flags, int size)
166{
167	struct mbuf *memoryBuffer =
168		(struct mbuf *)object_cache_alloc(sMBufCache, m_to_oc_flags(how));
169	if (memoryBuffer == NULL)
170		return NULL;
171	construct_mbuf(memoryBuffer, type, flags);
172	if (construct_ext_sized_mbuf(memoryBuffer, how, size) < 0) {
173		object_cache_free(sMBufCache, memoryBuffer, 0);
174		return NULL;
175	}
176	return memoryBuffer;
177}
178
179
180void
181m_clget(struct mbuf *memoryBuffer, int how)
182{
183	memoryBuffer->m_ext.ext_buf = NULL;
184	/* called checks for errors by looking for M_EXT */
185	construct_ext_mbuf(memoryBuffer, how);
186}
187
188
189void *
190m_cljget(struct mbuf *memoryBuffer, int how, int size)
191{
192	if (memoryBuffer == NULL)
193		panic("m_cljget doesn't support allocate mbuf");
194	memoryBuffer->m_ext.ext_buf = NULL;
195	construct_ext_sized_mbuf(memoryBuffer, how, size);
196	/* shouldn't be used */
197	return NULL;
198}
199
200
201void
202m_freem(struct mbuf *memoryBuffer)
203{
204	while (memoryBuffer)
205		memoryBuffer = m_free(memoryBuffer);
206}
207
208
209static void
210mb_free_ext(struct mbuf *memoryBuffer)
211{
212	/*
213	if (m->m_ext.ref_count != NULL)
214		panic("unsupported");
215	*/
216
217	object_cache *cache = NULL;
218
219	if (memoryBuffer->m_ext.ext_type == EXT_CLUSTER)
220		cache = sChunkCache;
221	else if (memoryBuffer->m_ext.ext_type == EXT_JUMBO9)
222		cache = sJumbo9ChunkCache;
223	else if (memoryBuffer->m_ext.ext_type == EXT_JUMBOP)
224		cache = sJumboPageSizeCache;
225	else
226		panic("unknown type");
227
228	object_cache_free(cache, memoryBuffer->m_ext.ext_buf, 0);
229	memoryBuffer->m_ext.ext_buf = NULL;
230	object_cache_free(sMBufCache, memoryBuffer, 0);
231}
232
233
234struct mbuf *
235m_free(struct mbuf *memoryBuffer)
236{
237	struct mbuf *next = memoryBuffer->m_next;
238
239	if (memoryBuffer->m_flags & M_EXT)
240		mb_free_ext(memoryBuffer);
241	else
242		object_cache_free(sMBufCache, memoryBuffer, 0);
243
244	return next;
245}
246
247
248// TODO once all driver are updated to FreeBSD 8 this can be changed
249#if __FreeBSD_version__ >= 8
250m_extadd(struct mbuf *memoryBuffer, caddr_t buffer, u_int size,
251    void (*freeHook)(void *, void *), void *arg1, void *arg2, int flags, int type)
252{
253	// TODO: implement?
254	panic("m_extadd() called.");
255}
256#else
257void
258m_extadd(struct mbuf *memoryBuffer, caddr_t buffer, u_int size,
259    void (*freeHook)(void *, void *), void *args, int flags, int type)
260{
261	// TODO: implement?
262	panic("m_extadd() called.");
263}
264#endif
265
266
267status_t
268init_mbufs()
269{
270	sMBufCache = create_object_cache("mbufs", MSIZE, 8, NULL, NULL, NULL);
271	if (sMBufCache == NULL)
272		goto clean;
273	sChunkCache = create_object_cache("mbuf chunks", MCLBYTES, 0, NULL, NULL,
274		NULL);
275	if (sChunkCache == NULL)
276		goto clean;
277	sJumbo9ChunkCache = create_object_cache("mbuf jumbo9 chunks", MJUM9BYTES, 0,
278		NULL, NULL, NULL);
279	if (sJumbo9ChunkCache == NULL)
280		goto clean;
281	sJumboPageSizeCache = create_object_cache("mbuf jumbo page size chunks",
282		MJUMPAGESIZE, 0, NULL, NULL, NULL);
283	if (sJumboPageSizeCache == NULL)
284		goto clean;
285	return B_OK;
286
287clean:
288	if (sJumbo9ChunkCache != NULL)
289		delete_object_cache(sJumbo9ChunkCache);
290	if (sChunkCache != NULL)
291		delete_object_cache(sChunkCache);
292	if (sMBufCache != NULL)
293		delete_object_cache(sMBufCache);
294	return B_NO_MEMORY;
295}
296
297
298void
299uninit_mbufs()
300{
301	delete_object_cache(sMBufCache);
302	delete_object_cache(sChunkCache);
303	delete_object_cache(sJumbo9ChunkCache);
304	delete_object_cache(sJumboPageSizeCache);
305}
306