VirtualBox

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

Last change on this file since 75478 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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