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