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 20 int mbuf_alloced = 0; 21 struct mbuf m_freelist, m_usedlist; 22 #define MBUF_THRESH 30 23 int 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 31 void 32 m_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 */ 46 struct mbuf * 47 m_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; 77 end_error: 78 DEBUG_ARG("m = %lx", (long )m); 79 return m; 80 } 81 82 void 83 m_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 */ 116 void 117 m_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 */ 133 void 134 m_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 168 void 169 m_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 */ 188 int 189 m_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 */ 205 struct mbuf * 206 dtom(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