xref: /haiku/src/libs/compat/freebsd_network/mbuf.c (revision 90eb65c9569a6f617c7a66b9d867e6c412d180b3)
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 <net_buffer.h>
15 
16 #include <compat/sys/malloc.h>
17 #include <compat/sys/mbuf.h>
18 #include <compat/sys/kernel.h>
19 
20 
21 static object_cache *sMBufCache;
22 static object_cache *sChunkCache;
23 static object_cache *sJumbo9ChunkCache;
24 static object_cache *sJumboPageSizeCache;
25 
26 
27 int max_linkhdr = 16;
28 int max_protohdr = 40 + 20; /* ip6 + tcp */
29 
30 /* max_linkhdr + max_protohdr, but that's not allowed by gcc. */
31 int max_hdr = 16 + 40 + 20;
32 
33 /* MHLEN - max_hdr */
34 int max_datalen = MHLEN - (16 + 40 + 20);
35 
36 
37 static int
m_to_oc_flags(int how)38 m_to_oc_flags(int how)
39 {
40 	if (how & M_NOWAIT)
41 		return CACHE_DONT_WAIT_FOR_MEMORY;
42 
43 	return 0;
44 }
45 
46 
47 int
m_init(struct mbuf * m,int how,short type,int flags)48 m_init(struct mbuf *m, int how, short type, int flags)
49 {
50 	int error;
51 
52 	if (type == MT_NOINIT)
53 		return 0;
54 
55 	m->m_next = NULL;
56 	m->m_nextpkt = NULL;
57 	m->m_data = m->m_dat;
58 	m->m_len = 0;
59 	m->m_flags = flags;
60 	m->m_type = type;
61 	if (flags & M_PKTHDR)
62 		error = m_pkthdr_init(m, how);
63 	else
64 		error = 0;
65 
66 	return (error);
67 }
68 
69 
70 static void*
allocate_ext_buf(int how,int size,int * ext_type)71 allocate_ext_buf(int how, int size, int* ext_type)
72 {
73 	object_cache *cache;
74 	int extType;
75 	if (size != MCLBYTES && size != MJUM9BYTES && size != MJUMPAGESIZE)
76 		panic("unsupported size");
77 
78 	if (size == MCLBYTES) {
79 		cache = sChunkCache;
80 		extType = EXT_CLUSTER;
81 	} else if (size == MJUM9BYTES) {
82 		cache = sJumbo9ChunkCache;
83 		extType = EXT_JUMBO9;
84 	} else {
85 		cache = sJumboPageSizeCache;
86 		extType = EXT_JUMBOP;
87 	}
88 
89 	if (ext_type != NULL)
90 		*ext_type = extType;
91 	return object_cache_alloc(cache, m_to_oc_flags(how));
92 }
93 
94 
95 static int
construct_ext_sized_mbuf(struct mbuf * memoryBuffer,int how,int size)96 construct_ext_sized_mbuf(struct mbuf *memoryBuffer, int how, int size)
97 {
98 	int extType;
99 
100 	memoryBuffer->m_ext.ext_buf = allocate_ext_buf(how, size, &extType);
101 	if (memoryBuffer->m_ext.ext_buf == NULL)
102 		return B_NO_MEMORY;
103 
104 	memoryBuffer->m_data = memoryBuffer->m_ext.ext_buf;
105 	memoryBuffer->m_flags |= M_EXT;
106 	memoryBuffer->m_ext.ext_size = size;
107 	memoryBuffer->m_ext.ext_type = extType;
108 	memoryBuffer->m_ext.ext_flags = EXT_FLAG_EMBREF;
109 	memoryBuffer->m_ext.ext_count = 1;
110 
111 	return 0;
112 }
113 
114 
115 static inline int
construct_ext_mbuf(struct mbuf * memoryBuffer,int how)116 construct_ext_mbuf(struct mbuf *memoryBuffer, int how)
117 {
118 	return construct_ext_sized_mbuf(memoryBuffer, how, MCLBYTES);
119 }
120 
121 
122 static int
construct_pkt_mbuf(int how,struct mbuf * memoryBuffer,short type,int flags)123 construct_pkt_mbuf(int how, struct mbuf *memoryBuffer, short type, int flags)
124 {
125 	if (m_init(memoryBuffer, how, type, flags) < 0)
126 		return -1;
127 	if (construct_ext_mbuf(memoryBuffer, how) < 0)
128 		return -1;
129 	memoryBuffer->m_ext.ext_type = EXT_CLUSTER;
130 	return 0;
131 }
132 
133 
134 struct mbuf *
m_getcl(int how,short type,int flags)135 m_getcl(int how, short type, int flags)
136 {
137 	struct mbuf *memoryBuffer =
138 		(struct mbuf *)object_cache_alloc(sMBufCache, m_to_oc_flags(how));
139 	if (memoryBuffer == NULL)
140 		return NULL;
141 
142 	if (construct_pkt_mbuf(how, memoryBuffer, type, flags) < 0) {
143 		object_cache_free(sMBufCache, memoryBuffer, 0);
144 		return NULL;
145 	}
146 
147 	return memoryBuffer;
148 }
149 
150 
151 static struct mbuf *
_m_get(int how,short type,int flags)152 _m_get(int how, short type, int flags)
153 {
154 	struct mbuf *memoryBuffer =
155 		(struct mbuf *)object_cache_alloc(sMBufCache, m_to_oc_flags(how));
156 	if (memoryBuffer == NULL)
157 		return NULL;
158 
159 	m_init(memoryBuffer, how, type, flags);
160 
161 	return memoryBuffer;
162 }
163 
164 
165 struct mbuf *
m_get(int how,short type)166 m_get(int how, short type)
167 {
168 	return _m_get(how, type, 0);
169 }
170 
171 
172 struct mbuf *
m_get2(int size,int how,short type,int flags)173 m_get2(int size, int how, short type, int flags)
174 {
175 	if (size <= MHLEN || (size <= MLEN && (flags & M_PKTHDR) == 0)) {
176 		return _m_get(how, type, flags);
177 	} else if (size <= MCLBYTES) {
178 		size = MCLBYTES;
179 	} else if (size <= MJUMPAGESIZE) {
180 		size = MJUMPAGESIZE;
181 	} else if (size <= MJUM9BYTES) {
182 		size = MJUM9BYTES;
183 	} else /* (size > MJUM9BYTES) */ {
184 		return NULL;
185 	}
186 
187 	return m_getjcl(how, type, flags, size);
188 }
189 
190 
191 struct mbuf *
m_gethdr(int how,short type)192 m_gethdr(int how, short type)
193 {
194 	return _m_get(how, type, M_PKTHDR);
195 }
196 
197 
198 struct mbuf *
m_getjcl(int how,short type,int flags,int size)199 m_getjcl(int how, short type, int flags, int size)
200 {
201 	struct mbuf *memoryBuffer =
202 		(struct mbuf *)object_cache_alloc(sMBufCache, m_to_oc_flags(how));
203 	if (memoryBuffer == NULL)
204 		return NULL;
205 	if (m_init(memoryBuffer, how, type, flags) < 0) {
206 		object_cache_free(sMBufCache, memoryBuffer, 0);
207 		return NULL;
208 	}
209 	if (construct_ext_sized_mbuf(memoryBuffer, how, size) < 0) {
210 		object_cache_free(sMBufCache, memoryBuffer, 0);
211 		return NULL;
212 	}
213 	return memoryBuffer;
214 }
215 
216 
217 int
m_clget(struct mbuf * memoryBuffer,int how)218 m_clget(struct mbuf *memoryBuffer, int how)
219 {
220 	memoryBuffer->m_ext.ext_buf = NULL;
221 	/* called checks for errors by looking for M_EXT */
222 	construct_ext_mbuf(memoryBuffer, how);
223 	return memoryBuffer->m_flags & M_EXT;
224 }
225 
226 
227 void*
m_cljget(struct mbuf * memoryBuffer,int how,int size)228 m_cljget(struct mbuf* memoryBuffer, int how, int size)
229 {
230 	if (memoryBuffer == NULL)
231 		return allocate_ext_buf(how, size, NULL);
232 
233 	memoryBuffer->m_ext.ext_buf = NULL;
234 	construct_ext_sized_mbuf(memoryBuffer, how, size);
235 	return memoryBuffer->m_ext.ext_buf;
236 }
237 
238 
239 static void
mb_free_ext(struct mbuf * memoryBuffer)240 mb_free_ext(struct mbuf *memoryBuffer)
241 {
242 	volatile u_int *refcnt;
243 	struct mbuf *mref;
244 	int freembuf;
245 
246 	KASSERT(memoryBuffer->m_flags & M_EXT, ("%s: M_EXT not set on %p",
247 		__func__, memoryBuffer));
248 
249 	/* See if this is the mbuf that holds the embedded refcount. */
250 	if (memoryBuffer->m_ext.ext_flags & EXT_FLAG_EMBREF) {
251 		refcnt = &memoryBuffer->m_ext.ext_count;
252 		mref = memoryBuffer;
253 	} else {
254 		KASSERT(memoryBuffer->m_ext.ext_cnt != NULL,
255 			("%s: no refcounting pointer on %p", __func__, memoryBuffer));
256 		refcnt = memoryBuffer->m_ext.ext_cnt;
257 		mref = __containerof(refcnt, struct mbuf, m_ext.ext_count);
258 	}
259 
260 	/*
261 	 * Check if the header is embedded in the cluster.  It is
262 	 * important that we can't touch any of the mbuf fields
263 	 * after we have freed the external storage, since mbuf
264 	 * could have been embedded in it.  For now, the mbufs
265 	 * embedded into the cluster are always of type EXT_EXTREF,
266 	 * and for this type we won't free the mref.
267 	 */
268 	if (memoryBuffer->m_flags & M_NOFREE) {
269 		freembuf = 0;
270 		KASSERT(memoryBuffer->m_ext.ext_type == EXT_EXTREF,
271 			("%s: no-free mbuf %p has wrong type", __func__, memoryBuffer));
272 	} else
273 		freembuf = 1;
274 
275 	/* Free attached storage only if this mbuf is the only reference to it. */
276 	if (*refcnt == 1 || atomic_add((int32*)refcnt, -1) == 1) {
277 		object_cache *cache = NULL;
278 
279 		if (memoryBuffer->m_ext.ext_type == EXT_CLUSTER)
280 			cache = sChunkCache;
281 		else if (memoryBuffer->m_ext.ext_type == EXT_JUMBO9)
282 			cache = sJumbo9ChunkCache;
283 		else if (memoryBuffer->m_ext.ext_type == EXT_JUMBOP)
284 			cache = sJumboPageSizeCache;
285 		else
286 			panic("unknown mbuf ext_type %d", memoryBuffer->m_ext.ext_type);
287 
288 		object_cache_free(cache, memoryBuffer->m_ext.ext_buf, 0);
289 		object_cache_free(sMBufCache, mref, 0);
290 	}
291 
292 	if (freembuf && memoryBuffer != mref)
293 		object_cache_free(sMBufCache, memoryBuffer, 0);
294 }
295 
296 
297 struct mbuf *
m_free(struct mbuf * memoryBuffer)298 m_free(struct mbuf* memoryBuffer)
299 {
300 	struct mbuf* next = memoryBuffer->m_next;
301 
302 	if ((memoryBuffer->m_flags & (M_PKTHDR|M_NOFREE)) == (M_PKTHDR|M_NOFREE))
303 		m_tag_delete_chain(memoryBuffer, NULL);
304 	if (memoryBuffer->m_flags & M_EXT)
305 		mb_free_ext(memoryBuffer);
306 	else if ((memoryBuffer->m_flags & M_NOFREE) == 0)
307 		object_cache_free(sMBufCache, memoryBuffer, 0);
308 
309 	return next;
310 }
311 
312 
313 status_t
init_mbufs()314 init_mbufs()
315 {
316 	status_t status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule);
317 	if (status != B_OK)
318 		goto clean;
319 
320 	sMBufCache = create_object_cache("mbufs", MSIZE, 8, NULL, NULL, NULL);
321 	if (sMBufCache == NULL)
322 		goto clean;
323 	sChunkCache = create_object_cache("mbuf chunks", MCLBYTES, 0, NULL, NULL,
324 		NULL);
325 	if (sChunkCache == NULL)
326 		goto clean;
327 	sJumbo9ChunkCache = create_object_cache("mbuf jumbo9 chunks", MJUM9BYTES, 0,
328 		NULL, NULL, NULL);
329 	if (sJumbo9ChunkCache == NULL)
330 		goto clean;
331 	sJumboPageSizeCache = create_object_cache("mbuf page size chunks",
332 		MJUMPAGESIZE, 0, NULL, NULL, NULL);
333 	if (sJumboPageSizeCache == NULL)
334 		goto clean;
335 	return B_OK;
336 
337 clean:
338 	if (sJumbo9ChunkCache != NULL)
339 		delete_object_cache(sJumbo9ChunkCache);
340 	if (sChunkCache != NULL)
341 		delete_object_cache(sChunkCache);
342 	if (sMBufCache != NULL)
343 		delete_object_cache(sMBufCache);
344 	put_module(NET_BUFFER_MODULE_NAME);
345 	return B_NO_MEMORY;
346 }
347 
348 
349 void
uninit_mbufs()350 uninit_mbufs()
351 {
352 	delete_object_cache(sMBufCache);
353 	delete_object_cache(sChunkCache);
354 	delete_object_cache(sJumbo9ChunkCache);
355 	delete_object_cache(sJumboPageSizeCache);
356 }
357