summaryrefslogtreecommitdiff
path: root/emulators/qemu-devel/files/patch-bt
blob: 62e8924722b3f18795af02cbcc47b792dac88100 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
Index: qemu/vl.c
@@ -43,6 +43,9 @@
 #ifndef __APPLE__
 #include <libutil.h>
 #endif
+#ifdef __FreeBSD__
+#include <sys/module.h>
+#endif
 #else
 #include <linux/if.h>
 #include <linux/if_tun.h>
@@ -1059,6 +1062,34 @@
 
 #endif /* CONFIG_SLIRP */
 
+#ifdef __FreeBSD__
+#define LOAD_QUIETLY	1
+#define LOAD_VERBOSLY	2
+
+int
+loadmodules(int how, const char *module, ...)
+{
+  int loaded = 0;
+  va_list ap;
+
+  va_start(ap, module);
+#ifndef NO_MODULES
+  while (module != NULL) {
+    if (modfind(module) == -1) {
+      if (kldload(module) == -1) {
+        if (how == LOAD_VERBOSLY)
+          fprintf(stderr, "%s: Cannot load module\n", module);
+      } else
+        loaded++;
+    }
+    module = va_arg(ap, const char *);
+  }
+  va_end(ap);
+#endif
+  return loaded;
+}
+#endif
+
 #if !defined(_WIN32)
 #ifdef _BSD
 static int tun_open(char *ifname, int ifname_size)
@@ -1067,11 +1098,55 @@
     char *dev;
     struct stat s;
 
+#ifdef __FreeBSD__
+    int i, kldtried = 0, enoentcount = 0, err = 0;
+    char dname[100];
+#ifdef USE_DEVTAP
+    /*
+     * 5.x has /dev/tap, but that seems to just blindly increase its
+     * couter on every open() for some people(??), i.e. on every qemu run.
+     */
+    i = -1;
+#else
+    i = 0;
+#endif
+    for (; i < 10; i++) {
+        if (i == -1)
+	    strcpy(dname, "/dev/tap");
+        else
+	    snprintf(dname, sizeof dname, "%s%d",
+		     "/dev/tap", i);
+        fd = open(dname, O_RDWR);
+        if (fd >= 0)
+            break;
+        else if (errno == ENXIO || errno == ENOENT) {
+            if (i == 0 && !kldtried++) {
+                /*
+                 * Attempt to load the tunnel interface KLD if it isn't loaded
+                 * already.
+                 */
+                if (loadmodules(LOAD_VERBOSLY, "if_tap", NULL))
+                    i = -1;
+                continue;
+            }
+            if (errno != ENOENT || ++enoentcount > 3) {
+                err = errno;
+	        break;
+            }
+        } else
+            err = errno;
+    }
+    if (fd < 0) {
+        fprintf(stderr, "warning: could not open %s (%s): no virtual network emulation\n", dname, strerror(err));
+        return -1;
+    }
+#else
     fd = open("/dev/tap", O_RDWR);
     if (fd < 0) {
-        fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n");
+        fprintf(stderr, "warning: could not open /dev/tap (%s): no virtual network emulation\n", strerror(errno));
         return -1;
     }
+#endif
 
     fstat(fd, &s);
     dev = devname(s.st_rdev, S_IFCHR);