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