xref: /haiku/src/libs/compat/freebsd_network/mbuf.c (revision 7749d0bb0c358a3279b1b9cc76d8376e900130a5)
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 
19 static object_cache *sMBufCache;
20 static object_cache *sChunkCache;
21 static object_cache *sJumbo9ChunkCache;
22 static object_cache *sJumboPageSizeCache;
23 
24 
25 int max_linkhdr = 16;
26 int max_protohdr = 40 + 20; /* ip6 + tcp */
27 
28 /* max_linkhdr + max_protohdr, but that's not allowed by gcc. */
29 int max_hdr = 16 + 40 + 20;
30 
31 /* MHLEN - max_hdr */
32 int max_datalen = MHLEN - (16 + 40 + 20);
33 
34 
35 static int
36 m_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 
45 static int
46 construct_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 
66 static int
67 construct_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 
101 static inline int
102 construct_ext_mbuf(struct mbuf *memoryBuffer, int how)
103 {
104 	return construct_ext_sized_mbuf(memoryBuffer, how, MCLBYTES);
105 }
106 
107 
108 static int
109 construct_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 
119 struct mbuf *
120 m_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 
136 static 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 
150 struct mbuf *
151 m_get(int how, short type)
152 {
153 	return _m_get(how, type, 0);
154 }
155 
156 
157 struct mbuf *
158 m_gethdr(int how, short type)
159 {
160 	return _m_get(how, type, M_PKTHDR);
161 }
162 
163 
164 struct mbuf *
165 m_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 
180 void
181 m_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 
189 void *
190 m_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 
201 void
202 m_freem(struct mbuf *memoryBuffer)
203 {
204 	while (memoryBuffer)
205 		memoryBuffer = m_free(memoryBuffer);
206 }
207 
208 
209 static void
210 mb_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 
234 struct mbuf *
235 m_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
250 m_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
257 void
258 m_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 
267 status_t
268 init_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 
287 clean:
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 
298 void
299 uninit_mbufs()
300 {
301 	delete_object_cache(sMBufCache);
302 	delete_object_cache(sChunkCache);
303 	delete_object_cache(sJumbo9ChunkCache);
304 	delete_object_cache(sJumboPageSizeCache);
305 }
306