1/* 2 * Copyright (c) 1995 Danny Gasparovski 3 * 4 * Please read the file COPYRIGHT for the 5 * terms and conditions of the copyright. 6 */ 7 8/* 9 * mbuf's in SLiRP are much simpler than the real mbufs in 10 * FreeBSD. They are fixed size, determined by the MTU, 11 * so that one whole packet can fit. Mbuf's cannot be 12 * chained together. If there's more data than the mbuf 13 * could hold, an external malloced buffer is pointed to 14 * by m_ext (and the data pointers) and M_EXT is set in 15 * the flags 16 */ 17 18#include <slirp.h> 19 20int mbuf_alloced = 0; 21struct mbuf m_freelist, m_usedlist; 22#define MBUF_THRESH 30 23int mbuf_max = 0; 24 25/* 26 * Find a nice value for msize 27 * XXX if_maxlinkhdr already in mtu 28 */ 29#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + sizeof(struct m_hdr ) + 6) 30 31void 32m_init(void) 33{ 34 m_freelist.m_next = m_freelist.m_prev = &m_freelist; 35 m_usedlist.m_next = m_usedlist.m_prev = &m_usedlist; 36} 37 38/* 39 * Get an mbuf from the free list, if there are none 40 * malloc one 41 * 42 * Because fragmentation can occur if we alloc new mbufs and 43 * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE, 44 * which tells m_free to actually free() it 45 */ 46struct mbuf * 47m_get(void) 48{ 49 register struct mbuf *m; 50 int flags = 0; 51 52 DEBUG_CALL("m_get"); 53 54 if (m_freelist.m_next == &m_freelist) { 55 m = (struct mbuf *)malloc(SLIRP_MSIZE); 56 if (m == NULL) goto end_error; 57 mbuf_alloced++; 58 if (mbuf_alloced > MBUF_THRESH) 59 flags = M_DOFREE; 60 if (mbuf_alloced > mbuf_max) 61 mbuf_max = mbuf_alloced; 62 } else { 63 m = m_freelist.m_next; 64 remque(m); 65 } 66 67 /* Insert it in the used list */ 68 insque(m,&m_usedlist); 69 m->m_flags = (flags | M_USEDLIST); 70 71 /* Initialise it */ 72 m->m_size = SLIRP_MSIZE - sizeof(struct m_hdr); 73 m->m_data = m->m_dat; 74 m->m_len = 0; 75 m->m_nextpkt = NULL; 76 m->m_prevpkt = NULL; 77end_error: 78 DEBUG_ARG("m = %lx", (long )m); 79 return m; 80} 81 82void 83m_free(struct mbuf *m) 84{ 85 86 DEBUG_CALL("m_free"); 87 DEBUG_ARG("m = %lx", (long )m); 88 89 if(m) { 90 /* Remove from m_usedlist */ 91 if (m->m_flags & M_USEDLIST) 92 remque(m); 93 94 /* If it's M_EXT, free() it */ 95 if (m->m_flags & M_EXT) 96 free(m->m_ext); 97 98 /* 99 * Either free() it or put it on the free list 100 */ 101 if (m->m_flags & M_DOFREE) { 102 free(m); 103 mbuf_alloced--; 104 } else if ((m->m_flags & M_FREELIST) == 0) { 105 insque(m,&m_freelist); 106 m->m_flags = M_FREELIST; /* Clobber other flags */ 107 } 108 } /* if(m) */ 109} 110 111/* 112 * Copy data from one mbuf to the end of 113 * the other.. if result is too big for one mbuf, malloc() 114 * an M_EXT data segment 115 */ 116void 117m_cat(struct mbuf *m, struct mbuf *n) 118{ 119 /* 120 * If there's no room, realloc 121 */ 122 if (M_FREEROOM(m) < n->m_len) 123 m_inc(m,m->m_size+MINCSIZE); 124 125 memcpy(m->m_data+m->m_len, n->m_data, n->m_len); 126 m->m_len += n->m_len; 127 128 m_free(n); 129} 130 131 132/* make m size bytes large */ 133void 134m_inc(struct mbuf *m, int size) 135{ 136 int datasize; 137 138 /* some compiles throw up on gotos. This one we can fake. */ 139 if(m->m_size>size) return; 140 141 if (m->m_flags & M_EXT) { 142 datasize = m->m_data - m->m_ext; 143 m->m_ext = (char *)realloc(m->m_ext,size); 144/* if (m->m_ext == NULL) 145 * return (struct mbuf *)NULL; 146 */ 147 m->m_data = m->m_ext + datasize; 148 } else { 149 char *dat; 150 datasize = m->m_data - m->m_dat; 151 dat = (char *)malloc(size); 152/* if (dat == NULL) 153 * return (struct mbuf *)NULL; 154 */ 155 memcpy(dat, m->m_dat, m->m_size); 156 157 m->m_ext = dat; 158 m->m_data = m->m_ext + datasize; 159 m->m_flags |= M_EXT; 160 } 161 162 m->m_size = size; 163 164} 165 166 167 168void 169m_adj(struct mbuf *m, int len) 170{ 171 if (m == NULL) 172 return; 173 if (len >= 0) { 174 /* Trim from head */ 175 m->m_data += len; 176 m->m_len -= len; 177 } else { 178 /* Trim from tail */ 179 len = -len; 180 m->m_len -= len; 181 } 182} 183 184 185/* 186 * Copy len bytes from m, starting off bytes into n 187 */ 188int 189m_copy(struct mbuf *n, struct mbuf *m, int off, int len) 190{ 191 if (len > M_FREEROOM(n)) 192 return -1; 193 194 memcpy((n->m_data + n->m_len), (m->m_data + off), len); 195 n->m_len += len; 196 return 0; 197} 198 199 200/* 201 * Given a pointer into an mbuf, return the mbuf 202 * XXX This is a kludge, I should eliminate the need for it 203 * Fortunately, it's not used often 204 */ 205struct mbuf * 206dtom(void *dat) 207{ 208 struct mbuf *m; 209 210 DEBUG_CALL("dtom"); 211 DEBUG_ARG("dat = %lx", (long )dat); 212 213 /* bug corrected for M_EXT buffers */ 214 for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) { 215 if (m->m_flags & M_EXT) { 216 if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) ) 217 return m; 218 } else { 219 if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) ) 220 return m; 221 } 222 } 223 224 DEBUG_ERROR((dfd, "dtom failed")); 225 226 return (struct mbuf *)0; 227} 228