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