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