1 /* 2 * Copyright 2007, Hugo Santos. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Hugo Santos, hugosantos@gmail.com 7 * 8 * Some of this code is based on previous work by Marcus Overhagen. 9 * 10 * `m_defrag' and friends are straight from FreeBSD 6.2. 11 */ 12 13 #include "device.h" 14 15 #include <stdint.h> 16 #include <string.h> 17 #include <slab/Slab.h> 18 19 #include <compat/sys/mbuf.h> 20 #include <compat/sys/kernel.h> 21 22 static object_cache *sMBufCache; 23 static object_cache *sChunkCache; 24 25 int max_linkhdr = 16; 26 int max_protohdr = 40 + 20; /* ip6 + tcp */ 27 28 29 static int 30 m_to_oc_flags(int how) 31 { 32 if (how & M_NOWAIT) 33 return CACHE_DONT_SLEEP; 34 35 return 0; 36 } 37 38 39 static int 40 construct_mbuf(struct mbuf *mb, short type, int flags) 41 { 42 mb->m_next = NULL; 43 mb->m_nextpkt = NULL; 44 mb->m_len = 0; 45 mb->m_flags = flags; 46 mb->m_type = type; 47 48 if (flags & M_PKTHDR) { 49 mb->m_data = mb->m_pktdat; 50 memset(&mb->m_pkthdr, 0, sizeof(mb->m_pkthdr)); 51 /* SLIST_INIT(&m->m_pkthdr.tags); */ 52 } else { 53 mb->m_data = mb->m_dat; 54 } 55 56 return 0; 57 } 58 59 60 static int 61 construct_ext_mbuf(struct mbuf *mb, int how) 62 { 63 mb->m_ext.ext_buf = object_cache_alloc(sChunkCache, m_to_oc_flags(how)); 64 if (mb->m_ext.ext_buf == NULL) 65 return B_NO_MEMORY; 66 67 mb->m_data = mb->m_ext.ext_buf; 68 mb->m_flags |= M_EXT; 69 /* mb->m_ext.ext_free = NULL; */ 70 /* mb->m_ext.ext_args = NULL; */ 71 mb->m_ext.ext_size = MCLBYTES; 72 mb->m_ext.ext_type = EXT_CLUSTER; 73 /* mb->m_ext.ref_cnt = NULL; */ 74 75 return 0; 76 } 77 78 79 static int 80 construct_pkt_mbuf(int how, struct mbuf *mb, short type, int flags) 81 { 82 construct_mbuf(mb, type, flags); 83 if (construct_ext_mbuf(mb, how) < 0) 84 return -1; 85 mb->m_ext.ext_type = EXT_PACKET; 86 return 0; 87 } 88 89 90 static void 91 destruct_pkt_mbuf(struct mbuf *mb) 92 { 93 object_cache_free(sChunkCache, mb->m_ext.ext_buf); 94 mb->m_ext.ext_buf = NULL; 95 } 96 97 98 struct mbuf * 99 m_getcl(int how, short type, int flags) 100 { 101 struct mbuf *mb = 102 (struct mbuf *)object_cache_alloc(sMBufCache, m_to_oc_flags(how)); 103 if (mb == NULL) 104 return NULL; 105 106 if (construct_pkt_mbuf(how, mb, type, flags) < 0) { 107 object_cache_free(sMBufCache, mb); 108 return NULL; 109 } 110 111 return mb; 112 } 113 114 115 static struct mbuf * 116 _m_get(int how, short type, int flags) 117 { 118 struct mbuf *mb = 119 (struct mbuf *)object_cache_alloc(sMBufCache, m_to_oc_flags(how)); 120 if (mb == NULL) 121 return NULL; 122 123 construct_mbuf(mb, type, flags); 124 125 return mb; 126 } 127 128 129 struct mbuf * 130 m_get(int how, short type) 131 { 132 return _m_get(how, type, 0); 133 } 134 135 136 struct mbuf * 137 m_gethdr(int how, short type) 138 { 139 return _m_get(how, type, M_PKTHDR); 140 } 141 142 143 void 144 m_clget(struct mbuf *m, int how) 145 { 146 m->m_ext.ext_buf = NULL; 147 /* called checks for errors by looking for M_EXT */ 148 construct_ext_mbuf(m, how); 149 } 150 151 152 void 153 m_freem(struct mbuf *mb) 154 { 155 while (mb) 156 mb = m_free(mb); 157 } 158 159 160 static void 161 mb_free_ext(struct mbuf *m) 162 { 163 /* 164 if (m->m_ext.ref_count != NULL) 165 panic("unsupported"); 166 */ 167 168 if (m->m_ext.ext_type == EXT_PACKET) 169 destruct_pkt_mbuf(m); 170 else if (m->m_ext.ext_type == EXT_CLUSTER) { 171 object_cache_free(sChunkCache, m->m_ext.ext_buf); 172 m->m_ext.ext_buf = NULL; 173 } else 174 panic("unknown type"); 175 176 object_cache_free(sMBufCache, m); 177 } 178 179 180 struct mbuf * 181 m_free(struct mbuf *m) 182 { 183 struct mbuf *next = m->m_next; 184 185 if (m->m_flags & M_EXT) 186 mb_free_ext(m); 187 else 188 object_cache_free(sMBufCache, m); 189 190 return next; 191 } 192 193 194 void 195 m_extadd(struct mbuf *m, caddr_t buffer, u_int size, 196 void (*freeHook)(void *, void *), void *args, int flags, int type) 197 { 198 // TODO: implement? 199 panic("m_extadd() called."); 200 } 201 202 203 status_t 204 init_mbufs() 205 { 206 sMBufCache = create_object_cache("mbufs", MSIZE, 8, NULL, NULL, NULL); 207 if (sMBufCache == NULL) 208 return B_NO_MEMORY; 209 210 sChunkCache = create_object_cache("mbuf chunks", MCLBYTES, 0, NULL, NULL, 211 NULL); 212 if (sChunkCache == NULL) { 213 delete_object_cache(sMBufCache); 214 return B_NO_MEMORY; 215 } 216 217 return B_OK; 218 } 219 220 221 void 222 uninit_mbufs() 223 { 224 delete_object_cache(sMBufCache); 225 delete_object_cache(sChunkCache); 226 } 227 228