diff -ur klh10-2.0a/src/Mk-lnx86.mk klh10-2.0a+rtc1/src/Mk-lnx86.mk --- klh10-2.0a/src/Mk-lnx86.mk Sat Nov 10 22:28:37 2001 +++ klh10-2.0a+rtc1/src/Mk-lnx86.mk Sat Jan 26 23:17:01 2002 @@ -27,7 +27,7 @@ -Wmissing-declarations -Wredundant-decls # Source definitions -CENVFLAGS = -DCENV_CPU_I386=1 -DCENV_SYS_LINUX=1 +CENVFLAGS = -DCENV_CPU_I386=1 -DCENV_SYS_LINUX=1 -DDIEHARD_ROUTING # 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 -ur klh10-2.0a/src/dpimp.c klh10-2.0a+rtc1/src/dpimp.c --- klh10-2.0a/src/dpimp.c Mon Nov 19 11:31:35 2001 +++ klh10-2.0a+rtc1/src/dpimp.c Sun Jan 27 02:04:16 2002 @@ -281,6 +281,7 @@ struct ether_addr ehost_ea; /* Emulated host ethernet addr */ struct ether_addr ihost_ea; /* IMP/Native host ethernet addr */ int eaflags = 0; +int ifx = 0; #define EAF_IHOST 01 /* ihost_ea is set - IMP/Native host EA */ #define EAF_EHOST 02 /* ehost_ea is set - Emulated host EA */ @@ -683,6 +684,7 @@ struct osnpf npf; npf.osnpf_ifnam = dpimp->dpimp_ifnam; + npf.osnpf_ifx = 0; npf.osnpf_dedic = FALSE; /* Force filtering always! */ npf.osnpf_rdtmo = dpimp->dpimp_rdtmo; npf.osnpf_backlog = dpimp->dpimp_backlog; @@ -693,6 +695,7 @@ ea_set(&npf.osnpf_ea, dpimp->dpimp_eth); /* Set requested ea if any */ pffd = osn_pfinit(&npf, (void *)dpimp); /* Will abort if fails */ ea_set(&ihost_ea, &npf.osnpf_ea); /* Copy actual ea if one */ + ifx = npf.osnpf_ifx; } } @@ -1242,6 +1245,15 @@ if ((i = ++(arpp->dpimpsh_arprefs)) < 0) i = arp_refreset(); at->at_lastref = i; +#ifdef EBUG_HEAVY /* DEBUG */ + if (swstatus) { + char ipbuf[OSN_IPSTRSIZ]; + char eabuf[OSN_EASTRSIZ]; + dbprintln("ARP found %s = %s", + ip_adrsprint(ipbuf, (unsigned char *)&ip), + eth_adrsprint(eabuf, (unsigned char *)eap)); + } +#endif return at; } @@ -1258,6 +1270,13 @@ } return at; } +#ifdef EBUG_HEAVY /* DEBUG */ + if (swstatus) { + char ipbuf[OSN_IPSTRSIZ]; + dbprintln("ARP fail %s", + ip_adrsprint(ipbuf, (unsigned char *)&ip)); + } +#endif return NULL; } @@ -1442,8 +1461,15 @@ arp.arp_pln = sizeof(arp.arp_spa); /* Ptcl address len */ arp.arp_op = htons(ARPOP_REPLY); /* Type REPLY */ +#if 0 + /* XXX This code seems to be quite questionable to me. + * arp.arp_spa is set twice (see below), further the + * length should probably be sizeof arp.arp_spa instead of + * ..._sha. I think it is superfluous and should be removed. --rtc + */ memcpy((char *)arp.arp_spa, /* Sender IP addr */ (char *)&ihost_ip, sizeof(arp.arp_sha)); +#endif /* Sender hdw addr and IP addr (that's us - the resolved info) */ ea_set(arp.arp_sha, &ihost_ea); /* Sender hdw addr */ @@ -1823,12 +1849,12 @@ switch (buff[SIH_HSIZ+SIL_TYP]) { case SIMT_HH: /* Regular Host-Host Message */ +#if KLH10_NET_TUN if (buff[SIH_HSIZ+SIL_LNK] != SILNK_IP) { error("Non-IP Host-Imp msg received: %#o", buff[SIH_HSIZ+SIL_LNK]); continue; } -#if KLH10_NET_TUN if (DBGFLG) dbprintln("net out = %d", rcnt - (SIH_HSIZ+SI_LDRSIZ)); if (write(pffd, &buff[SIH_HSIZ+SI_LDRSIZ], @@ -1836,6 +1862,36 @@ syserr(errno, "tun write() failed"); else { #else + if (buff[SIH_HSIZ+SIL_LNK] == SILNK_IP) { + /* Packet length is top aligned to word margin. Not to + * crop the trailing padding can cause problems with + * some TCP/IP implementations, so we try to fix it. + * For example rerouting it to raw IP under Linux + * causes the kernel to change the packet length and + * checksum in the IP header to include the garbage + * at the end into the packet, causing connections + * to choke. --rtc + */ + struct iphdr *ih = + (struct iphdr *) (buff + SIH_HSIZ + SI_LDRSIZ); + int diff = rcnt - SIH_HSIZ - SI_LDRSIZ - ntohs(ih->tot_len); +#ifdef EBUG_HEAVY /* DEBUG */ + if (diff > 0) { + rcnt -= diff; + fprintf(stderr, + "Corrected packet skew %d bytes\r\n", diff); + } else if (diff < 0) + fprintf(stderr, + "Unusual packet skew %d bytes\r\n", diff); +#else + if (diff > 0) + rcnt -= diff; +#endif + } + /* Non-IP is being routed in hi_iproute by injecting the IMP + * leader data into the lower three bytes of the native IP + * address. --rtc + */ if (hi_iproute(&ipdest, &buff[SIH_HSIZ], rcnt - SIH_HSIZ)) { ip_write(&ipdest, &buff[SIH_HSIZ+SI_LDRSIZ], rcnt - (SIH_HSIZ+SI_LDRSIZ)); @@ -1913,20 +1969,46 @@ return FALSE; } - /* Derive destination IP address from IMP leader */ - haddr.ia_addr = ihost_ip; /* Init with native IP addr */ - haddr.ia_octet[1] = lp[SIL_HST]; /* Set up host byte */ - haddr.ia_octet[2] = lp[SIL_IMP1]; /* High imp byte (old "logical host")*/ - haddr.ia_octet[3] = lp[SIL_IMP0]; /* Low byte of imp */ - + if (lp[SIL_LNK] != SILNK_IP) { + /* Non-IP traffic, derive destination IP address from IMP leader */ + haddr.ia_addr = ihost_ip; /* Init with native IP addr */ + haddr.ia_octet[1] = lp[SIL_HST]; /* Set up host byte */ + haddr.ia_octet[2] = lp[SIL_IMP1]; /* High imp byte (old "logical host")*/ + haddr.ia_octet[3] = lp[SIL_IMP0]; /* Low byte of imp */ + } else { + /* Directly route IP packets. */ + struct iphdr *ih = (struct iphdr *) (lp + SI_LDRSIZ); + haddr.ia_addr.s_addr = ih->daddr; + } +#ifdef EBUG_HEAVY /* DEBUG */ + { + char ipbuf[OSN_IPSTRSIZ]; + fprintf(stderr, "IP DEST PREROUTE = %s\r\n", + ip_adrsprint(ipbuf, (unsigned char *)&haddr.ia_addr)); + } +#endif /* Now see if address is local, or if gateway routing needed. */ if ((haddr.ia_addr.s_addr & ihost_nm.s_addr) == ihost_net.s_addr) { *ipa = haddr.ia_addr; /* Local, win! */ +#ifdef EBUG_HEAVY /* DEBUG */ + { + char ipbuf[OSN_IPSTRSIZ]; + fprintf(stderr, "IP DEST POSTROUTE LOCAL = %s\r\n", + ip_adrsprint(ipbuf, (unsigned char *)ipa)); + } +#endif return TRUE; } /* Yucko, need to substitute gateway address. Lotsa luck. */ *ipa = gwdef_ip; +#ifdef EBUG_HEAVY /* DEBUG */ + { + char ipbuf[OSN_IPSTRSIZ]; + fpprintf(stderr, "IP DEST POSTROUTE = %s\r\n", + ip_adrsprint(ipbuf, (unsigned char *)ipa)); + } +#endif return TRUE; } @@ -2031,8 +2113,12 @@ ** ever shows up on the output! */ # if DPIMP_DATAOFFSET /* New code, OK to simply prepend header */ - char *buf = (char *)(pp - ETHER_HDRSIZ); - memcpy(buf, (char *)hp, ETHER_HDRSIZ); + unsigned char *buf = pp - ETHER_HDRSIZ; + memcpy(buf, (unsigned char *)hp, ETHER_HDRSIZ); + /* XXX Shouldn't memmove be used here instead of memcpy? If + * this is copying data supplied by arp_req()/arp_reply(), the + * memory overlaps for sure. --rtc + */ # else /* Old code, does extra buffer copy */ unsigned char buf[MAXETHERLEN]; memcpy(buf, (char *)hp, ETHER_HDRSIZ); @@ -2048,20 +2134,75 @@ } #elif KLH10_NET_BPF || KLH10_NET_LNX - struct iovec iov[2]; - - iov[0].iov_base = (char *) hp; - iov[0].iov_len = ETHER_HDRSIZ; - iov[1].iov_base = pp; - iov[1].iov_len = cnt; + static struct sockaddr_ll sll = { + AF_PACKET, 0, 0, ARPHRD_ETHER, PACKET_OUTGOING, ETHER_ADRSIZ, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + }; +# if DPIMP_DATAOFFSET + /* FIXME This is quite unclean code. Nothing guarantees + * that there's nothing important between pp and hp in memory if + * ether_write is called from arp_req()/arp_reply(). Pray + * for it to nevertheless work. --rtc + */ + unsigned char *buf = pp - ETHER_HDRSIZ; + memmove(buf, hp, ETHER_HDRSIZ); +# else + unsigned char buf[MAXETHERLEN]; + memcpy(buf, (char *)hp, ETHER_HDRSIZ); + memcpy(buf+ETHER_HDRSIZ, pp, cnt); +# endif + /* Copy protocol type and destination hardware address. Some card + * drivers overwrite the appropriate ethernet header fields with these. + */ + memcpy(sll.sll_addr, buf, ETHER_ADRSIZ); + memcpy(&sll.sll_protocol, buf + 2 * ETHER_ADRSIZ, sizeof sll.sll_protocol); + sll.sll_ifindex = ifx; + +#ifdef DIEHARD_ROUTING + if (memcmp(sll.sll_addr, &ihost_ea, ETHER_ADRSIZ) == 0) { + static int fd = -1; + static struct sockaddr_in si = {AF_INET, 0, {0}}; + struct iphdr *ih = (struct iphdr *) pp; + unsigned int on = 1; + /* Linux does not handle any raw ethernet packets addressed to + * the local card's MAC sent via the AF_PACKET mechanism. + * So we try as hard as we can to get the kernel to see packets + * destined to it. --rtc + */ + /* The setsockopt should not really be required, doing anyway */ + if (fd == -1 && ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1 + || setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof on) == -1)) + error("socket()/setsockopt() failed - %s", dp_strerror(errno)); + else if (ntohs(sll.sll_protocol) == ETHERTYPE_IP) { +#ifdef EBUG_HEAVY /* DEBUG */ + fprintf(stderr, "WRITING TO RAWIP FD %d\r\n", fd); +#endif + si.sin_port = ih->protocol; + si.sin_addr.s_addr = ih->daddr; + if (sendto(fd, pp, cnt, 0, &si, sizeof si) == -1 && swstatus) { + char ipbuf[OSN_IPSTRSIZ]; + dbprintln("error for %s: %s", + ip_adrsprint(ipbuf, (unsigned char *)&ih->daddr), + dp_strerror(errno)); + } + return; + } else + /* This packet will probably disappear unhandled in ether. */ + dbprintln("Local proto %04X unhandled", ntohs(sll.sll_protocol)); + } +#endif if (DP_DBGFLG) dbprintln("net out = %d", cnt); +#ifdef EBUG_HEAVY /* DEBUG */ + fprintf(stderr, "WRITING TO ETHER #%d, FD %d\r\n", ifx, pffd); + dumppkt(buf, ETHER_HDRSIZ + cnt); +#endif - if (writev(pffd, iov, sizeof(iov)/sizeof(*iov)) < 0) { + if (sendto(pffd, buf, ETHER_HDRSIZ + cnt, 0, + (struct sockaddr *)&sll, sizeof sll) < 0) /* What to do here? For debugging, complain but return. */ - error("writev() failed - %s", dp_strerror(errno)); - } + error("sendto() failed - %s", dp_strerror(errno)); #elif KLH10_NET_TUN /* No code needed here -- routine never used */ #else diff -ur klh10-2.0a/src/kn10cpu.c klh10-2.0a+rtc1/src/kn10cpu.c --- klh10-2.0a/src/kn10cpu.c Mon Nov 19 11:43:06 2001 +++ klh10-2.0a+rtc1/src/kn10cpu.c Sat Jan 26 02:23:29 2002 @@ -3369,7 +3369,7 @@ { if (!cpu.mr_usrmode && cpu.mr_exsafe) { /* Barf just in case, but fall thru to let 10 monitor handle it */ - fprintf(stderr,"[KLH10: Illegal exec mode op, PC = %lo: %o %o,%lo]", + fprintf(stderr,"[KLH10: Illegal exec mode op, PC = %lo: %o %o,%lo]\r\n", (long)PC_30, op, ac, (long)e); if (cpu.mr_exsafe >= 2) apr_halt(HALT_EXSAFE); diff -ur klh10-2.0a/src/osdnet.c klh10-2.0a+rtc1/src/osdnet.c --- klh10-2.0a/src/osdnet.c Mon Nov 19 11:32:12 2001 +++ klh10-2.0a+rtc1/src/osdnet.c Sat Jan 26 23:28:29 2002 @@ -1756,7 +1756,6 @@ /* Open a socket of the desired type. */ struct sockaddr_ll sll; - int ifx; /* Get raw packets with ethernet headers */ @@ -1771,23 +1770,16 @@ esfatal(1, "Couldn't open packet socket"); /* Need ifc index in order to do binding, so get it. */ - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifcname, sizeof(ifr.ifr_name)); + memset(&ifr, 0, sizeof ifr); + strncpy(ifr.ifr_name, ifcname, sizeof ifr.ifr_name); if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0 ) esfatal(1, "SIOCGIFINDEX of %s failed", ifcname); - ifx = ifr.ifr_ifindex; - /* Bind to proper device/interface using ifc index */ - memset(&sll, 0, sizeof(sll)); - sll.sll_family = AF_PACKET; - sll.sll_protocol = htons(ETH_P_ALL); - sll.sll_ifindex = ifx; - if (bind(fd, (struct sockaddr *)&sll, sizeof(sll))) - esfatal(1, "bind to %s failed", ifcname); + osnpf->osnpf_ifx = ifr.ifr_ifindex; /* This code only works with Ethernet, so check for that */ - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifcname, sizeof(ifr.ifr_name)); + memset(&ifr, 0, sizeof ifr); + strncpy(ifr.ifr_name, ifcname, sizeof ifr.ifr_name); if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0 ) esfatal(1, "SIOCGIFHWADDR of %s failed", ifcname); @@ -1795,10 +1787,28 @@ efatal(1, "%s is not an ethernet - ARPHRD type %d", ifcname, ifr.ifr_hwaddr.sa_family); - /* Finally, attempt to determine current ethernet MAC address. + /* Attempt to determine current ethernet MAC address. Assume above call returned it in sa_data. */ - ea_set(&osnpf->osnpf_ea, &ifr.ifr_addr.sa_data[0]); + ea_set(&osnpf->osnpf_ea, ifr.ifr_addr.sa_data); + + /* Bind to proper device/interface using ifc index */ + memset(&sll, 0, sizeof sll); + sll.sll_family = AF_PACKET; + sll.sll_protocol = htons(ETH_P_ALL); + sll.sll_ifindex = osnpf->osnpf_ifx; + sll.sll_hatype = ARPHRD_ETHER; + sll.sll_pkttype = PACKET_HOST; + sll.sll_halen = ETHER_ADRSIZ; + memcpy(sll.sll_addr, &osnpf->osnpf_ea, ETHER_ADRSIZ); + /* This hardware address clobbers the ethernet header source + * address on some card drivers. + */ + /* Is home-brew ETHER_ADRSIZ really necessary? At least Linux provides + * ETH_ALEN in the shipped include files for this purpose. --rtc + */ + if (bind(fd, (struct sockaddr *) &sll, sizeof sll)) + esfatal(1, "bind to %s failed", ifcname); return fd; } diff -ur klh10-2.0a/src/osdnet.h klh10-2.0a+rtc1/src/osdnet.h --- klh10-2.0a/src/osdnet.h Mon Nov 19 11:33:39 2001 +++ klh10-2.0a+rtc1/src/osdnet.h Fri Jan 25 00:41:52 2002 @@ -107,6 +107,7 @@ # include /* For ntohl, htonl, in_addr */ # include /* Semi-std defs for: ether_addr, ether_header, ether_arp */ +# include /* For struct iphdr */ # define ossock_t int /* No typedef until code revised */ #endif /* CENV_SYS_UNIX */ @@ -375,6 +376,7 @@ struct osnpf { /* Arg struct for common initialization params */ char *osnpf_ifnam; /* Interface name */ + int osnpf_ifx; /* Interface index */ int osnpf_dedic; /* TRUE if dedicated ifc, else shared */ int osnpf_rdtmo; /* Read timeout, if any */ int osnpf_backlog; /* Allow # backlogged packets, if any */