From 0a03946833d3bff4258eb439bdc5bbfad69a3c5b Mon Sep 17 00:00:00 2001 From: Olaf Seibert Date: Mon, 27 Apr 2015 23:33:58 +0200 Subject: [PATCH] Add tap/bridge support, and some other small build support things for my environment. --- bld/nbaxp/00build | 3 + bld/nbx86/00build | 2 + doc/install.txt | 40 +++++++ run/klt20/klt20.ini | 7 +- src/Mk-nbx86.mk | 2 +- src/dpimp.c | 4 + src/dpni20.c | 47 ++++++-- src/klh10.c | 3 + src/kn10ops.c | 4 +- src/osdnet.c | 283 +++++++++++++++++++++++++++++++++++++++++--- src/osdnet.h | 15 ++- 11 files changed, 374 insertions(+), 36 deletions(-) diff --git a/bld/nbaxp/00build b/bld/nbaxp/00build index 2c71ab1..c33ba7a 100755 --- a/bld/nbaxp/00build +++ b/bld/nbaxp/00build @@ -1,2 +1,5 @@ #!/bin/sh make base-kl CONFFLAGS_AUX=-DKLH10_I_CIRC=1 +# or +# make base-ks CONFFLAGS_AUX=-DKLH10_I_CIRC=1 +# make base-ks-its CONFFLAGS_AUX=-DKLH10_I_CIRC=1 diff --git a/bld/nbx86/00build b/bld/nbx86/00build index 2c71ab1..4e1debd 100755 --- a/bld/nbx86/00build +++ b/bld/nbx86/00build @@ -1,2 +1,4 @@ #!/bin/sh +export KL10HOME=/scratch/tops20/emulators/panda-dist/i386 make base-kl CONFFLAGS_AUX=-DKLH10_I_CIRC=1 +#make base-ks-its CONFFLAGS_AUX=-DKLH10_I_CIRC=1 diff --git a/doc/install.txt b/doc/install.txt index 38c0ec1..69f640c 100644 --- a/doc/install.txt +++ b/doc/install.txt @@ -175,6 +175,16 @@ config file if they don't already exist (correct as of FreeBSD 4.2): pseudo-device bpf 1 # Need at least one for NI20 or IMP pseudo-device tun 1 # Need at least one for IMP +NetBSD +------ + See The NetBSD Guide, chapter 17.9 "Kernel Tuning" for information on +how to recompile a kernel. You need at least these options (as of 3.0): + + options SYSVSHM # System V-like memory sharing + options SHMMAXPGS=10240 # 2048 pages is the default, >8192 for KLH10 + + pseudo-device tap # cloning device for NI20 + pseudo-device bridge # cloning device for NI20 Linux ----- @@ -1116,6 +1126,36 @@ mistakenly "fixed" to disallow it (FreeBSD). other host before telnetting back into the KN10. A better solution would be to fix those OSes that are open-source, and push to have these fixes incorporated in the standard releases. + For NetBSD (it may work on FreeBSD too) there exists a better +solution. A special configuration is created with a virtual ethernet +segment that has its host-side in the form of the interface tap0 (as in +the example below). The tap0 interface is bridged to the real network +interface. The NI20 is at the "other end" of the virtual ethernet. +(This differs from the other connectivity methods where the named +interface is the one that is basically used as the NI20). The NI20 is +therefore a dedicated interface: + + devdef ni0 564 ni20 ipaddr=10.0.0.51 ifc=tap0 dedic=true + +If the named tap interface already exists, no further changes to its +configuration are made. You can use this for alternative connectivity, +such as routed on the 10.0.1.0/24 subnet (instead of bridged): + + # To the shell, suppose your real network is 10.0.0.0/24, + # create a 10.0.1.0/24 network for KLH: + ifconfig tap0 create inet 10.0.1.1 netmask 255.255.255.0 up + ; in .ini file: + devdef ni0 564 ni20 ipaddr=10.0.1.51 ifc=tap0 dedic=true + ! in SYSTEM:INTERNET.ADDRESS on TOPS-20 v7.0 + IPNI#0,10 0 1 51,PACKET-SIZE:1500,DEFAULT,PREFERRED + ! in SYSTEM:INTERNET.ADDRESS on TOPS-20 v7.1 + IPNI#0,10.0.1.51,PACKET-SIZE:1500,LOGICAL-HOST-MASK:255.255.255.0,DEFAULT,PREFERRED + ! in SYSTEM:INTERNET.GATEWAYS on TOPS-20 v7.x + PRIME 10.0.1.1 + +(If TOPS-20 v7.0 can't do subnetting it might be better to use a +192.168.2.0/24 network) + LHDH (IMP): (KS-ITS only) diff --git a/run/klt20/klt20.ini b/run/klt20/klt20.ini index ad66100..2a7a489 100644 --- a/run/klt20/klt20.ini +++ b/run/klt20/klt20.ini @@ -12,7 +12,12 @@ devdef mta0 rh1.0 tm03 type=tu45 ; Need KLNI to avoid LAPRBF BUGCHKs - use valid address if known ; -devdef ni0 564 ni20 ipaddr=10.0.0.51 +; devdef ni0 564 ni20 ipaddr=10.0.0.51 +; The (NetBSD/FreeBSD) version with tap(4) and bridge(4) creates the named +; tap device dynamically and bridges it to the default interface. +; If you want it differently (for instance routed instead of bridged), +; you can create the tap yourself and it will be used as it is. +devdef ni0 564 ni20 ipaddr=10.0.0.51 ifc=tap0 dedic=true ; Load disk bootstrap directly load boot.sav diff --git a/src/Mk-nbx86.mk b/src/Mk-nbx86.mk index 05931e0..64816d5 100644 --- a/src/Mk-nbx86.mk +++ b/src/Mk-nbx86.mk @@ -21,7 +21,7 @@ # Build definitions SRC = ../../src -CFLAGS = -c -g3 -O3 +CFLAGS = -c -g3 -O3 -ggdb CFLAGS_LINT = -ansi -pedantic -Wall -Wshadow \ -Wstrict-prototypes -Wmissing-prototypes \ -Wmissing-declarations -Wredundant-decls diff --git a/src/dpimp.c b/src/dpimp.c index 6428dd3..afe4e9b 100644 --- a/src/dpimp.c +++ b/src/dpimp.c @@ -228,6 +228,10 @@ default for every OS that implements /dev/tun. #include /* For setpriority() */ #include /* For mlockall() */ +#if CENV_SYS_NETBSD +#include +#endif + #include "dpimp.h" /* DPIMP specific defs, grabs DPSUP if needed */ #ifdef RCSID diff --git a/src/dpni20.c b/src/dpni20.c index 0690b1b..3085e0f 100644 --- a/src/dpni20.c +++ b/src/dpni20.c @@ -169,6 +169,7 @@ The following general situations are possible: RCSID(dpni20_c,"$Id: dpni20.c,v 2.7 2003/02/23 18:07:50 klh Exp $") #endif + /* Globals */ int chpid; /* PID of child, handles input (net-to-10). */ @@ -432,6 +433,8 @@ main(int argc, char **argv) progname = progname_w; /* Reset progname to indicate identity */ tentoeth(dpni); /* Parent process handles output to net */ + osn_pfdeinit(); + return 1; /* Never returns, but placate compiler */ } @@ -498,6 +501,7 @@ void net_init(register struct dpni20_s *dpni) ea_set(&ihost_ea, &npf.osnpf_ea); /* Copy actual ea */ } + /* Now set any return info values in shared struct. */ memcpy(dpni->dpni_eth, (char *)&ihost_ea, 6); /* Copy ether addr */ @@ -996,7 +1000,7 @@ pfshow(struct OSN_PFSTRUCT *pf) /* LNX packetfilter initialization */ -#if KLH10_NET_LNX +#if KLH10_NET_LNX || KLH10_NET_TAP_BRIDGE /* The Linux PF_PACKET interface is described to some extent @@ -1092,6 +1096,10 @@ int lnx_filter(register struct dpni20_s *dpni, */ void eth_adrset(register struct dpni20_s *dpni) { +#if OSN_USE_IPONLY + dbprintln("\"%s\" multicast table ignored - IP-only interface", + dpni->dpni_ifnam); +#else unsigned char rdea[ETHER_ADRSIZ]; char old[OSN_EASTRSIZ]; char new[OSN_EASTRSIZ]; @@ -1157,6 +1165,7 @@ void eth_adrset(register struct dpni20_s *dpni) } } +#endif /* Assume succeeded since call succeeded, and clobber our address! */ memcpy(dpni->dpni_eth, dpni->dpni_rqeth, ETHER_ADRSIZ); } @@ -1175,6 +1184,10 @@ void eth_adrset(register struct dpni20_s *dpni) void eth_mcatset(register struct dpni20_s *dpni) { +#if OSN_USE_IPONLY + dbprintln("\"%s\" multicast table ignored - IP-only interface", + dpni->dpni_ifnam); +#else ossock_t s; int i, n, j; char ethstr[OSN_EASTRSIZ]; @@ -1249,6 +1262,7 @@ void eth_mcatset(register struct dpni20_s *dpni) nmcats = n; memcpy(ethmcat[0], dpni->dpni_mcat[0], (n * 6)); +#endif } /* ARP Hackery */ @@ -1361,7 +1375,9 @@ int arp_myreply(register unsigned char *buf, register int cnt) /* Now send it! Ignore any errors. */ if (swstatus) { char ipstr[OSN_IPSTRSIZ]; - dbprintln("ARP MyReply %s", ip_adrsprint(ipstr, ife->ife_ipchr)); + char ethstr[OSN_EASTRSIZ]; + dbprintln("ARP MyReply %s %s", ip_adrsprint(ipstr, ife->ife_ipchr), + eth_adrsprint(ethstr, ife->ife_ea)); } #if KLH10_NET_DLPI @@ -1372,6 +1388,9 @@ int arp_myreply(register unsigned char *buf, register int cnt) (void) putmsg(pffd, NULL, &data, 0); } #else + /* XXX + * Why is this sent to the packet filter (= host) and not to the -10????? + */ (void)write(pffd, pktbuf, sizeof(pktbuf)); #endif return TRUE; @@ -1441,7 +1460,7 @@ void ethtoten(register struct dpni20_s *dpni) cnt = data.len; /* Else cnt must be -1 as call failed */ } -#elif KLH10_NET_NIT || KLH10_NET_PFLT || KLH10_NET_LNX +#elif KLH10_NET_NIT || KLH10_NET_PFLT || KLH10_NET_LNX || KLH10_NET_TAP_BRIDGE cnt = read(pffd, buff, max); #elif KLH10_NET_BPF cnt = read(pffd, tbuff, tmax); @@ -1499,17 +1518,20 @@ void ethtoten(register struct dpni20_s *dpni) else dbprint("Read=%d", cnt); } -#if KLH10_NET_LNX +#if KLH10_NET_LNX || KLH10_NET_TAP_BRIDGE /* Linux has no packet filtering, thus must apply manual check to each and every packet read, unless dedicated. Ugh! */ - if (!dpni->dpni_dedic) { + if (KLH10_NET_TAP_BRIDGE || !dpni->dpni_dedic) { /* Sharing interface. Check for IP, DECNET, 802.3 */ - if (!lnx_filter(dpni, buff, cnt)) + if (!lnx_filter(dpni, buff, cnt)) { + if (DBGFLG) + dbprint("Dropped"); continue; /* Drop packet, continue reading */ + } } #endif /* KLH10_NET_LNX */ -#if KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_PFLT || KLH10_NET_LNX +#if KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_PFLT || KLH10_NET_LNX || KLH10_NET_TAP_BRIDGE #if 0 if (DBGFLG) if (((struct ether_header *)buff)->ether_type == htons(ETHERTYPE_ARP)) @@ -1521,7 +1543,7 @@ void ethtoten(register struct dpni20_s *dpni) if (DBGFLG) dbprint("sent RPKT"); -#endif /* KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_PFLT || KLH10_NET_LNX */ +#endif /* KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_PFLT || KLH10_NET_LNX || NET_TAP_BRIDGE */ #if KLH10_NET_BPF /* Screwy BPF algorithm requires more overhead because there's @@ -1594,7 +1616,11 @@ void tentoeth(register struct dpni20_s *dpni) /* Must check for outbound ARP requests if asked to and have ** at least one entry in our table of host's IP interfaces. */ +#if KLH10_NET_TAP_BRIDGE + doarpchk = 0; +#else doarpchk = (dpni->dpni_doarp & DPNI_ARPF_OCHK) && (osn_nifents() > 0); +#endif dpx = dp_dpxto(&dp); /* Get ptr to "To-DP" xfer stuff */ buff = dp_xrbuff(dpx, &max); @@ -1640,7 +1666,7 @@ void tentoeth(register struct dpni20_s *dpni) } #else cnt = write(pffd, buff, rcnt); -#endif +#endif /* else KLH10_NET_DLPI */ if (cnt != rcnt) { if ((cnt < 0) && (errno == EINTR)) { continue; /* Start over, may have new cmd */ @@ -1701,6 +1727,9 @@ void dumppkt(unsigned char *ucp, int cnt) fprintf(stderr, "\r\n"); } } + + + /* Add OSDNET shared code here */ diff --git a/src/klh10.c b/src/klh10.c index d01a4b6..4b68f3f 100644 --- a/src/klh10.c +++ b/src/klh10.c @@ -337,6 +337,7 @@ CMDDEF(cd_lights, fc_lights, CMRF_TLIN, "", KEYSBEGIN(fectbkeys) KEYDEF("?", cd_ques) KEYDEF("help", cd_help) + KEYDEF("exit", cd_quit) KEYDEF("quit", cd_quit) KEYDEF("load", cd_load) KEYDEF("dump", cd_dump) @@ -2765,6 +2766,7 @@ fc_dump(struct cmd_s *cm) static void fc_lights(struct cmd_s *cm) { +#if KLH10_DEV_LITES /* Moby conditional for entire file */ unsigned long port = 0; int c; char *sloc = cm->cmd_arglin; @@ -2783,6 +2785,7 @@ fc_lights(struct cmd_s *cm) } } printf("?Bad address\n"); +#endif /* KLH10_DEV_LITES */ } /* Instruction printing routines */ diff --git a/src/kn10ops.c b/src/kn10ops.c index 3c9eee3..9ac90b9 100644 --- a/src/kn10ops.c +++ b/src/kn10ops.c @@ -759,7 +759,7 @@ dw10_t op10ashc(register dw10_t d, ** must be done to the argument prior to the call! */ static dw10_t -x_ashc(register dw10_t d, +x_ashc(/*register*/ dw10_t d, register int i) { #endif /* IFFLAGS */ @@ -3238,7 +3238,7 @@ static int qdivstep(qw10_t *aq, register dw10_t d, register int nmagbits) { - register qw10_t qw; + /*register*/ qw10_t qw; dw10_t quot; register int qbit; diff --git a/src/osdnet.c b/src/osdnet.c index ba664a1..96e0093 100644 --- a/src/osdnet.c +++ b/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 s, struct ifconf *ifc) 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 s, struct ifconf *ifc) } } +#include + void osn_ifctab_show(FILE *f, struct ifconf *ifc) { @@ -393,7 +401,14 @@ osn_ifctab_show(FILE *f, struct ifconf *ifc) 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 *ifc) 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 *ifc) 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 *ifc) 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 *ifc) 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 *ifc) 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 *ifents, int nents) 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 *ifents, int nents) 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_INET, SOCK_DGRAM, 0) */ 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 socket or FD */ } 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_INET, SOCK_DGRAM, 0) */ 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_INET, SOCK_DGRAM, 0) */ 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 *arg) } #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 +#include +#include + +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 */ diff --git a/src/osdnet.h b/src/osdnet.h index 4f0ab26..028af38 100644 --- a/src/osdnet.h +++ b/src/osdnet.h @@ -59,6 +59,9 @@ #ifndef KLH10_NET_DLPI /* Solaris Data Link Provider Interface */ # define KLH10_NET_DLPI 0 #endif +#ifndef KLH10_NET_TAP_BRIDGE /* BSD Ethernet Tunnel device + a bridge */ +# define KLH10_NET_TAP_BRIDGE 0 +#endif #ifndef KLH10_NET_TUN /* BSD IP Tunnel device */ # define KLH10_NET_TUN 0 #endif @@ -67,14 +70,18 @@ #endif #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) /* None explicitly specified, pick a reasonable default */ -# if (CENV_SYS_FREEBSD && OSN_USE_IPONLY) +# if ((CENV_SYS_NETBSD || CENV_SYS_FREEBSD) && OSN_USE_IPONLY) # undef KLH10_NET_TUN # define KLH10_NET_TUN 1 # elif (CENV_SYS_NETBSD || CENV_SYS_FREEBSD) -# undef KLH10_NET_BPF -# define KLH10_NET_BPF 1 +/* + * # undef KLH10_NET_BPF + * # define KLH10_NET_BPF 1 + */ +# undef KLH10_NET_TAP_BRIDGE +# define KLH10_NET_TAP_BRIDGE 1 # elif CENV_SYS_DECOSF # undef KLH10_NET_PFLT # define KLH10_NET_PFLT 1