1d79531a39
PDP-10 KL10B model emulator. KL10B model supports extended addressing. Tap networking support is from http://www.falu.nl/~rhialto/klh-diffs2 . This package is potentially built on i386, amd64, arm, alpha, sparc, and powerpc platforms. But this package supports i386 and amd64 only now, and only amd64 build is tested, due to lack of my test environments.
442 lines
14 KiB
C
442 lines
14 KiB
C
$NetBSD: patch-src_osdnet.c,v 1.1 2013/10/17 15:41:10 ryoon Exp $
|
||
|
||
http://www.falu.nl/~rhialto/klh-diffs2
|
||
|
||
--- src/osdnet.c.orig 2005-04-28 22:01:04.000000000 +0000
|
||
+++ src/osdnet.c
|
||
@@ -68,7 +68,7 @@ int
|
||
osn_ifsock(char *ifnam, ossock_t *as)
|
||
{
|
||
#if (KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_BPF || KLH10_NET_PFLT || \
|
||
- KLH10_NET_TUN || KLH10_NET_LNX)
|
||
+ KLH10_NET_TUN || KLH10_NET_LNX || KLH10_NET_TAP_BRIDGE)
|
||
return ((*as = socket(AF_INET, SOCK_DGRAM, 0)) >= 0);
|
||
#else
|
||
# error OSD implementation needed for osn_ifsock
|
||
@@ -79,7 +79,7 @@ int
|
||
osn_ifclose(ossock_t s)
|
||
{
|
||
#if (KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_BPF || KLH10_NET_PFLT || \
|
||
- KLH10_NET_TUN || KLH10_NET_LNX)
|
||
+ KLH10_NET_TUN || KLH10_NET_LNX || KLH10_NET_TAP_BRIDGE)
|
||
return (close(s) >= 0);
|
||
#else
|
||
# error OSD implementation needed for osn_ifclose
|
||
@@ -161,6 +161,12 @@ or alternatively:
|
||
? (sizeof(struct ifreq) - sizeof(struct sockaddr) + (ifr).ifr_addr.sa_len) \
|
||
: sizeof(struct ifreq))
|
||
|
||
+ This has been made trickier by NetBSD 5.0, which doesn't put a sockaddr
|
||
+ but a (union with as largest member a) sockaddr_storage in the ifreq.
|
||
+ Now the size is always the same again, but not sizeof(struct sockaddr).
|
||
+ This can (probably) be recognised by the existence of
|
||
+ #define ifr_space ifr_ifru.ifru_space / * sockaddr_storage * /
|
||
+
|
||
*/
|
||
/*
|
||
Note that searching for AF_INET or IP addresses only finds interfaces that
|
||
@@ -288,7 +294,7 @@ osn_iftab_pass(int opts, int npass, int
|
||
uses a variable-size "ifreq" entry! Choke...
|
||
*/
|
||
ifnext = ifp + 1; /* Assume normal entry at first */
|
||
-#if NETIF_HAS_SALEN
|
||
+#if NETIF_HAS_SALEN && !defined(ifr_space)
|
||
if (ifp->ifr_addr.sa_len > sizeof(struct sockaddr)) {
|
||
offset = ifp->ifr_addr.sa_len - sizeof(struct sockaddr);
|
||
ifnext = (struct ifreq *)((char *)ifnext + offset);
|
||
@@ -382,6 +388,8 @@ osn_iftab_pass(int opts, int npass, int
|
||
}
|
||
}
|
||
|
||
+#include <stddef.h>
|
||
+
|
||
void
|
||
osn_ifctab_show(FILE *f, struct ifconf *ifc)
|
||
{
|
||
@@ -393,7 +401,14 @@ osn_ifctab_show(FILE *f, struct ifconf *
|
||
int nents = 0;
|
||
int nvary = 0;
|
||
|
||
- fprintf(f, "Interface table: %ld bytes (%d entries if std addr len %d)\n",
|
||
+ fprintf(f, "sizeof struct ifreq = %d\r\n", (int) sizeof(struct ifreq));
|
||
+ fprintf(f, "IFNAMSIZ = %d\r\n", (int) IFNAMSIZ);
|
||
+ fprintf(f, "offset of struct sockaddr_storage = %d\r\n", (int) offsetof(struct ifreq, ifr_space));
|
||
+ fprintf(f, "sizeof struct sockaddr = %d\r\n", (int) sizeof(struct sockaddr));
|
||
+ fprintf(f, "sizeof struct sockaddr_storage = %d\r\n", (int) sizeof(struct sockaddr_storage));
|
||
+ fprintf(f, "sizeof union ifr_ifru = %d\r\n", (int) sizeof(ifr->ifr_ifru));
|
||
+
|
||
+ fprintf(f, "Interface table: %ld bytes (%d entries if std addr len %d)\r\n",
|
||
(long)ifc->ifc_len, ifc->ifc_len/sizeof(struct ifreq),
|
||
(int)sizeof(struct sockaddr));
|
||
|
||
@@ -408,18 +423,19 @@ osn_ifctab_show(FILE *f, struct ifconf *
|
||
len = sizeof(struct sockaddr);
|
||
#endif
|
||
|
||
+ fprintf(f, "offset: %d\r\n", (int)((char *)ifr - (char *)ifc->ifc_req));
|
||
/* Output entry data */
|
||
- fprintf(f, "%2d: \"%.*s\" fam %d, len %d",
|
||
+ fprintf(f, "%2d: \"%.*s\" sockaddr.sa_family %d, .sa_len %d",
|
||
i, (int)sizeof(ifr->ifr_name), ifr->ifr_name,
|
||
ifr->ifr_addr.sa_family, len);
|
||
if (len) {
|
||
cp = (unsigned char *) ifr->ifr_addr.sa_data;
|
||
- fprintf(f, " = %x", *cp);
|
||
+ fprintf(f, " = (sockaddr.sa_data) %x", *cp);
|
||
for (--len; len > 0; --len) {
|
||
fprintf(f, ":%x", *++cp);
|
||
}
|
||
}
|
||
- fprintf(f, "\n");
|
||
+ fprintf(f, "\r\n");
|
||
|
||
cp = (unsigned char *) ifr->ifr_addr.sa_data;
|
||
switch (ifr->ifr_addr.sa_family) {
|
||
@@ -429,7 +445,7 @@ osn_ifctab_show(FILE *f, struct ifconf *
|
||
struct in_addr *in = &skin->sin_addr;
|
||
unsigned char *ucp = (unsigned char *) &in->s_addr;
|
||
|
||
- fprintf(f, " AF_INET = port %d, IP %d.%d.%d.%d\n",
|
||
+ fprintf(f, " AF_INET = port %d, IP %d.%d.%d.%d\r\n",
|
||
(int)skin->sin_port,
|
||
ucp[0], ucp[1], ucp[2], ucp[3]);
|
||
}
|
||
@@ -439,7 +455,7 @@ osn_ifctab_show(FILE *f, struct ifconf *
|
||
case AF_LINK:
|
||
{
|
||
struct sockaddr_dl *dla = (struct sockaddr_dl *) &ifr->ifr_addr;
|
||
- fprintf(f, " AF_LINK = type %d, alen %d",
|
||
+ fprintf(f, " AF_LINK = type %d, sdl_alen %d",
|
||
dla->sdl_type, dla->sdl_alen);
|
||
if (len = dla->sdl_alen) {
|
||
cp = (unsigned char *) LLADDR(dla);
|
||
@@ -448,18 +464,23 @@ osn_ifctab_show(FILE *f, struct ifconf *
|
||
fprintf(f, ":%x", *++cp);
|
||
}
|
||
}
|
||
- fprintf(f, "\n");
|
||
+ fprintf(f, "\r\n");
|
||
}
|
||
break;
|
||
#endif
|
||
|
||
+#if defined(AF_INET6)
|
||
+ case AF_INET6:
|
||
+ fprintf(f, " AF_INET6 (No handler for this)\r\n");
|
||
+ break;
|
||
+#endif
|
||
default:
|
||
- fprintf(f, " No handler for this family\n");
|
||
+ fprintf(f, " No handler for this family\r\n");
|
||
}
|
||
|
||
|
||
/* Move onto next entry */
|
||
-#if NETIF_HAS_SALEN
|
||
+#if NETIF_HAS_SALEN && !defined(ifr_space)
|
||
if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)) {
|
||
++nvary;
|
||
ifr = (struct ifreq *)((char *)(ifr + 1) +
|
||
@@ -469,10 +490,10 @@ osn_ifctab_show(FILE *f, struct ifconf *
|
||
ifr++;
|
||
}
|
||
if (nvary)
|
||
- fprintf(f, "Interface summary: %d entries of varying length\n",
|
||
+ fprintf(f, "Interface summary: %d entries of varying length\r\n",
|
||
nents);
|
||
else
|
||
- fprintf(f, "Interface summary: %d entries of std length %d\n",
|
||
+ fprintf(f, "Interface summary: %d entries of std length %d\r\n",
|
||
nents, (int)sizeof(struct ifreq));
|
||
}
|
||
|
||
@@ -483,7 +504,7 @@ osn_iftab_show(FILE *f, struct ifent *if
|
||
register struct ifent *ife;
|
||
int i;
|
||
|
||
- fprintf(f, "Filtered IFE table: %d entries\n", nents);
|
||
+ fprintf(f, "Filtered IFE table: %d entries\r\n", nents);
|
||
|
||
for (i = 0, ife = ifents; i < nents; ++i, ++ife) {
|
||
fprintf(f, "%2d: \"%s\"", i, ife->ife_name);
|
||
@@ -502,7 +523,7 @@ osn_iftab_show(FILE *f, struct ifent *if
|
||
fprintf(f, " (Other: fam %d)",
|
||
ife->ife_pother->ifr_addr.sa_family);
|
||
}
|
||
- fprintf(f, "\n");
|
||
+ fprintf(f, "\r\n");
|
||
}
|
||
}
|
||
|
||
@@ -897,6 +918,9 @@ osn_ifeaget(int s, /* Socket for (AF_IN
|
||
return TRUE;
|
||
}
|
||
|
||
+static struct eth_addr emhost_ea = /* Emulated host ether addr for tap */
|
||
+ { 0xf2, 0x0b, 0xa4, 0xff, 0xff, 0xff };
|
||
+
|
||
/* OSN_PFEAGET - get physical ethernet address for an open packetfilter FD.
|
||
*
|
||
* Also not well documented, but generally easier to perform.
|
||
@@ -945,8 +969,20 @@ osn_pfeaget(int pfs, /* Packetfilter so
|
||
}
|
||
ea_set(eap, endp.end_addr);
|
||
|
||
-#elif KLH10_NET_BPF && !CENV_SYS_NETBSD && !CENV_SYS_FREEBSD
|
||
- /* NetBSD no longer seems to support this */
|
||
+#elif KLH10_NET_TAP_BRIDGE
|
||
+ /* If we do tap(4) + bridge(4), the ether address of the tap is wholly
|
||
+ * irrelevant, it is on the other side of the "wire".
|
||
+ * Our own address is something we can make up completely.
|
||
+ */
|
||
+ if (emhost_ea.ea_octets[5] == 0xFF) {
|
||
+ time_t t = time(NULL);
|
||
+ emhost_ea.ea_octets[5] = t & 0xFE;
|
||
+ emhost_ea.ea_octets[4] = (t >> 8) & 0xFF;
|
||
+ emhost_ea.ea_octets[3] = (t >> 16) & 0xFF;
|
||
+ }
|
||
+ ea_set(eap, &emhost_ea); /* Return the ether address */
|
||
+#elif (KLH10_NET_BPF && !CENV_SYS_NETBSD && !CENV_SYS_FREEBSD)
|
||
+ /* NetBSD no longer seems to support this (on bpf) */
|
||
struct ifreq ifr;
|
||
|
||
strncpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name));
|
||
@@ -1131,7 +1167,7 @@ osn_ifeaset(int s, /* Socket for (AF_IN
|
||
char *ifnam, /* Interface name */
|
||
unsigned char *newpa) /* New ether address */
|
||
{
|
||
-#if CENV_SYS_DECOSF || KLH10_NET_LNX \
|
||
+#if CENV_SYS_DECOSF || KLH10_NET_LNX || KLH10_NET_TAP_BRIDGE \
|
||
|| (CENV_SYS_FREEBSD && defined(SIOCSIFLLADDR))
|
||
|
||
/* Common preamble code */
|
||
@@ -1190,6 +1226,8 @@ osn_ifeaset(int s, /* Socket for (AF_IN
|
||
if (ownsock) close(s);
|
||
return FALSE;
|
||
}
|
||
+# elif KLH10_NET_TAP_BRIDGE
|
||
+ ea_set(&emhost_ea, newpa);
|
||
# else
|
||
# error "Unimplemented OS routine osn_ifeaset()"
|
||
# endif
|
||
@@ -1338,6 +1376,7 @@ pfopen(void)
|
||
}
|
||
|
||
#endif /* KLH10_NET_PFLT || KLH10_NET_BPF */
|
||
+
|
||
|
||
#if KLH10_NET_PFLT
|
||
|
||
@@ -1916,6 +1955,212 @@ osn_pfinit(struct osnpf *osnpf, void *ar
|
||
}
|
||
#endif /* KLH10_NET_NIT */
|
||
|
||
+/*
|
||
+ * Too bad that this is never called...
|
||
+ */
|
||
+osn_pfdeinit()
|
||
+{
|
||
+#if KLH10_NET_TAP_BRIDGE
|
||
+ void tap_bridge_close();
|
||
+ tap_bridge_close();
|
||
+#endif
|
||
+}
|
||
+
|
||
+#if KLH10_NET_TAP_BRIDGE
|
||
+
|
||
+osn_pfinit(register struct osnpf *osnpf, void *arg)
|
||
+{
|
||
+ int fd;
|
||
+ char *ifnam = osnpf->osnpf_ifnam;
|
||
+
|
||
+ /* No "default interface" concept here */
|
||
+ if (!ifnam || !ifnam[0])
|
||
+ esfatal(1, "Packetfilter interface must be specified");
|
||
+
|
||
+ fd = tap_bridge_open(ifnam);
|
||
+
|
||
+ /* Now get our fresh new virtual interface's ethernet address.
|
||
+ */
|
||
+ (void) osn_pfeaget(fd, ifnam, (unsigned char *)&(osnpf->osnpf_ea));
|
||
+
|
||
+ return fd;
|
||
+}
|
||
+
|
||
+#include <net/if_tap.h>
|
||
+#include <net/if_bridgevar.h>
|
||
+#include <stdint.h>
|
||
+
|
||
+static struct ifreq br_ifr;
|
||
+static struct ifreq tap_ifr;
|
||
+static int my_tap;
|
||
+
|
||
+/*
|
||
+ * A TAP is a virtual ethernet interface, much like TUN is a virtual IP
|
||
+ * interface. We can use it to inject packets into the Unix input stream,
|
||
+ * provided it is UP and the host side has a matching IP address and
|
||
+ * netmask (also much like TUN), or that it is bridged to another interface.
|
||
+ *
|
||
+ * Here we try to create the user-given interface and then bridge it to
|
||
+ * the "default" interface. This is probably the most common configuration.
|
||
+ * If something else is desired, the user can set up the tap herself,
|
||
+ * and we'll just use it as it is. This is useful for a routed approach,
|
||
+ * for instance.
|
||
+ */
|
||
+int
|
||
+tap_bridge_open(char *ifnam)
|
||
+{
|
||
+ int tapfd;
|
||
+ int res;
|
||
+ union ipaddr netmask;
|
||
+ char cmdbuff[128];
|
||
+ struct ifent *ife;
|
||
+ int s;
|
||
+ int i;
|
||
+ struct ifbreq br_req;
|
||
+ struct ifdrv br_ifd;
|
||
+
|
||
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||
+ esfatal(1, "tap_bridge_open: socket() failed");
|
||
+ }
|
||
+
|
||
+ /* try to create tapN as specified by the user */
|
||
+ memset(&tap_ifr, 0, sizeof(tap_ifr));
|
||
+ strcpy(tap_ifr.ifr_name, ifnam);
|
||
+ res = ioctl(s, SIOCIFCREATE, &tap_ifr);
|
||
+ if (res == 0) {
|
||
+ my_tap = 1;
|
||
+ dbprintln("Created host-side tap \"%s\"", ifnam);
|
||
+ } else {
|
||
+ if (errno != EEXIST)
|
||
+ esfatal(1, "tap_bridge_open: can't create tap \"%s\"?", ifnam);
|
||
+ my_tap = 0;
|
||
+ dbprintln("Host-side tap \"%s\" alread exists; use it as-is", ifnam);
|
||
+ }
|
||
+
|
||
+ sprintf(cmdbuff, "/dev/%s", ifnam);
|
||
+ tapfd = open(cmdbuff, O_RDWR, 0);
|
||
+
|
||
+ if (tapfd < 0) {
|
||
+ /* Note possible error meanings:
|
||
+ ENOENT - no such filename
|
||
+ ENXIO - not configured in kernel
|
||
+ */
|
||
+ esfatal(1, "Couldn't find or open 10-side tap \"%s\"", cmdbuff);
|
||
+ }
|
||
+
|
||
+ dbprintln("Opened 10-side tap \"%s\"", cmdbuff);
|
||
+
|
||
+ /* Finally, turn on IFF_UP just in case the above didn't do it.
|
||
+ Note interface name is still there from the SIOCIFCREATE.
|
||
+ */
|
||
+ if (ioctl(s, SIOCGIFFLAGS, &tap_ifr) < 0) {
|
||
+ esfatal(1, "tap_bridge_open tap SIOCGIFFLAGS failed");
|
||
+ }
|
||
+ if (!(tap_ifr.ifr_flags & IFF_UP)) {
|
||
+ tap_ifr.ifr_flags |= IFF_UP;
|
||
+ if (ioctl(s, SIOCSIFFLAGS, &tap_ifr) < 0) {
|
||
+ esfatal(1, "tap_bridge_open tap SIOCSIFFLAGS failed");
|
||
+ }
|
||
+ if (DP_DBGFLG)
|
||
+ dbprint("tap_bridge_open tap did SIOCSIFFLAGS");
|
||
+ }
|
||
+
|
||
+ if (my_tap) {
|
||
+ for (i = 0; i < 1000; i++) {
|
||
+ /* try to create bridge%d */
|
||
+ memset(&br_ifr, 0, sizeof(br_ifr));
|
||
+ sprintf(br_ifr.ifr_name, "bridge%d", i);
|
||
+ res = ioctl(s, SIOCIFCREATE, &br_ifr);
|
||
+ if (res == 0)
|
||
+ break;
|
||
+ if (errno != EEXIST)
|
||
+ esfatal(1, "tap_bridge_open: can't create bridge \"%s\"?", br_ifr.ifr_name);
|
||
+ }
|
||
+ dbprintln("Created bridge \"%s\"", br_ifr.ifr_name);
|
||
+
|
||
+ /*
|
||
+ * Find default IP interface to bridge with.
|
||
+ * It might find the wrong one if there is more than one.
|
||
+ */
|
||
+
|
||
+ ife = osn_ipdefault();
|
||
+ if (!ife)
|
||
+ esfatal(0, "Couldn't find default interface");
|
||
+
|
||
+ if (swstatus)
|
||
+ dbprintln("Bridging with default interface \"%s\"", ife->ife_name);
|
||
+
|
||
+ if (1) {
|
||
+ sprintf(cmdbuff, "/sbin/brconfig %s add %s add %s up",
|
||
+ br_ifr.ifr_name, ife->ife_name, ifnam);
|
||
+ res = system(cmdbuff);
|
||
+ dbprintln("%s => %d", cmdbuff, res);
|
||
+ } else {
|
||
+ /* do whatever brconfig bridge0 add intf0 does... */
|
||
+ memset(&br_ifd, 0, sizeof(br_ifd));
|
||
+ memset(&br_req, 0, sizeof(br_req));
|
||
+
|
||
+ /* set name of the bridge */
|
||
+ strcpy(br_ifd.ifd_name, br_ifr.ifr_name);
|
||
+ br_ifd.ifd_cmd = BRDGADD;
|
||
+ br_ifd.ifd_len = sizeof(br_req);
|
||
+ br_ifd.ifd_data = &br_req;
|
||
+
|
||
+ /* brconfig bridge0 add tap0 (the virtual interface) */
|
||
+ strcpy(br_req.ifbr_ifsname, ifnam);
|
||
+ res = ioctl(s, SIOCSDRVSPEC, &br_ifd);
|
||
+ if (res == -1)
|
||
+ esfatal(1, "tap_bridge_open: can't add virtual intf to bridge?");
|
||
+
|
||
+ /* brconfig bridge0 add vr0 (the hardware interface) */
|
||
+ strcpy(br_req.ifbr_ifsname, ife->ife_name);
|
||
+ res = ioctl(s, SIOCSDRVSPEC, &br_ifd);
|
||
+ if (res == -1)
|
||
+ esfatal(1, "tap_bridge_open: can't add real intf to bridge?");
|
||
+
|
||
+ /* Finally, turn on IFF_UP just in case the above didn't do it.
|
||
+ * Note interface name is still there.
|
||
+ */
|
||
+ if (ioctl(s, SIOCGIFFLAGS, &br_ifr) < 0) {
|
||
+ esfatal(1, "tap_bridge_open bridge SIOCGIFFLAGS failed");
|
||
+ }
|
||
+ if (!(br_ifr.ifr_flags & IFF_UP)) {
|
||
+ br_ifr.ifr_flags |= IFF_UP;
|
||
+ if (ioctl(s, SIOCSIFFLAGS, &br_ifr) < 0) {
|
||
+ esfatal(1, "tap_bridge_open bridge SIOCSIFFLAGS failed");
|
||
+ }
|
||
+ if (DP_DBGFLG)
|
||
+ dbprint("tap_bridge_open bridge did SIOCSIFFLAGS");
|
||
+ }
|
||
+
|
||
+ }
|
||
+ }
|
||
+ close(s);
|
||
+
|
||
+ return tapfd; /* Success! */
|
||
+}
|
||
+
|
||
+void
|
||
+tap_bridge_close()
|
||
+{
|
||
+ if (my_tap) {
|
||
+ int s, res;
|
||
+ struct ifreq tap_ifr;
|
||
+
|
||
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||
+ esfatal(1, "tap_bridge_close: socket() failed");
|
||
+ }
|
||
+
|
||
+ /* Destroy bridge */
|
||
+ res = ioctl(s, SIOCIFDESTROY, &br_ifr);
|
||
+ res = ioctl(s, SIOCIFDESTROY, &tap_ifr);
|
||
+
|
||
+ close(s);
|
||
+ }
|
||
+}
|
||
+
|
||
+#endif /* KLH10_NET_TAP_BRIDGE */
|
||
+
|
||
#if KLH10_NET_DLPI
|
||
|
||
/* DLPI packetfilter initialization */
|