VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/misc.c@ 45322

Last change on this file since 45322 was 45089, checked in by vboxsync, 12 years ago

backed out: r84371 and r84372, need to investiagte in Linux case for a moment.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.7 KB
Line 
1/* $Id: misc.c 45089 2013-03-19 11:26:12Z vboxsync $ */
2/** @file
3 * NAT - helpers.
4 */
5
6/*
7 * Copyright (C) 2006-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*
19 * This code is based on:
20 *
21 * Copyright (c) 1995 Danny Gasparovski.
22 *
23 * Please read the file COPYRIGHT for the
24 * terms and conditions of the copyright.
25 */
26
27#ifndef VBOX_NAT_TST_QUEUE
28#include <slirp.h>
29#include "zone.h"
30
31# ifndef HAVE_INET_ATON
32int
33inet_aton(const char *cp, struct in_addr *ia)
34{
35 u_int32_t addr = inet_addr(cp);
36 if (addr == 0xffffffff)
37 return 0;
38 ia->s_addr = addr;
39 return 1;
40}
41# endif
42
43/*
44 * Get our IP address and put it in our_addr
45 */
46void
47getouraddr(PNATState pData)
48{
49 our_addr.s_addr = loopback_addr.s_addr;
50}
51#else /* VBOX_NAT_TST_QUEUE */
52# include <iprt/cdefs.h>
53# include <iprt/types.h>
54# include "misc.h"
55#endif
56struct quehead
57{
58 struct quehead *qh_link;
59 struct quehead *qh_rlink;
60};
61
62void
63insque(PNATState pData, void *a, void *b)
64{
65 register struct quehead *element = (struct quehead *) a;
66 register struct quehead *head = (struct quehead *) b;
67 NOREF(pData);
68 element->qh_link = head->qh_link;
69 head->qh_link = (struct quehead *)element;
70 element->qh_rlink = (struct quehead *)head;
71 ((struct quehead *)(element->qh_link))->qh_rlink = (struct quehead *)element;
72}
73
74void
75remque(PNATState pData, void *a)
76{
77 register struct quehead *element = (struct quehead *) a;
78 NOREF(pData);
79 ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
80 ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
81 element->qh_rlink = NULL;
82 /* element->qh_link = NULL; TCP FIN1 crashes if you do this. Why ? */
83}
84
85#ifndef VBOX_NAT_TST_QUEUE
86/*
87 * Set fd blocking and non-blocking
88 */
89void
90fd_nonblock(int fd)
91{
92# ifdef FIONBIO
93 int opt = 1;
94
95 ioctlsocket(fd, FIONBIO, &opt);
96# else /* !FIONBIO */
97 int opt;
98
99 opt = fcntl(fd, F_GETFL, 0);
100 opt |= O_NONBLOCK;
101 fcntl(fd, F_SETFL, opt);
102# endif
103}
104
105# if !defined(VBOX_NAT_MEM_DEBUG)
106# if defined (LOG_ENABLED)
107# undef LogFlowFunc
108# define LogFlowFunc(x)
109
110# undef LogFlowFuncEnter
111# define LogFlowFuncEnter()
112
113# undef LogFlowFuncLeave
114# define LogFlowFuncLeave()
115
116# undef Log2
117# define Log2(x)
118# endif /* !LOG_ENABLED */
119# else /* VBOX_NAT_MEM_DEBUG */
120# define NAT_MEM_LOG_ENABLED
121# endif
122
123
124/**
125 * Called when memory becomes available, works pfnXmitPending.
126 *
127 * @note This will LEAVE the critical section of the zone and RE-ENTER it
128 * again. Changes to the zone data should be expected across calls to
129 * this function!
130 *
131 * @param zone The zone.
132 */
133DECLINLINE(void) slirp_zone_check_and_send_pending(uma_zone_t zone)
134{
135 LogFlowFunc(("ENTER: zone:%R[mzone]\n", zone));
136 if ( zone->fDoXmitPending
137 && zone->master_zone == NULL)
138 {
139 int rc2;
140 zone->fDoXmitPending = false;
141 rc2 = RTCritSectLeave(&zone->csZone); AssertRC(rc2);
142
143 slirp_output_pending(zone->pData->pvUser);
144
145 rc2 = RTCritSectEnter(&zone->csZone); AssertRC(rc2);
146 }
147 LogFlowFuncLeave();
148}
149
150static void *slirp_uma_alloc(uma_zone_t zone,
151 int size, uint8_t *pflags, int fWait)
152{
153 struct item *it;
154 uint8_t *sub_area;
155 void *ret = NULL;
156 int rc;
157
158 LogFlowFunc(("ENTER: %R[mzone], size:%d, pflags:%p, %RTbool\n", zone, size, pflags, fWait));
159# ifndef NAT_MEM_LOG_ENABLED
160 NOREF(size);
161 NOREF(pflags);
162 NOREF(fWait);
163# endif
164 RTCritSectEnter(&zone->csZone);
165 for (;;)
166 {
167 if (!LIST_EMPTY(&zone->free_items))
168 {
169 it = LIST_FIRST(&zone->free_items);
170 Assert(it->magic == ITEM_MAGIC);
171 rc = 0;
172 if (zone->pfInit)
173 rc = zone->pfInit(zone->pData, (void *)&it[1], zone->size, M_DONTWAIT);
174 if (rc == 0)
175 {
176 zone->cur_items++;
177 LIST_REMOVE(it, list);
178 LIST_INSERT_HEAD(&zone->used_items, it, list);
179 slirp_zone_check_and_send_pending(zone); /* may exit+enter the cs! */
180 ret = (void *)&it[1];
181 }
182 else
183 {
184 AssertMsgFailed(("NAT: item initialization failed for zone %s\n", zone->name));
185 ret = NULL;
186 }
187 break;
188 }
189
190 if (!zone->master_zone)
191 {
192 /* We're on the master zone and we can't allocate more. */
193 Log2(("NAT: no room on %s zone\n", zone->name));
194 /* AssertMsgFailed(("NAT: OOM!")); */
195 zone->fDoXmitPending = true;
196 break;
197 }
198
199 /* we're on a sub-zone, we need get a chunk from the master zone and split
200 * it into sub-zone conforming chunks.
201 */
202 sub_area = slirp_uma_alloc(zone->master_zone, zone->master_zone->size, NULL, 0);
203 if (!sub_area)
204 {
205 /* No room on master */
206 Log2(("NAT: no room on %s zone for %s zone\n", zone->master_zone->name, zone->name));
207 break;
208 }
209 zone->max_items++;
210 it = &((struct item *)sub_area)[-1];
211 /* It's the chunk descriptor of the master zone, we should remove it
212 * from the master list first.
213 */
214 Assert((it->zone && it->zone->magic == ZONE_MAGIC));
215 RTCritSectEnter(&it->zone->csZone);
216 /** @todo should we alter count of master counters? */
217 LIST_REMOVE(it, list);
218 RTCritSectLeave(&it->zone->csZone);
219
220 /** @todo '+ zone->size' should be depend on flag */
221 memset(it, 0, sizeof(struct item));
222 it->zone = zone;
223 it->magic = ITEM_MAGIC;
224 LIST_INSERT_HEAD(&zone->free_items, it, list);
225 if (zone->cur_items >= zone->max_items)
226 LogRel(("NAT: zone(%s) has reached it maximum\n", zone->name));
227 }
228 RTCritSectLeave(&zone->csZone);
229 LogFlowFunc(("LEAVE: %p\n", ret));
230 return ret;
231}
232
233static void slirp_uma_free(void *item, int size, uint8_t flags)
234{
235 struct item *it;
236 uma_zone_t zone;
237# ifndef NAT_MEM_LOG_ENABLED
238 NOREF(size);
239 NOREF(flags);
240# endif
241
242 Assert(item);
243 it = &((struct item *)item)[-1];
244 LogFlowFunc(("ENTER: item:%p(%R[mzoneitem]), size:%d, flags:%RX8\n", item, it, size, flags));
245 Assert(it->magic == ITEM_MAGIC);
246 zone = it->zone;
247 /* check border magic */
248 Assert((*(uint32_t *)(((uint8_t *)&it[1]) + zone->size) == 0xabadbabe));
249
250 RTCritSectEnter(&zone->csZone);
251 Assert(zone->magic == ZONE_MAGIC);
252 LIST_REMOVE(it, list);
253 if (zone->pfFini)
254 {
255 zone->pfFini(zone->pData, item, zone->size);
256 }
257 if (zone->pfDtor)
258 {
259 zone->pfDtor(zone->pData, item, zone->size, NULL);
260 }
261 LIST_INSERT_HEAD(&zone->free_items, it, list);
262 zone->cur_items--;
263 slirp_zone_check_and_send_pending(zone); /* may exit+enter the cs! */
264 RTCritSectLeave(&zone->csZone);
265 LogFlowFuncLeave();
266}
267
268uma_zone_t uma_zcreate(PNATState pData, char *name, size_t size,
269 ctor_t ctor, dtor_t dtor, zinit_t init, zfini_t fini, int flags1, int flags2)
270{
271 uma_zone_t zone = NULL;
272# ifndef NAT_MEM_LOG_ENABLED
273 NOREF(flags1);
274 NOREF(flags2);
275# endif
276 LogFlowFunc(("ENTER: name:%s size:%d, ctor:%p, dtor:%p, init:%p, fini:%p, flags1:%RX32, flags2:%RX32\n",
277 name, ctor, dtor, init, fini, flags1, flags2));
278 zone = RTMemAllocZ(sizeof(struct uma_zone));
279 Assert((pData));
280 zone->magic = ZONE_MAGIC;
281 zone->pData = pData;
282 zone->name = name;
283 zone->size = size;
284 zone->pfCtor = ctor;
285 zone->pfDtor = dtor;
286 zone->pfInit = init;
287 zone->pfFini = fini;
288 zone->pfAlloc = slirp_uma_alloc;
289 zone->pfFree = slirp_uma_free;
290 RTCritSectInit(&zone->csZone);
291 LogFlowFunc(("LEAVE: %R[mzone]\n", zone));
292 return zone;
293
294}
295uma_zone_t uma_zsecond_create(char *name, ctor_t ctor,
296 dtor_t dtor, zinit_t init, zfini_t fini, uma_zone_t master)
297{
298 uma_zone_t zone;
299 Assert(master);
300 LogFlowFunc(("ENTER: name:%s ctor:%p, dtor:%p, init:%p, fini:%p, master:%R[mzone]\n",
301 name, ctor, dtor, init, fini, master));
302 zone = RTMemAllocZ(sizeof(struct uma_zone));
303 if (zone == NULL)
304 {
305 LogFlowFunc(("LEAVE: %R[mzone]\n", NULL));
306 return NULL;
307 }
308
309 Assert((master && master->pData));
310 zone->magic = ZONE_MAGIC;
311 zone->pData = master->pData;
312 zone->name = name;
313 zone->pfCtor = ctor;
314 zone->pfDtor = dtor;
315 zone->pfInit = init;
316 zone->pfFini = fini;
317 zone->pfAlloc = slirp_uma_alloc;
318 zone->pfFree = slirp_uma_free;
319 zone->size = master->size;
320 zone->master_zone = master;
321 RTCritSectInit(&zone->csZone);
322 LogFlowFunc(("LEAVE: %R[mzone]\n", zone));
323 return zone;
324}
325
326void uma_zone_set_max(uma_zone_t zone, int max)
327{
328 int i = 0;
329 struct item *it;
330 LogFlowFunc(("ENTER: zone:%R[mzone], max:%d\n", zone, max));
331 zone->max_items = max;
332 zone->area = RTMemAllocZ(max * (sizeof(struct item) + zone->size + sizeof(uint32_t)));
333 for (; i < max; ++i)
334 {
335 it = (struct item *)(((uint8_t *)zone->area) + i*(sizeof(struct item) + zone->size + sizeof(uint32_t)));
336 it->magic = ITEM_MAGIC;
337 it->zone = zone;
338 *(uint32_t *)(((uint8_t *)&it[1]) + zone->size) = 0xabadbabe;
339 LIST_INSERT_HEAD(&zone->free_items, it, list);
340 }
341 LogFlowFuncLeave();
342}
343
344void uma_zone_set_allocf(uma_zone_t zone, uma_alloc_t pfAlloc)
345{
346 LogFlowFunc(("ENTER: zone:%R[mzone], pfAlloc:%Rfn\n", zone, pfAlloc));
347 zone->pfAlloc = pfAlloc;
348 LogFlowFuncLeave();
349}
350
351void uma_zone_set_freef(uma_zone_t zone, uma_free_t pfFree)
352{
353 LogFlowFunc(("ENTER: zone:%R[mzone], pfAlloc:%Rfn\n", zone, pfFree));
354 zone->pfFree = pfFree;
355 LogFlowFuncLeave();
356}
357
358uint32_t *uma_find_refcnt(uma_zone_t zone, void *mem)
359{
360 /** @todo (vvl) this function supposed to work with special zone storing
361 reference counters */
362 struct item *it = NULL;
363# ifndef NAT_MEM_LOG_ENABLED
364 NOREF(zone);
365# endif
366 LogFlowFunc(("ENTER: zone:%R[mzone], mem:%p\n", zone, mem));
367 it = (struct item *)mem; /* 1st element */
368 Assert(mem != NULL);
369 Assert(zone->magic == ZONE_MAGIC);
370 /* for returning pointer to counter we need get 0 elemnt */
371 Assert(it[-1].magic == ITEM_MAGIC);
372 LogFlowFunc(("LEAVE: %p\n", &it[-1].ref_count));
373 return &it[-1].ref_count;
374}
375
376void *uma_zalloc_arg(uma_zone_t zone, void *args, int how)
377{
378 void *mem;
379# ifndef NAT_MEM_LOG_ENABLED
380 NOREF(how);
381# endif
382 Assert(zone->magic == ZONE_MAGIC);
383 LogFlowFunc(("ENTER: zone:%R[mzone], args:%p, how:%RX32\n", zone, args, how));
384 if (zone->pfAlloc == NULL)
385 {
386 LogFlowFunc(("LEAVE: NULL\n"));
387 return NULL;
388 }
389 RTCritSectEnter(&zone->csZone);
390 mem = zone->pfAlloc(zone, zone->size, NULL, 0);
391 if (mem != NULL)
392 {
393 if (zone->pfCtor)
394 zone->pfCtor(zone->pData, mem, zone->size, args, M_DONTWAIT);
395 }
396 RTCritSectLeave(&zone->csZone);
397 LogFlowFunc(("LEAVE: %p\n", mem));
398 return mem;
399}
400
401void uma_zfree(uma_zone_t zone, void *item)
402{
403 LogFlowFunc(("ENTER: zone:%R[mzone], item:%p\n", zone, item));
404 uma_zfree_arg(zone, item, NULL);
405 LogFlowFuncLeave();
406}
407
408void uma_zfree_arg(uma_zone_t zone, void *mem, void *flags)
409{
410 struct item *it;
411 Assert(zone->magic == ZONE_MAGIC);
412 Assert((zone->pfFree));
413 Assert((mem));
414 LogFlowFunc(("ENTER: zone:%R[mzone], mem:%p, flags:%p\n", zone, mem, flags));
415# ifndef NAT_MEM_LOG_ENABLED
416 NOREF(flags);
417# endif
418
419 RTCritSectEnter(&zone->csZone);
420 it = &((struct item *)mem)[-1];
421 Assert((it->magic == ITEM_MAGIC));
422 Assert((zone->magic == ZONE_MAGIC && zone == it->zone));
423
424 zone->pfFree(mem, 0, 0);
425 RTCritSectLeave(&zone->csZone);
426 LogFlowFuncLeave();
427}
428
429int uma_zone_exhausted_nolock(uma_zone_t zone)
430{
431 int fExhausted;
432 LogFlowFunc(("ENTER: zone:%R[mzone]\n", zone));
433 RTCritSectEnter(&zone->csZone);
434 fExhausted = (zone->cur_items == zone->max_items);
435 RTCritSectLeave(&zone->csZone);
436 LogFlowFunc(("LEAVE: %RTbool\n", fExhausted));
437 return fExhausted;
438}
439
440void zone_drain(uma_zone_t zone)
441{
442 struct item *it;
443 uma_zone_t master_zone;
444
445 /* vvl: Huh? What to do with zone which hasn't got backstore ? */
446 Assert((zone->master_zone));
447 LogFlowFunc(("ENTER: zone:%R[mzone]\n", zone));
448 master_zone = zone->master_zone;
449 while (!LIST_EMPTY(&zone->free_items))
450 {
451 it = LIST_FIRST(&zone->free_items);
452 Assert((it->magic == ITEM_MAGIC));
453
454 RTCritSectEnter(&zone->csZone);
455 LIST_REMOVE(it, list);
456 zone->max_items--;
457 RTCritSectLeave(&zone->csZone);
458
459 it->zone = master_zone;
460
461 RTCritSectEnter(&master_zone->csZone);
462 LIST_INSERT_HEAD(&master_zone->free_items, it, list);
463 master_zone->cur_items--;
464 slirp_zone_check_and_send_pending(master_zone); /* may exit+enter the cs! */
465 RTCritSectLeave(&master_zone->csZone);
466 }
467 LogFlowFuncLeave();
468}
469
470void slirp_null_arg_free(void *mem, void *arg)
471{
472 /** @todo (vvl) make it wiser */
473 LogFlowFunc(("ENTER: mem:%p, arg:%p\n", mem, arg));
474 Assert(mem);
475# ifndef NAT_MEM_LOG_ENABLED
476 NOREF(arg);
477# endif
478 RTMemFree(mem);
479 LogFlowFuncLeave();
480}
481
482void *uma_zalloc(uma_zone_t zone, int len)
483{
484# ifndef NAT_MEM_LOG_ENABLED
485 NOREF(zone);
486 NOREF(len);
487# endif
488 LogFlowFunc(("ENTER: zone:%R[mzone], len:%d\n", zone, len));
489 LogFlowFunc(("LEAVE: NULL"));
490 return NULL;
491}
492
493struct mbuf *slirp_ext_m_get(PNATState pData, size_t cbMin, void **ppvBuf, size_t *pcbBuf)
494{
495 struct mbuf *m;
496 size_t size = MCLBYTES;
497 LogFlowFunc(("ENTER: cbMin:%d, ppvBuf:%p, pcbBuf:%p\n", cbMin, ppvBuf, pcbBuf));
498 if (cbMin < MSIZE)
499 size = MCLBYTES;
500 else if (cbMin < MCLBYTES)
501 size = MCLBYTES;
502 else if (cbMin < MJUM9BYTES)
503 size = MJUM9BYTES;
504 else if (cbMin < MJUM16BYTES)
505 size = MJUM16BYTES;
506 else
507 AssertMsgFailed(("Unsupported size"));
508
509 m = m_getjcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR, size);
510 if (m == NULL)
511 {
512 *ppvBuf = NULL;
513 *pcbBuf = 0;
514 LogFlowFunc(("LEAVE: NULL\n"));
515 return NULL;
516 }
517 m->m_len = size;
518 *ppvBuf = mtod(m, void *);
519 *pcbBuf = size;
520 LogFlowFunc(("LEAVE: %p\n", m));
521 return m;
522}
523
524void slirp_ext_m_free(PNATState pData, struct mbuf *m, uint8_t *pu8Buf)
525{
526
527 LogFlowFunc(("ENTER: m:%p, pu8Buf:%p\n", m, pu8Buf));
528 if ( !pu8Buf
529 && pu8Buf != mtod(m, uint8_t *))
530 RTMemFree(pu8Buf); /* This buffer was allocated on heap */
531 m_freem(pData, m);
532 LogFlowFuncLeave();
533}
534
535static void zone_destroy(uma_zone_t zone)
536{
537 RTCritSectEnter(&zone->csZone);
538 LogFlowFunc(("ENTER: zone:%R[mzone]\n", zone));
539 LogRel(("NAT: zone(nm:%s, used:%d)\n", zone->name, zone->cur_items));
540 RTMemFree(zone->area);
541 RTCritSectLeave(&zone->csZone);
542 RTCritSectDelete(&zone->csZone);
543 RTMemFree(zone);
544 LogFlowFuncLeave();
545}
546
547void m_fini(PNATState pData)
548{
549 LogFlowFuncEnter();
550# define ZONE_DESTROY(zone) do { zone_destroy((zone)); (zone) = NULL;} while (0)
551 ZONE_DESTROY(pData->zone_clust);
552 ZONE_DESTROY(pData->zone_pack);
553 ZONE_DESTROY(pData->zone_mbuf);
554 ZONE_DESTROY(pData->zone_jumbop);
555 ZONE_DESTROY(pData->zone_jumbo9);
556 ZONE_DESTROY(pData->zone_jumbo16);
557 ZONE_DESTROY(pData->zone_ext_refcnt);
558# undef ZONE_DESTROY
559 /** @todo do finalize here.*/
560 LogFlowFuncLeave();
561}
562
563void
564if_init(PNATState pData)
565{
566 /* 14 for ethernet */
567 if_maxlinkhdr = 14;
568 if_comp = IF_AUTOCOMP;
569 if_mtu = 1500;
570 if_mru = 1500;
571}
572#endif /* VBOX_NAT_TST_QUEUE */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette