diff --git a/src/Mk-nbaxp.mk b/src/Mk-nbaxp.mk index 0ca1260..e1e2493 100644 --- a/src/Mk-nbaxp.mk +++ b/src/Mk-nbaxp.mk @@ -27,7 +27,11 @@ CFLAGS_LINT = -ansi -pedantic -Wall -Wshadow \ -Wmissing-declarations -Wredundant-decls # Source definitions -CENVFLAGS = -DCENV_CPU_ALPHA=1 -DCENV_SYS_NETBSD=1 -include netbsd-sucks.h +CENVFLAGS = -DCENV_CPU_ALPHA=1 -DCENV_SYS_NETBSD=1 -include netbsd-sucks.h \ + -DKLH10_NET_PCAP=1 \ + -DKLH10_NET_TUN=1 \ + -DKLH10_NET_TAP=1 \ + -DKLH10_NET_BRIDGE=1 # Any target with no customized rule here is simply passed on to the # standard Makefile. If no target is specified, "usage" is passed on diff --git a/src/dpimp.c b/src/dpimp.c index 1a4e4a0..fc3da70 100644 --- a/src/dpimp.c +++ b/src/dpimp.c @@ -305,7 +305,6 @@ void hosttoimp(struct dpimp_s *); void net_init(struct dpimp_s *); -#if !KLH10_NET_TUN void arp_init(struct dpimp_s *); struct arpent *arptab_look(struct in_addr); struct arpent *arp_look(struct in_addr, struct ether_addr *); @@ -319,7 +318,6 @@ void arp_reply(unsigned char *eap, unsigned char *iap); int hi_iproute(struct in_addr *ipa, unsigned char *lp, int cnt); void ip_write(struct in_addr *, unsigned char *, int); void ether_write(struct eth_header *, unsigned char *, int); -#endif /* !KLH10_NET_TUN */ void ihl_frag(int, unsigned char *); void ihl_hhsend(struct dpimp_s *, int, unsigned char *); @@ -745,10 +743,6 @@ net_init(struct dpimp_s *dpimp) { 0x06, 0, 0, 0x00000000 }, /* (005) ret #0 */ #endif -#define OSN_PFSTRUCT bpf_program -#define PF_FLEN bf_len -#define PF_FILT bf_insns - #define BPF_PFMAX 50 /* Max instructions in BPF filter */ struct bpf_insn bpf_pftab[BPF_PFMAX]; struct bpf_program bpf_pfilter = { 0, @@ -806,17 +800,17 @@ struct bpf_insn bpf_jump(unsigned short code, bpf_u_int32 k, #define BPFI_RETWIN() BPFI_RET((u_int)-1) /* Success return */ -static void pfshow(struct OSN_PFSTRUCT *); +static void pfshow(struct bpf_program *); -struct OSN_PFSTRUCT * +struct bpf_program * pfbuild(void *arg, struct in_addr *ipa) { struct dpimp_s *dpimp = (struct dpimp_s *)arg; unsigned char *ucp = (unsigned char *)ipa; - struct OSN_PFSTRUCT *pfp = &bpf_pfilter; + struct bpf_program *pfp = &bpf_pfilter; struct bpf_insn *p; - p = pfp->PF_FILT; /* Point to 1st instruction in BPF program */ + p = pfp->bf_insns; /* Point to 1st instruction in BPF program */ /* We're interested in IP (and thus ARP as well) packets. This is assumed to be the LAST part of the filter, thus @@ -854,7 +848,7 @@ pfbuild(void *arg, struct in_addr *ipa) *p++ = BPFI_RETFAIL(); /* Fail */ } - pfp->PF_FLEN = p - pfp->PF_FILT; /* Set # of items on list */ + pfp->bf_len = p - pfp->bf_insns; /* Set # of items on list */ if (DBGFLG) /* If debugging, print out resulting filter */ pfshow(pfp); @@ -865,18 +859,18 @@ pfbuild(void *arg, struct in_addr *ipa) /* Debug auxiliary to print out packetfilter we composed. */ static void -pfshow(struct OSN_PFSTRUCT *pf) +pfshow(struct bpf_program *pf) { int i; fprintf(stderr, "[dpimp: kernel packetfilter pri <>, len %d:\r\n", - /* pf->PF_PRIO, */ pf->PF_FLEN); - for (i = 0; i < pf->PF_FLEN; ++i) + /* pf->PF_PRIO, */ pf->bf_len); + for (i = 0; i < pf->bf_len; ++i) fprintf(stderr, "%04X %2d %2d %0X\r\n", - pf->PF_FILT[i].code, - pf->PF_FILT[i].jt, - pf->PF_FILT[i].jf, - pf->PF_FILT[i].k); + pf->bf_insns[i].code, + pf->bf_insns[i].jt, + pf->bf_insns[i].jf, + pf->bf_insns[i].k); fprintf(stderr, "]\r\n"); } #endif /* KLH10_NET_PCAP */ @@ -921,7 +915,6 @@ int lnx_filter(struct dpimp_s *dpimp, } -#if !KLH10_NET_TUN /* ARP hacking code. Originally modelled after old BSD ARP stuff. */ @@ -1373,7 +1366,6 @@ arp_reply(unsigned char *eap, /* Requestor ether addr */ ether_write(&eh, (unsigned char *)&arp.arp, sizeof(arp.arp)); } -#endif /* !KLH10_NET_TUN */ /* IMPTOHOST - Child-process main loop for pumping packets from IMP to HOST. ** Reads packets from net, fragments if necessary, and feeds @@ -1392,6 +1384,7 @@ imptohost(struct dpimp_s *dpimp) unsigned char *buffp; size_t max; int stoploop = 50; + int ether_hdr_offset; inibuf = dp_xsbuff(dpx, &max); /* Get initial buffer ptr */ @@ -1402,11 +1395,11 @@ imptohost(struct dpimp_s *dpimp) if (DBGFLG) fprintf(stderr, "[dpimp-R: sent INIT]\r\n"); -#if KLH10_NET_TUN -# define ETHER_HDR_OFFSET 0 /* No ether headers on TUN */ -#else -# define ETHER_HDR_OFFSET ETHER_HDRSIZ -#endif + if (pfdata.pf_ip4_only) { + ether_hdr_offset = 0; + } else { + ether_hdr_offset = ETHER_HDRSIZ; + } for (;;) { /* Make sure that buffer is free before clobbering it */ @@ -1416,12 +1409,12 @@ imptohost(struct dpimp_s *dpimp) fprintf(stderr, "[dpimp-R: InWait]\r\n"); /* Set up buffer and initialize offsets */ - buffp = inibuf + DPIMP_DATAOFFSET - ETHER_HDR_OFFSET; + buffp = inibuf + DPIMP_DATAOFFSET - ether_hdr_offset; /* OK, now do a blocking read on packetfilter input! */ cnt = osn_pfread(&pfdata, buffp, MAXETHERLEN); - if (cnt <= ETHER_HDR_OFFSET) { + if (cnt <= ether_hdr_offset) { /* If call times out due to E/BIOCSRTIMEOUT, will return 0 */ if (cnt == 0 && dpimp->dpimp_rdtmo) continue; /* Just try again */ @@ -1463,8 +1456,7 @@ imptohost(struct dpimp_s *dpimp) continue; /* Drop packet, continue reading */ } -#if !KLH10_NET_TUN - /* if (!pfdata.pf_ip4_only) */ { + if (!pfdata.pf_ip4_only) { /* Verify that pf filtering is doing its job */ switch (eh_tget((struct eth_header *)buffp)) { case ETHERTYPE_IP: @@ -1478,13 +1470,12 @@ imptohost(struct dpimp_s *dpimp) continue; } } -#endif /* OK, it claims to be an IP packet, see if so long that we ** need to fragment it. Yech! */ - cnt -= ETHER_HDR_OFFSET; - buffp += ETHER_HDR_OFFSET; + cnt -= ether_hdr_offset; + buffp += ether_hdr_offset; if (cnt > SI_MAXMSG) { ihl_frag(cnt, buffp); @@ -1546,11 +1537,11 @@ ihl_hhsend(struct dpimp_s *dpimp, /* Hack to set host/imp value as properly as possible. */ memcpy((char *)&haddr.ia_octet[0], pp + IPBOFF_SRC, 4); if ((haddr.ia_addr.s_addr & ihost_nm.s_addr) != ihost_net.s_addr) { -#if !KLH10_NET_TUN - haddr.ia_addr = gwdef_ip; /* Not local, use default GW */ -#else - haddr.ia_addr = tun_ip; /* Not local, use tunnel end */ -#endif + if (pfdata.pf_ip4_only) { + haddr.ia_addr = tun_ip; /* Not local, use tunnel end */ + } else { + haddr.ia_addr = gwdef_ip; /* Not local, use default GW */ + } } ihobuf[SIH_HSIZ+SIL_HST] = haddr.ia_octet[1]; @@ -1598,9 +1589,7 @@ hosttoimp(struct dpimp_s *dpimp) size_t max; int rcnt; unsigned char *inibuf; -#if !KLH10_NET_TUN struct in_addr ipdest; -#endif inibuf = dp_xrbuff(dpx, &max); /* Get initial buffer ptr */ @@ -1724,8 +1713,6 @@ hosttoimp(struct dpimp_s *dpimp) } } -#if !KLH10_NET_TUN - /* HI_IPROUTE - Determine where to actually send Host-Host IP datagram. ** See discussion of routing in comments at start of file. For now, let's build the IP address by slapping the 1st IP byte @@ -1831,7 +1818,6 @@ ether_write(struct eth_header *hp, #endif } -#endif /* !KLH10_NET_TUN */ void dumppkt(unsigned char *ucp, int cnt) diff --git a/src/dpimp.h b/src/dpimp.h index d4d6073..742dfd4 100644 --- a/src/dpimp.h +++ b/src/dpimp.h @@ -95,6 +95,8 @@ #define DPIMP_VERSION ((1<<10) | (1<<5) | (3)) /* 1.1.3 */ +#define IFNAM_LEN 16 /* at least IFNAMSIZ! */ + /* DPIMP-specific stuff */ /* C = controlling parent sets, D = Device proc sets */ /* If both, 1st letter indicates inital setter */ @@ -102,7 +104,7 @@ struct dpimp_s { struct dpc_s dpimp_dpc; /* CD Standard DPC portion */ int dpimp_ver; /* C Version of shared struct */ int dpimp_attrs; /* C Attribute flags */ - char dpimp_ifnam[16]; /* CD Interface name if any */ + char dpimp_ifnam[IFNAM_LEN];/* CD Interface name if any */ char dpimp_ifmeth[16]; /* C Interface access method */ unsigned char dpimp_eth[6]; /* CD Ethernet address of interface */ unsigned char dpimp_ip[4]; /* C 10's IP address to filter on, if shared */ diff --git a/src/dpni20.c b/src/dpni20.c index 5b42bee..36e50ed 100644 --- a/src/dpni20.c +++ b/src/dpni20.c @@ -170,6 +170,7 @@ The following general situations are possible: int chpid; /* PID of child, handles input (net-to-10). */ int swstatus = TRUE; +struct osnpf npf; struct pfdata pfdata; /* Packet-Filter state */ struct dp_s dp; /* Device-Process struct for DP ops */ @@ -191,6 +192,7 @@ struct ether_addr ihost_ea; /* Native host ether addr for selected ifc */ int nmcats = 0; unsigned char ethmcat[DPNI_MCAT_SIZ][6]; /* Table of known MCAT addresses */ + /* Local predeclarations */ void ethtoten(struct dpni20_s *); @@ -393,10 +395,10 @@ main(int argc, char **argv) dbprintln(" addr %s", ip_adrsprint(sbuf, (unsigned char *)&ihost_ip)); #endif -#if KLH10_NET_TUN - dbprintln(" tun %s", - ip_adrsprint(sbuf, (unsigned char *)&tun_ip)); -#endif + if (pfdata.pf_ip4_only) { + dbprintln(" tun %s", + ip_adrsprint(sbuf, (unsigned char *)&tun_ip)); + } dbprintln(" VHOST %s", ip_adrsprint(sbuf, (unsigned char *)&ehost_ip)); } @@ -439,7 +441,7 @@ main(int argc, char **argv) progname = progname_w; /* Reset progname to indicate identity */ tentoeth(dpni); /* Parent process handles output to net */ - osn_pfdeinit(); + osn_pfdeinit(&pfdata, &npf); return 1; /* Never returns, but placate compiler */ } @@ -456,7 +458,7 @@ void net_init(struct dpni20_s *dpni) /* Get the IP address for the tunnel, if specified */ memcpy((char *)&tun_ip, (char *)&dpni->dpni_tun, 4); -#if !KLH10_NET_TUN + /* Ensure network device name, if specified, isn't too long */ if (dpni->dpni_ifnam[0] && (strlen(dpni->dpni_ifnam) >= sizeof(ifr.ifr_name))) { @@ -489,7 +491,6 @@ void net_init(struct dpni20_s *dpni) dbprintln("Using default interface \"%s\"", dpni->dpni_ifnam); } } -#endif /* Now set remaining stuff */ @@ -497,7 +498,6 @@ void net_init(struct dpni20_s *dpni) the ethernet address for the selected interface. */ { - struct osnpf npf; npf.osnpf_ifnam = dpni->dpni_ifnam; npf.osnpf_ifmeth = dpni->dpni_ifmeth; @@ -560,10 +560,6 @@ void net_init(struct dpni20_s *dpni) */ -#define OSN_PFSTRUCT bpf_program -#define PF_FLEN bf_len -#define PF_FILT bf_insns - #define BPF_PFMAX 50 /* Max instructions in BPF filter */ struct bpf_insn bpf_pftab[BPF_PFMAX]; struct bpf_program bpf_pfilter = { 0, @@ -620,16 +616,16 @@ struct bpf_insn bpf_jump(unsigned short code, bpf_u_int32 k, #define BPFI_RETFAIL() BPFI_RET(0) /* Failure return */ #define BPFI_RETWIN() BPFI_RET((u_int)-1) /* Success return */ -static void pfshow(struct OSN_PFSTRUCT *); +static void pfshow(struct bpf_program *); -struct OSN_PFSTRUCT * +struct bpf_program * pfbuild(void *arg, struct in_addr *ipa) { struct dpni20_s *dpni = (struct dpni20_s *)arg; - struct OSN_PFSTRUCT *pfp = &bpf_pfilter; + struct bpf_program *pfp = &bpf_pfilter; struct bpf_insn *p; - p = pfp->PF_FILT; /* Point to 1st instruction in BPF program */ + p = pfp->bf_insns; /* Point to 1st instruction in BPF program */ /* First check for broadcast/multicast bit in dest address */ *p++ = BPFI_LDB(PKBOFF_EDEST); /* Get 1st byte of dest ether addr */ @@ -737,7 +733,7 @@ pfbuild(void *arg, struct in_addr *ipa) *p++ = BPFI_RETFAIL(); /* Fail */ } - pfp->PF_FLEN = p - pfp->PF_FILT; /* Set # of items on list */ + pfp->bf_len = p - pfp->bf_insns; /* Set # of items on list */ if (DBGFLG) /* If debugging, print out resulting filter */ pfshow(pfp); @@ -748,19 +744,19 @@ pfbuild(void *arg, struct in_addr *ipa) /* Debug auxiliary to print out packetfilter we composed. */ static void -pfshow(struct OSN_PFSTRUCT *pf) +pfshow(struct bpf_program *pf) { int i; fprintf(stderr, "[%s: kernel packetfilter pri <>, len %d:\r\n", progname, - /* pf->PF_PRIO, */ pf->PF_FLEN); - for (i = 0; i < pf->PF_FLEN; ++i) + /* pf->PF_PRIO, */ pf->bf_len); + for (i = 0; i < pf->bf_len; ++i) fprintf(stderr, "%04X %2d %2d %0X\r\n", - pf->PF_FILT[i].code, - pf->PF_FILT[i].jt, - pf->PF_FILT[i].jf, - pf->PF_FILT[i].k); + pf->bf_insns[i].code, + pf->bf_insns[i].jt, + pf->bf_insns[i].jf, + pf->bf_insns[i].k); fprintf(stderr, "]\r\n"); } @@ -1103,6 +1099,7 @@ int arp_myreply(unsigned char *buf, int cnt) #endif ucp += ETHER_ADRSIZ; ea_set(ucp, (char *)&ihost_ea); /* Set source addr to ours! */ + ucp[5]++; /* but modified to pass the echo check */ ucp += ETHER_ADRSIZ; *ucp++ = (ETHERTYPE_ARP>>8)&0377; /* Set high byte of type */ *ucp++ = (ETHERTYPE_ARP )&0377; /* Set low byte of type */ @@ -1157,11 +1154,10 @@ int arp_myreply(unsigned char *buf, int cnt) dpx = dp_dpxfr(&dp); /* Get ptr to from-DP comm rgn */ buff = dp_xsbuff(dpx, &max); /* Set up buffer ptr & max count */ - /* Tell KLH10 we're initialized and ready by sending initial packet */ if (sizeof(pktbuf) <= max && dp_xswait(dpx)) { /* Wait until buff free, in case */ - memcpy(buff, pktbuf, sizeof(pktbuf)); - dp_xsend(dpx, DPNI_RPKT, cnt); + memcpy(buff, pktbuf, ARP_PKTSIZ); + dp_xsend(dpx, DPNI_RPKT, ARP_PKTSIZ); if (DP_DBGFLG) dbprint("sent ARP reply to -10"); } @@ -1284,11 +1280,7 @@ void tentoeth(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); diff --git a/src/enaddr.c b/src/enaddr.c index 6694b28..a100567 100644 --- a/src/enaddr.c +++ b/src/enaddr.c @@ -421,16 +421,18 @@ static int pareth(char *cp, unsigned char *adr) #define OSN_PFSTRUCT bpf_program -struct OSN_PFSTRUCT * +struct bpf_program * pfbuild(void *arg, struct in_addr *ipa) { return NULL; } -struct OSN_PFSTRUCT * +struct bpf_program * pfeabuild(void *arg, unsigned char *ea) { return NULL; } +#define IFNAM_LEN 16 /* at least IFNAMSIZ! */ + #include "osdnet.c" diff --git a/src/osdnet.c b/src/osdnet.c index 2c6d4b5..4e5f859 100644 --- a/src/osdnet.c +++ b/src/osdnet.c @@ -36,10 +36,31 @@ # include "osdnet.h" /* Insurance to make sure our defs are there */ #endif +#if KLH10_NET_TAP +#include +#endif + /* Local predeclarations */ struct ifent *osn_iflookup(char *ifnam); +static struct ifent *osn_iftab_addaddress(char *name, struct sockaddr *addr); +#if KLH10_NET_PCAP +static void osn_pfinit_pcap(struct pfdata *pfdata, struct osnpf *osnpf, void *pfarg); +static ssize_t osn_pfread_pcap(struct pfdata *pfdata, void *buf, size_t nbytes); +static int osn_pfwrite_pcap(struct pfdata *pfdata, const void *buf, size_t nbytes); +#endif /* KLH10_NET_PCAP */ +#if KLH10_NET_TUN || KLH10_NET_TAP +static void osn_pfinit_tuntap(struct pfdata *pfdata, struct osnpf *osnpf, void *pfarg); +static void osn_pfdeinit_tuntap(struct pfdata *pfdata, struct osnpf *osnpf); +static ssize_t osn_pfread_fd(struct pfdata *pfdata, void *buf, size_t nbytes); +static int osn_pfwrite_fd(struct pfdata *pfdata, const void *buf, size_t nbytes); +#endif /* TUN || TAP */ + +#if KLH10_NET_BRIDGE +struct tuntap_context; +void bridge_create(struct tuntap_context *tt_ctx, struct osnpf *osnpf); +#endif /* Get a socket descriptor suitable for general net interface examination and manipulation; this is not necessarily suitable for @@ -104,8 +125,6 @@ static int iftab_initf = 0; static int iftab_nifs = 0; static struct ifent iftab[NETIFC_MAX]; -static struct ifent * -osn_iftab_addaddress(char *name, struct sockaddr *addr); /* Get table of all interfaces, using our own generic entry format. * @@ -385,7 +404,7 @@ osn_ifcreate(char *ifnam) if (!ife && iftab_nifs < NETIFC_MAX) { ife = &iftab[iftab_nifs]; iftab_nifs++; - strncpy(ife->ife_name, name, IFNAMSIZ); + strncpy(ife->ife_name, ifnam, IFNAMSIZ); ife->ife_name[IFNAMSIZ] = '\0'; } @@ -789,7 +808,7 @@ osn_pfeaget(int pfs, /* Packetfilter socket or FD */ } ea_set(eap, endp.end_addr); -#elif KLH10_NET_TAP_BRIDGE +#elif KLH10_NET_TAP /* 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. @@ -987,7 +1006,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 || CENV_SYS_LINUX || KLH10_NET_TAP_BRIDGE \ +#if CENV_SYS_DECOSF || CENV_SYS_LINUX || KLH10_NET_TAP \ || (CENV_SYS_FREEBSD && defined(SIOCSIFLLADDR)) /* Common preamble code */ @@ -1046,7 +1065,7 @@ osn_ifeaset(int s, /* Socket for (AF_INET, SOCK_DGRAM, 0) */ if (ownsock) close(s); return FALSE; } -# elif KLH10_NET_TAP_BRIDGE +# elif KLH10_NET_TAP ea_set(&emhost_ea, newpa); # else # error "Unimplemented OS routine osn_ifeaset()" @@ -1159,9 +1178,67 @@ osn_ifmcset(int s, * very OSD. * FD is always opened for both read/write. */ -#if KLH10_NET_PCAP void osn_pfinit(struct pfdata *pfdata, struct osnpf *osnpf, void *pfarg) +{ + char *method = osnpf->osnpf_ifmeth; + + if (!method) + method = ""; + + if (DP_DBGFLG) + dbprint("osn_pfinit: ifmeth=%s", method); + + /* + * The order of tests here is the order of preference + * (most desired first), for when the user does not + * spefify ifmeth=xxx. + */ +#if KLH10_NET_TUN && OSN_USE_IPONLY + if (!method[0] || !strcmp(method, "tun")) { + pfdata->pf_meth = PF_METH_TUN; + return osn_pfinit_tuntap(pfdata, osnpf, pfarg); + } +#endif /* KLH10_NET_TUN */ +#if KLH10_NET_TAP + /* Also match tap+bridge */ + if (!method[0] || !strncmp(method, "tap", 3)) { + pfdata->pf_meth = PF_METH_TAP; + return osn_pfinit_tuntap(pfdata, osnpf, pfarg); + } +#endif /* KLH10_NET_TAP */ +#if KLH10_NET_PCAP + if (!method[0] || !strcmp(method, "pcap")) { + pfdata->pf_meth = PF_METH_PCAP; + return osn_pfinit_pcap(pfdata, osnpf, pfarg); + } +#endif /* KLH10_NET_PCAP */ + +} + +ssize_t +osn_pfread(struct pfdata *pfdata, void *buf, size_t nbytes) +{ + return pfdata->pf_read(pfdata, buf, nbytes); +} + +int +osn_pfwrite(struct pfdata *pfdata, const void *buf, size_t nbytes) +{ + return pfdata->pf_write(pfdata, buf, nbytes); +} + +void +osn_pfdeinit(struct pfdata *pfdata, struct osnpf *osnpf) +{ + if (pfdata->pf_deinit) + pfdata->pf_deinit(pfdata, osnpf); +} + +#if KLH10_NET_PCAP +static +void +osn_pfinit_pcap(struct pfdata *pfdata, struct osnpf *osnpf, void *pfarg) { char errbuf[PCAP_ERRBUF_SIZE]; char *what = ""; @@ -1178,6 +1255,10 @@ osn_pfinit(struct pfdata *pfdata, struct osnpf *osnpf, void *pfarg) ifnam = ife->ife_name; } + pfdata->pf_meth = PF_METH_PCAP; + pfdata->pf_read = osn_pfread_pcap; + pfdata->pf_write = osn_pfwrite_pcap; + pfdata->pf_deinit = NULL; pfdata->pf_handle = pc = pcap_create(ifnam, errbuf); pfdata->pf_ip4_only = FALSE; @@ -1194,10 +1275,10 @@ osn_pfinit(struct pfdata *pfdata, struct osnpf *osnpf, void *pfarg) WARNING: NetBSD does not implement this correctly! The code in src/sys/net/bpf.c:bpfread() treats the immediate flag in a way that - causes it to return EWOULDBLOCK [[ note: I see EAGAIN]] if no input is - available. But this flag must still be set in order for bpfpoll() to - detect input as soon as it arrives! - See read loops in osn_pfread() below for workaround. + causes it to return EWOULDBLOCK if no input is available. But this flag + must still be set in order for bpfpoll() to detect input as soon as it + arrives! + See read loops in osn_pfread_pcap() below for workaround. */ if (pcap_set_immediate_mode(pc, 1) < 0) { what = "pcap_set_immediate_mode"; @@ -1224,7 +1305,7 @@ osn_pfinit(struct pfdata *pfdata, struct osnpf *osnpf, void *pfarg) to experiment. */ if (!osnpf->osnpf_dedic) { - struct OSN_PFSTRUCT *pf; + struct bpf_program *pf; /* Set the kernel packet filter */ pf = pfbuild(pfarg, &(osnpf->osnpf_ip.ia_addr)); @@ -1248,13 +1329,14 @@ osn_pfinit(struct pfdata *pfdata, struct osnpf *osnpf, void *pfarg) pfdata->pf_fd = pcap_get_selectable_fd(pc); - /* Now get our interface's ethernet address. - ** In general, this has to wait until after the packetfilter is opened, - ** since until then we don't have a handle on the specific interface - ** that will be used. - */ - //(void) osn_pfeaget(pfdata->pf_fd, ifnam, (unsigned char *)&(osnpf->osnpf_ea)); + /* Now get our interface's ethernet address. */ (void) osn_ifealookup(ifnam, (unsigned char *) &osnpf->osnpf_ea); + if (DP_DBGFLG) { + char eastr[OSN_EASTRSIZ]; + + dbprintln("EN addr for \"%s\" = %s", + ifnam, eth_adrsprint(eastr, (unsigned char *)&osnpf->osnpf_ea)); + } return; @@ -1280,7 +1362,7 @@ error: */ inline ssize_t -osn_pfread(struct pfdata *pfdata, void *buf, size_t nbytes) +osn_pfread_pcap(struct pfdata *pfdata, void *buf, size_t nbytes) { struct pcap_pkthdr pkt_header; const u_char *pkt_data; @@ -1295,7 +1377,7 @@ tryagain: memcpy(buf, pkt_data, nbytes); if (DP_DBGFLG) - dbprint("osn_pfread: read %d bytes", nbytes); + dbprint("osn_pfread_pcap: read %d bytes", nbytes); return nbytes; } @@ -1304,16 +1386,16 @@ tryagain: /* NetBSD bpf is broken. See osdnet.c:osn_pfinit() comments re BIOCIMMEDIATE to understand why this crock is necessary. - Always block for at least 10 sec, will wake up sooner if + Always block for at least 30 sec, will wake up sooner if input arrives. */ if (errno == EAGAIN || errno == EWOULDBLOCK) { - int ptimeout = 10; + int ptimeout = 30; struct pollfd myfd; int err = errno; if (DP_DBGFLG) - dbprint("osn_pfread: polling after reading nothing (err=%d)", err); + dbprint("osn_pfread_pcap: polling after reading nothing (err=%d)", err); myfd.fd = pfdata->pf_fd; myfd.events = POLLIN; (void) poll(&myfd, 1, ptimeout * 1000); @@ -1334,33 +1416,67 @@ tryagain: */ inline int -osn_pfwrite(struct pfdata *pfdata, const void *buf, size_t nbytes) +osn_pfwrite_pcap(struct pfdata *pfdata, const void *buf, size_t nbytes) { //if (DP_DBGFLG) // dbprint("osn_pfwrite: writing %d bytes", nbytes); return pcap_inject(pfdata->pf_handle, buf, nbytes); } -#endif +#endif /* KLH10_NET_PCAP */ -#if KLH10_NET_BPF +#if KLH10_NET_TUN || KLH10_NET_TAP /* Adapted from DEC's pfopen.c - doing it ourselves here because pfopen(3) * did not always exist, and this way we can report errors better. */ +struct tuntap_context { + int my_tap; + char saved_ifnam[IFNAM_LEN]; +#if KLH10_NET_BRIDGE + struct ifreq br_ifr; + struct ifreq tap_ifr; +#endif +}; + +/* + * Since each emulated device runs in its own process, + * we need only one of these. + */ +static struct tuntap_context tt_ctx; + +#define BASENAMESIZE 32 + static int -pfopen(void) +pfopen(char *basename, struct tuntap_context *tt_ctx, struct osnpf *osnpf) { -# define PFDEVPREF "/dev/bpf" - char pfname[sizeof(PFDEVPREF)+10]; + char pfname[BASENAMESIZE]; int fd; int i = 0; - /* Find first free packetfilter device */ - do { - (void) sprintf(pfname, "%s%d", PFDEVPREF, i++); - fd = open(pfname, O_RDWR, 0); - } while (fd < 0 && errno == EBUSY); /* If device busy, keep looking */ + if (DP_DBGFLG) + dbprint("pfopen: ifnam=%s", osnpf->osnpf_ifnam); + +#if CENV_SYS_NETBSD + /* See if an explicit tunnel unit number is given */ + if (isdigit(osnpf->osnpf_ifnam[3])) { + fd = pfopen_create(basename, tt_ctx, osnpf); + if (fd >= 0) { + return fd; + } + } +#endif /* CENV_SYS_NETBSD */ + + /* See if the device is a cloning device */ + fd = open(basename, O_RDWR, 0); + + if (fd < 0) { + /* Not a cloner. Find first free tunnel device. */ + do { + (void) snprintf(pfname, BASENAMESIZE, "%s%d", basename, i++); + fd = open(pfname, O_RDWR, 0); + } while (fd < 0 && errno == EBUSY); /* If device busy, keep looking */ + } if (fd < 0) { /* Note possible error meanings: @@ -1370,13 +1486,16 @@ pfopen(void) esfatal(1, "Couldn't find or open packetfilter device, last tried %s", pfname); } + + tt_ctx->my_tap = TRUE; + return fd; /* Success! */ } -#endif /* KLH10_NET_BPF */ +#endif /* KLH10_NET_TUN || _TAP */ -#if KLH10_NET_TUN +#if KLH10_NET_TUN || KLH10_NET_TAP /* In order to use the TUN interface we have to do the equivalent of (1) "ifconfig tun0 up" @@ -1432,31 +1551,27 @@ The ifra_mask field is ignored (left as-is or zeroed if new) unless */ void -osn_pfinit(struct pfdata *pfdata, struct osnpf *osnpf, void *arg) +osn_pfinit_tuntap(struct pfdata *pfdata, struct osnpf *osnpf, void *arg) { int allowextern = TRUE; /* For now, always try for external access */ int fd; -#if CENV_SYS_LINUX /* [BV: tun support for Linux] */ struct ifreq ifr; char ifnam[IFNAMSIZ]; -#else /* not CENV_SYS_LINUX */ - char tunname[sizeof "/dev/tun000"]; - char *ifnam = tunname + sizeof("/dev/")-1; - int i = -1; -#endif /* CENV_SYS_LINUX */ char ipb1[OSN_IPSTRSIZ]; char ipb2[OSN_IPSTRSIZ]; struct ifent *ife = NULL; /* Native host's default IP interface if one */ struct in_addr iplocal; /* TUN ifc address at hardware OS end */ - struct in_addr ipremote; /* Address at remote (emulated host) end */ + struct in_addr ipremote; /* Address at remote (emulated guest) end */ static unsigned char ipremset[4] = { 192, 168, 0, 44}; /* Remote address is always that of emulated machine */ ipremote = osnpf->osnpf_ip.ia_addr; iplocal = osnpf->osnpf_tun.ia_addr; + strncpy(tt_ctx.saved_ifnam, osnpf->osnpf_ifnam, IFNAM_LEN); if (DP_DBGFLG) - dbprint("Opening TUN device"); + dbprint("Opening %s device", + pfdata->pf_ip4_only ? "TUN" : "TAP"); /* Local address can be set explicitly if we plan to do full IP masquerading. */ @@ -1480,40 +1595,81 @@ osn_pfinit(struct pfdata *pfdata, struct osnpf *osnpf, void *arg) osnpf->osnpf_tun.ia_addr = iplocal; } -#if CENV_SYS_LINUX /* [BV: Linux way] */ - if ((fd = open("/dev/net/tun", O_RDWR)) < 0) /* get a fresh device */ - esfatal(0, "Couldn't open tunnel device /dev/net/tun"); - memset(&ifr, 0, sizeof(ifr)); -# if OSN_USE_IPONLY - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* TUN (no Ethernet headers), no pkt info */ - /* ip tuntap add mode tun */ -# else - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* TAP (yes Ethernet headers), no pkt info */ - /* ip tuntap add mode tap */ -# endif /* OSN_USE_IPONLY */ - if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) /* turn it on */ - esfatal(0, "Couldn't set tun device"); - strcpy(ifnam, ifr.ifr_name); /* get device name (typically "tun0") */ -#else /* not CENV_SYS_LINUX */ - do { -# if OSN_USE_IPONLY - sprintf(tunname, "/dev/tun%d", ++i); -# else - sprintf(tunname, "/dev/tap%d", ++i); -# endif /* OSN_USE_IPONLY */ - } while ((fd = open(tunname, O_RDWR)) < 0 && errno == EBUSY); + char *basename = ""; - if (fd < 0) - esfatal(1, "Couldn't open tunnel device %s", tunname); + switch (pfdata->pf_meth) { + case PF_METH_TUN: + pfdata->pf_ip4_only = TRUE; +#if CENV_SYS_LINUX + basename = "/dev/net/tun"; +#else + basename = "/dev/tun"; +#endif /* CENV_SYS_LINUX */ + break; + case PF_METH_TAP: + pfdata->pf_ip4_only = FALSE; +#if CENV_SYS_LINUX + basename = "/dev/net/tun"; +#else + basename = "/dev/tap"; +#endif /* CENV_SYS_LINUX */ + break; + default: + esfatal(0, "pf_meth value %d invalid", pfdata->pf_meth); + } + + fd = pfopen(basename, &tt_ctx, osnpf); + if (fd < 0) { + esfatal(0, "Couldn't open tunnel device %s", basename); + } + + memset(&ifr, 0, sizeof(ifr)); + +#if CENV_SYS_LINUX /* [BV: Linux way] */ + if (pfdata->pf_meth == PF_METH_TUN) { + ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* TUN (no Ethernet headers), no pkt info */ + /* ip tuntap add mode tun */ + } else { + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; /* TAP (yes Ethernet headers), no pkt info */ + /* ip tuntap add mode tap */ + } + if (isdigit(ifnam[3])) { + /* + * If a specific unit was requested, try to get it. + * I don't know if it will be created if it does not exist yet. + */ + strcpy(ifr.ifr_name, ifnam); + } + if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) /* turn it on */ + esfatal(0, "Couldn't set tun device"); + strcpy(ifnam, ifr.ifr_name); /* get device name (typically "tun0") */ #endif /* CENV_SYS_LINUX */ + /* + * This is mostly on NetBSD. + * Copy back the actual interface we used, if the user specified + * a cloner device. + * + * This does require us to clean up the tunnel in all cases, + * since from now in the NI20 or IMP is stuck on *this* unit number. + * Even when it is restarted (which is possible at least in + * TOPS20 with the KNILDR command. + */ +#if defined(TAPGIFNAME) + if (ioctl(fd, TAPGIFNAME, (void *) &ifr) >= 0) { /* Ask which unit we got */ + strncpy(ifnam, ifr.ifr_name, IFNAMSIZ); /* get device name (typically "tap0") */ + if (DP_DBGFLG) + dbprint("TAPGIFNAME returns %s", ifnam); + } +#endif + if (DP_DBGFLG) - dbprintln("Opened %s, configuring for local %s, remote %s", + dbprintln("Opened %s, configuring for local (host) %s, remote (guest) %s", ifnam, ip_adrsprint(ipb1, (unsigned char *)&iplocal), ip_adrsprint(ipb2, (unsigned char *)&ipremote)); - strcpy(osnpf->osnpf_ifnam, ifnam); + strncpy(osnpf->osnpf_ifnam, ifnam, IFNAM_LEN); /* Activate TUN device. First address is "local" -- doesn't matter if all we care about is @@ -1532,92 +1688,76 @@ osn_pfinit(struct pfdata *pfdata, struct osnpf *osnpf, void *arg) This is only needed for TUNNEL devices, not TAP devices. */ -#if 0 /* Hacky method */ - { - char cmdbuff[128]; - int res; - sprintf(cmdbuff, "ifconfig %s %s %s up", - ifnam, - ip_adrsprint(ipb1, (unsigned char *)&iplocal), - ip_adrsprint(ipb2, (unsigned char *)&ipremote)); - - if ((res = system(cmdbuff)) != 0) { - esfatal(1, "osn_pfinit: ifconfig failed to initialize tunnel device?"); - } - } -#elif CENV_SYS_LINUX /* [BV: Linux tun device] */ +#if CENV_SYS_LINUX /* [BV: Linux tun device] */ + if (pfdata->pf_ip4_only) { /* "Hacky" but simple method */ -# if OSN_USE_IPONLY - { - char cmdbuff[128]; - int res; + char cmdbuff[128]; + int res; - /* ifconfig DEV IPLOCAL pointopoint IPREMOTE */ - sprintf(cmdbuff, "ifconfig %s %s pointopoint %s up", - ifnam, - ip_adrsprint(ipb1, (unsigned char *)&iplocal), - ip_adrsprint(ipb2, (unsigned char *)&ipremote)); - if (DP_DBGFLG) - dbprintln("running \"%s\"",cmdbuff); - if ((res = system(cmdbuff)) != 0) { - esfatal(1, "osn_pfinit: ifconfig failed to initialize tunnel device?"); - } - } -# endif /* OSN_USE_IPONLY */ -#else /* not CENV_SYS_LINUX */ - { - /* Internal method */ - int s; - struct ifaliasreq ifra; - struct ifreq ifr; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - esfatal(1, "pf_init: tun socket() failed"); - } - - /* Delete first (only) IP address for this device, if any. - Ignore errors. - */ - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); - if (ioctl(s, SIOCDIFADDR, &ifr) < 0) { + /* ifconfig DEV IPLOCAL pointopoint IPREMOTE */ + sprintf(cmdbuff, "ifconfig %s %s pointopoint %s up", + ifnam, + ip_adrsprint(ipb1, (unsigned char *)&iplocal), + ip_adrsprint(ipb2, (unsigned char *)&ipremote)); if (DP_DBGFLG) - syserr(errno, "osn_pfinit tun SIOCDIFADDR failed"); - } - -# if OSN_USE_IPONLY - /* - * Then set the point-to-point addresses for the tunnel. - */ - memset(&ifra, 0, sizeof(ifra)); - strncpy(ifra.ifra_name, ifnam, sizeof(ifra.ifra_name)); - ((struct sockaddr_in *)(&ifra.ifra_addr))->sin_len = sizeof(struct sockaddr_in); - ((struct sockaddr_in *)(&ifra.ifra_addr))->sin_family = AF_INET; - ((struct sockaddr_in *)(&ifra.ifra_addr))->sin_addr = iplocal; - ((struct sockaddr_in *)(&ifra.ifra_broadaddr))->sin_len = sizeof(struct sockaddr_in); - ((struct sockaddr_in *)(&ifra.ifra_broadaddr))->sin_family = AF_INET; - ((struct sockaddr_in *)(&ifra.ifra_broadaddr))->sin_addr = ipremote; - if (ioctl(s, SIOCAIFADDR, &ifra) < 0) { - esfatal(1, "osn_pfinit tun SIOCAIFADDR failed"); - } -# endif /* OSN_USE_IPONLY */ - - - /* Finally, turn on IFF_UP just in case the above didn't do it. - Note interface name is still there from the SIOCDIFADDR. - */ - if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) { - esfatal(1, "osn_pfinit tun SIOCGIFFLAGS failed"); - } - if (!(ifr.ifr_flags & IFF_UP)) { - ifr.ifr_flags |= IFF_UP; - if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) { - esfatal(1, "osn_pfinit tun SIOCSIFFLAGS failed"); + dbprintln("running \"%s\"",cmdbuff); + if ((res = system(cmdbuff)) != 0) { + esfatal(1, "osn_pfinit: ifconfig failed to initialize tunnel device?"); + } + } +#else /* not CENV_SYS_LINUX */ + { + /* Internal method */ + int s; + struct ifaliasreq ifra; + struct ifreq ifr; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + esfatal(1, "pf_init: tun socket() failed"); + } + + /* Delete first (only) IP address for this device, if any. + Ignore errors. + */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCDIFADDR, &ifr) < 0) { + if (DP_DBGFLG) + syserr(errno, "osn_pfinit tun SIOCDIFADDR failed"); + } + + if (pfdata->pf_ip4_only) { + /* + * Then set the point-to-point addresses for the tunnel. + */ + memset(&ifra, 0, sizeof(ifra)); + strncpy(ifra.ifra_name, ifnam, sizeof(ifra.ifra_name)); + ((struct sockaddr_in *)(&ifra.ifra_addr))->sin_len = sizeof(struct sockaddr_in); + ((struct sockaddr_in *)(&ifra.ifra_addr))->sin_family = AF_INET; + ((struct sockaddr_in *)(&ifra.ifra_addr))->sin_addr = iplocal; + ((struct sockaddr_in *)(&ifra.ifra_broadaddr))->sin_len = sizeof(struct sockaddr_in); + ((struct sockaddr_in *)(&ifra.ifra_broadaddr))->sin_family = AF_INET; + ((struct sockaddr_in *)(&ifra.ifra_broadaddr))->sin_addr = ipremote; + if (ioctl(s, SIOCAIFADDR, &ifra) < 0) { + esfatal(1, "osn_pfinit tun SIOCAIFADDR failed"); + } + } + + /* Finally, turn on IFF_UP just in case the above didn't do it. + Note interface name is still there from the SIOCDIFADDR. + */ + if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) { + esfatal(1, "osn_pfinit tun SIOCGIFFLAGS failed"); + } + if (!(ifr.ifr_flags & IFF_UP)) { + ifr.ifr_flags |= IFF_UP; + if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) { + esfatal(1, "osn_pfinit tun SIOCSIFFLAGS failed"); + } + if (DP_DBGFLG) + dbprint("osn_pfinit tun did SIOCSIFFLAGS"); } - if (DP_DBGFLG) - dbprint("osn_pfinit tun did SIOCSIFFLAGS"); } - } #endif /* CENV_SYS_LINUX */ /* Now optionally determine ethernet address. @@ -1639,15 +1779,51 @@ osn_pfinit(struct pfdata *pfdata, struct osnpf *osnpf, void *arg) we're using TUN then we almost certainly also have the good stuff in ifconf. */ + + /* + * Now get our fresh new virtual interface's ethernet address. + * Basically, we can make it up. + */ + if (!pfdata->pf_ip4_only) { + /* 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(&osnpf->osnpf_ea, &emhost_ea); /* Return the ether address */ + + struct ifent *tap_ife = osn_ifcreate(ifnam); + if (tap_ife) { + tap_ife->ife_flags = IFF_UP; + ea_set(tap_ife->ife_ea, (unsigned char *)&osnpf->osnpf_ea); + tap_ife->ife_gotea = TRUE; + + if (DP_DBGFLG) { + dbprintln("Entered 10-side of TAP into table:"); + osn_iftab_show(stdout, &iftab[0], iftab_nifs); + } + } + } + if (allowextern && ife) { /* Need to determine ether addr of our default interface, then publish an ARP entry mapping the virtual host to the same ether addr. */ - (void) osn_arp_stuff(ifnam, (unsigned char *)&ipremote, ife->ife_ea, TRUE); +#if OSN_USE_IPONLY + /* dpni20 does this already; dpimp doesn't. */ + if (!pfdata->pf_ip4_only) { + (void) osn_arp_stuff(ifnam, (unsigned char *)&ipremote, &emhost_ea, TRUE); + } +#endif /* Return that as our ether address */ - ea_set((char *)&osnpf->osnpf_ea, ife->ife_ea); + //ea_set((char *)&osnpf->osnpf_ea, ife->ife_ea); // no, use emhost_ea as set up above } else { /* ARP hackery will be handled by IP masquerading and packet forwarding. */ #if 1 /*OSN_USE_IPONLY*/ /* TOPS-20 does not like NI20 with made up address? */ @@ -1665,32 +1841,44 @@ osn_pfinit(struct pfdata *pfdata, struct osnpf *osnpf, void *arg) } pfdata->pf_fd = fd; - pfdata->pf_handle = 0; + pfdata->pf_handle = &tt_ctx; pfdata->pf_can_filter = FALSE; - pfdata->pf_ip4_only = OSN_USE_IPONLY; + pfdata->pf_read = osn_pfread_fd; + pfdata->pf_write = osn_pfwrite_fd; + pfdata->pf_deinit = osn_pfdeinit_tuntap; + +#if KLH10_NET_BRIDGE + if (!strcmp(osnpf->osnpf_ifmeth, "tap+bridge")) { + /* Create the bridge */ + bridge_create(&tt_ctx, osnpf); + } +#endif /* KLH10_NET_BRIDGE */ if (DP_DBGFLG) dbprintln("osn_pfinit tun completed"); } -#endif /* KLH10_NET_TUN */ /* * Too bad that this is never called... */ void -osn_pfdeinit(void) +osn_pfdeinit_tuntap(struct pfdata *pfdata, struct osnpf *osnpf) { -#if KLH10_NET_TAP_BRIDGE - void tap_bridge_close(); - tap_bridge_close(); -#endif -} +#if KLH10_NET_BRIDGE + void tap_bridge_close(struct tuntap_context *tt_ctx); + tap_bridge_close(&tt_ctx); +#endif /* KLH10_NET_BRIDGE */ + struct tuntap_context *tt_ctx = pfdata->pf_handle; -#if KLH10_NET_TAP_BRIDGE + strncpy(osnpf->osnpf_ifnam, tt_ctx->saved_ifnam, IFNAM_LEN); +} +#endif /* KLH10_NET_TUN */ + +#if KLH10_NET_TAP_BRIDGE /* This part does nto work any more */ void -osn_pfinit(struct pfdata *pfdata, struct osnpf *osnpf, void *arg) +osn_pfinittap_bridge(struct pfdata *pfdata, struct osnpf *osnpf, void *arg) { int fd; char *ifnam = osnpf->osnpf_ifnam; @@ -1704,8 +1892,9 @@ osn_pfinit(struct pfdata *pfdata, struct osnpf *osnpf, void *arg) fd = tap_bridge_open(ifnam); - /* Now get our fresh new virtual interface's ethernet address. - */ + /* + * Now get our fresh new virtual interface's ethernet address. + */ (void) osn_pfeaget(fd, ifnam, (unsigned char *)&(osnpf->osnpf_ea)); struct ifent *ife = osn_ifcreate(ifnam); @@ -1717,22 +1906,21 @@ osn_pfinit(struct pfdata *pfdata, struct osnpf *osnpf, void *arg) pfdata->pf_fd = fd; pfdata->pf_handle = 0; - pfdata->pf_ip4_only = FALSE; pfdata->pf_can_filter = FALSE; } #endif /* KLH10_NET_TAP_BRIDGE */ -#if KLH10_NET_TAP_BRIDGE || KLH10_NET_TUN +#if KLH10_NET_TAP || KLH10_NET_TUN /* * Like the standard read(2) call: * Receives a single packet and returns its size. * Include link-layer headers, but no BPF headers or anything like that. */ -inline +static inline ssize_t -osn_pfread(struct pfdata *pfdata, void *buf, size_t nbytes) +osn_pfread_fd(struct pfdata *pfdata, void *buf, size_t nbytes) { return read(pfdata->pf_fd, buf, nbytes); } @@ -1742,24 +1930,16 @@ osn_pfread(struct pfdata *pfdata, void *buf, size_t nbytes) * Expect a full ethernet frame including link-layer header. * returns the number of bytes written. */ -inline +static inline int -osn_pfwrite(struct pfdata *pfdata, const void *buf, size_t nbytes) +osn_pfwrite_fd(struct pfdata *pfdata, const void *buf, size_t nbytes) { return write(pfdata->pf_fd, buf, nbytes); } -#endif /* KLH10_NET_TAP_BRIDGE || KLH10_NET_TUN */ +#endif /* KLH10_NET_TAP || KLH10_NET_TUN */ -#if KLH10_NET_TAP_BRIDGE - -#include -#include -#include - -static struct ifreq br_ifr; -static struct ifreq tap_ifr; -static int my_tap; +#if CENV_SYS_NETBSD /* * A TAP is a virtual ethernet interface, much like TUN is a virtual IP @@ -1774,37 +1954,59 @@ static int my_tap; * for instance. */ int -tap_bridge_open(char *ifnam) +pfopen_create(char *basename, struct tuntap_context *tt_ctx, struct osnpf *osnpf) { 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; + char *ifnam = osnpf->osnpf_ifnam; + + if (DP_DBGFLG) + dbprint("pfopen_create: ifnam=%s", osnpf->osnpf_ifnam); if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - esfatal(1, "tap_bridge_open: socket() failed"); + esfatal(1, "pfopen_create: 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); + memset(&tt_ctx->tap_ifr, 0, sizeof(tt_ctx->tap_ifr)); + strcpy(tt_ctx->tap_ifr.ifr_name, ifnam); + + res = ioctl(s, SIOCIFCREATE, &tt_ctx->tap_ifr); + if (res == 0) { - my_tap = 1; + tt_ctx->my_tap = TRUE; 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; + esfatal(1, "pfopen_create: can't create tap \"%s\"?", ifnam); + tt_ctx->my_tap = FALSE; dbprintln("Host-side tap \"%s\" alread exists; use it as-is", ifnam); } - sprintf(cmdbuff, "/dev/%s", ifnam); + /* 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, &tt_ctx->tap_ifr) < 0) { + esfatal(1, "pfopen_create tap SIOCGIFFLAGS failed"); + } + if (!(tt_ctx->tap_ifr.ifr_flags & IFF_UP)) { + tt_ctx->tap_ifr.ifr_flags |= IFF_UP; + if (ioctl(s, SIOCSIFFLAGS, &tt_ctx->tap_ifr) < 0) { + esfatal(1, "pfopen_create tap SIOCSIFFLAGS failed"); + } + if (DP_DBGFLG) + dbprint("pfopen_create tap did SIOCSIFFLAGS"); + } + + /* + * Combine basename with the unit number from the ifnam. + * Both "tun" and "tap" have 3 letters. + */ + sprintf(cmdbuff, "%s%s", basename, ifnam + 3); tapfd = open(cmdbuff, O_RDWR, 0); if (tapfd < 0) { @@ -1817,33 +2019,41 @@ tap_bridge_open(char *ifnam) 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"); - } + close(s); + + return tapfd; +} +#endif /* CENV_SYS_NETBSD */ + +#if KLH10_NET_BRIDGE + +#include + +void +bridge_create(struct tuntap_context *tt_ctx, struct osnpf *osnpf) +{ + int res; + char cmdbuff[128]; + struct ifent *ife; + int s; + int i; + + if (tt_ctx->my_tap) { + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + esfatal(1, "bridge_create: socket() failed"); + } - 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); + memset(&tt_ctx->br_ifr, 0, sizeof(tt_ctx->br_ifr)); + sprintf(tt_ctx->br_ifr.ifr_name, "bridge%d", i); + res = ioctl(s, SIOCIFCREATE, &tt_ctx->br_ifr); if (res == 0) break; if (errno != EEXIST) - esfatal(1, "tap_bridge_open: can't create bridge \"%s\"?", br_ifr.ifr_name); + esfatal(1, "bridge_create: can't create bridge \"%s\"?", tt_ctx->br_ifr.ifr_name); } - dbprintln("Created bridge \"%s\"", br_ifr.ifr_name); + dbprintln("Created bridge \"%s\"", tt_ctx->br_ifr.ifr_name); /* * Find default IP interface to bridge with. @@ -1857,60 +2067,19 @@ tap_bridge_open(char *ifnam) 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)); + sprintf(cmdbuff, "/sbin/brconfig %s add %s add %s up", + tt_ctx->br_ifr.ifr_name, ife->ife_name, osnpf->osnpf_ifnam); + res = system(cmdbuff); + dbprintln("%s => %d", cmdbuff, res); - /* 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); } - close(s); - - return tapfd; /* Success! */ } void -tap_bridge_close() +tap_bridge_close(struct tuntap_context *tt_ctx) { - if (my_tap) { + if (tt_ctx->my_tap) { int s, res; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { @@ -1918,14 +2087,14 @@ tap_bridge_close() } /* Destroy bridge */ - res = ioctl(s, SIOCIFDESTROY, &br_ifr); - res = ioctl(s, SIOCIFDESTROY, &tap_ifr); + res = ioctl(s, SIOCIFDESTROY, &tt_ctx->br_ifr); + res = ioctl(s, SIOCIFDESTROY, &tt_ctx->tap_ifr); close(s); } } -#endif /* KLH10_NET_TAP_BRIDGE */ +#endif /* KLH10_NET_TAP */ #if KLH10_NET_DLPI diff --git a/src/osdnet.h b/src/osdnet.h index 75b31c4..a749eb1 100644 --- a/src/osdnet.h +++ b/src/osdnet.h @@ -59,43 +59,45 @@ #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 */ +#ifndef KLH10_NET_TUN /* IP Tunnel device */ # define KLH10_NET_TUN 0 #endif -#ifndef KLH10_NET_LNX /* Linux PF_PACKET interface */ -# define KLH10_NET_LNX 0 +#ifndef KLH10_NET_TAP /* Ethernet Tunnel device */ +# define KLH10_NET_TAP 0 +#endif +#ifndef KLH10_NET_BRIDGE /* Bridge (used with an Ethernet tunnel) */ +# define KLH10_NET_BRIDGE 0 #endif #ifndef KLH10_NET_PCAP /* pretty generic libpcap interface */ # define KLH10_NET_PCAP 0 #endif #if !(KLH10_NET_NIT || KLH10_NET_DLPI || KLH10_NET_BPF || KLH10_NET_PFLT || \ - KLH10_NET_LNX || KLH10_NET_PCAP || KLH10_NET_TUN || KLH10_NET_TAP_BRIDGE) + KLH10_NET_LNX || KLH10_NET_PCAP || KLH10_NET_TUN || KLH10_NET_BRIDGE) /* None explicitly specified, pick a reasonable default */ -# if ((CENV_SYS_NETBSD || CENV_SYS_FREEBSD || CENV_SYS_LINUX) && OSN_USE_IPONLY) +# undef KLH10_NET_PCAP +# define KLH10_NET_PCAP 1 + +# if (CENV_SYS_NETBSD || CENV_SYS_FREEBSD || CENV_SYS_LINUX) # undef KLH10_NET_TUN # define KLH10_NET_TUN 1 -# elif 0 -# undef KLH10_NET_PCAP -# define KLH10_NET_PCAP 1 -# elif (CENV_SYS_NETBSD || CENV_SYS_FREEBSD) -# undef KLH10_NET_TAP_BRIDGE -# define KLH10_NET_TAP_BRIDGE 1 +# undef KLH10_NET_TAP +# define KLH10_NET_TAP 1 +# undef KLH10_NET_BRIDGE +# define KLH10_NET_BRIDGE 1 + # elif CENV_SYS_DECOSF # undef KLH10_NET_PFLT # define KLH10_NET_PFLT 1 + # elif CENV_SYS_SUN # undef KLH10_NET_NIT # define KLH10_NET_NIT 1 + # elif CENV_SYS_SOLARIS # undef KLH10_NET_DLPI # define KLH10_NET_DLPI 1 -# elif CENV_SYS_LINUX -# undef KLH10_NET_LNX -# define KLH10_NET_LNX 1 + # else # error "Must specify a KLH10_NET_ configuration" # endif @@ -384,16 +386,32 @@ union ipaddr { struct in_addr ia_addr; }; +struct pfdata; +struct osnpf; + +typedef ssize_t (*osn_pfread_f)(struct pfdata *pfdata, void *buf, size_t nbytes); +typedef int (*osn_pfwrite_f)(struct pfdata *pfdata, const void *buf, size_t nbytes); +typedef void (*osn_pfdeinit_f)(struct pfdata *, struct osnpf *); + /* * A structure that aggregates information about the packet filter variant * which is in use. */ struct pfdata { int pf_fd; /* most but not all have a file descriptor */ + int pf_meth; /* which packet "filter" is in use */ void *pf_handle; /* pcap has a handle */ int pf_can_filter; /* has a packet filter built-in and enabled */ int pf_ip4_only; /* set TRUE for IP i/f; FALSE for ethernet i/f */ + osn_pfread_f pf_read; /* indirection to packet reading function */ + osn_pfwrite_f pf_write; /* indirection to packet writing function */ + osn_pfdeinit_f pf_deinit; /* indirection to closing function */ }; + +#define PF_METH_NONE 0 +#define PF_METH_PCAP 1 +#define PF_METH_TUN 2 +#define PF_METH_TAP 3 int osn_iftab_init(void); int osn_nifents(void); /* # of entries cached by osn_iftab_init */ @@ -437,9 +455,11 @@ struct osnpf { /* Arg struct for common initialization params */ union ipaddr osnpf_tun; /* INOUT: IP address host side of tunnel */ struct ether_addr osnpf_ea; /* OUT: ether address of ifc */ }; + + /* the void * is an argument to pass on to pfbuild() */ void osn_pfinit(struct pfdata *, struct osnpf *, void *); -void osn_pfdeinit(void); +void osn_pfdeinit(struct pfdata *, struct osnpf *); ssize_t osn_pfread(struct pfdata *pfdata, void *buf, size_t nbytes); int osn_pfwrite(struct pfdata *pfdata, const void *buf, size_t nbytes);