int main(int argc, char **argv) { int i; ethernet_t *ep; nwio_ethopt_t ethopt; nwio_ethstat_t ethstat; char hostname[1024]; struct hostent *hostent; struct sigaction sa; nwio_ipconf_t ipconf; asynchio_t asyn; ssize_t n; ipaddr_t ip_addr; rarp46_t rarp46; int fd; int n_eths; program= argv[0]; asyn_init(&asyn); debug= 0; i= 1; while (i < argc && argv[i][0] == '-') { char *opt= argv[i++]+1; if (opt[0] == '-' && opt[1] == 0) break; /* -- */ while (*opt != 0) switch (*opt++) { case 'd': debug= 1; if (between('0', *opt, '9')) debug= strtoul(opt, &opt, 10); break; default: usage(); } } if ((n_eths= (argc - i)) == 0) usage(); #if __minix_vmd /* Minix-vmd can handle all nets at once using async I/O. */ ethernets= allocate(n_eths * sizeof(ethernets[0])); for (i= 0; i < n_eths; i++) { ethernets[i].n= ifname2n(argv[argc - n_eths + i]); } #else /* Minix forks n-1 times to handle each net in a process each. */ for (i= 0; i < n_eths; i++) { if (i+1 < n_eths) { switch (fork()) { case -1: fatal("fork()"); case 0: break; default: continue; } } ethernets= allocate(1 * sizeof(ethernets[0])); ethernets[0].n= ifname2n(argv[argc - n_eths + i]); } n_eths= 1; #endif sa.sa_handler= onsig; sigemptyset(&sa.sa_mask); sa.sa_flags= 0; sigaction(SIGUSR1, &sa, NULL); sigaction(SIGUSR2, &sa, NULL); for (i= 0; i < n_eths; i++) { ep= ðernets[i]; if ((ep->eth_fd= open(ethdev(ep->n), O_RDWR)) < 0) fatal(ethdev(ep->n)); if (ioctl(ep->eth_fd, NWIOGETHSTAT, ðstat) < 0) { fprintf(stderr, "%s: %s: Unable to get eth statistics: %s\n", program, ethdev(ep->n), strerror(errno)); exit(1); } ep->eth_addr= ethstat.nwes_addr; if (debug >= 1) { printf("%s: Ethernet address is %s\n", ethdev(ep->n), ether_ntoa(&ep->eth_addr)); } ethopt.nweo_flags= NWEO_COPY | NWEO_EN_LOC | NWEO_EN_BROAD | NWEO_TYPESPEC; ethopt.nweo_type= HTONS(ETH_RARP_PROTO); if (ioctl(ep->eth_fd, NWIOSETHOPT, ðopt) < 0) { fprintf(stderr, "%s: %s: Unable to set eth options: %s\n", program, ethdev(ep->n), strerror(errno)); exit(1); } /* What are my address and netmask? */ if ((fd= open(ipdev(ep->n), O_RDWR)) < 0) fatal(ipdev(ep->n)); if (ioctl(fd, NWIOGIPCONF, &ipconf) < 0) fatal(ipdev(ep->n)); ep->ip_addr= ipconf.nwic_ipaddr; ep->ip_mask= ipconf.nwic_netmask; close(fd); if (debug >= 1) { printf("%s: IP address is %s / ", ipdev(ep->n), inet_ntoa(ep->ip_addr)); printf("%s\n", inet_ntoa(ep->ip_mask)); } } /* Wait for RARP requests, reply, repeat. */ for(;;) { fflush(NULL); /* Wait for a RARP request. */ for (i= 0; i < n_eths; i++) { ep= ðernets[i]; n= asyn_read(&asyn, ep->eth_fd, ep->packet, sizeof(ep->packet)); if (n != -1) break; if (errno != EINPROGRESS) { report(ethdev(ep->n)); sleep(10); } } /* RARP request? */ if (i < n_eths && n >= sizeof(rarp46) && (memcpy(&rarp46, ep->packet, sizeof(rarp46)), 1) && rarp46.a46_hdr == HTONS(RARP_ETHERNET) && rarp46.a46_pro == HTONS(ETH_IP_PROTO) && rarp46.a46_hln == 6 && rarp46.a46_pln == 4 && rarp46.a46_op == HTONS(RARP_REQUEST) ) { if ((ether_ntohost(hostname, &rarp46.a46_tha) == 0 || (rarp46.a46_tha.ea_addr[0] == 'v' && (memcpy(&ip_addr, rarp46.a46_tha.ea_addr+2, 4), 1) && (hostent= gethostbyaddr((char*) &ip_addr, 4, AF_INET)) != NULL && addhostname(hostname, hostent->h_name, rarp46.a46_tha.ea_addr[1]))) && (hostent= gethostbyname(hostname)) != NULL && hostent->h_addrtype == AF_INET ) { /* Host is found in the ethers file and the DNS, or the * ethernet address denotes a special additional address * used for implementing a TCP/IP stack in user space. */ for (i= 0; hostent->h_addr_list[i] != NULL; i++) { memcpy(&ip_addr, hostent->h_addr_list[i], sizeof(ipaddr_t)); /* Check if the address is on this network. */ if (((ip_addr ^ ep->ip_addr) & ep->ip_mask) == 0) break; } if (hostent->h_addr_list[i] != NULL) { rarp_reply(ep, hostname, ip_addr, rarp46.a46_tha); } else { if (debug >= 2) { printf("%s: Host '%s' (%s) is on the wrong net\n", ethdev(ep->n), hostname, ether_ntoa(&rarp46.a46_tha)); } } } else { if (debug >= 2) { printf("%s: RARP request from unknown host '%s'\n", ethdev(ep->n), ether_ntoa(&rarp46.a46_tha)); } } } /* Wait for another request. */ if (asyn_wait(&asyn, 0, NULL) < 0) { report("asyn_wait()"); sleep(10); } } }
int main(int argc, char **argv) { int i; struct servent *service; udpport_t route_port; nwio_udpopt_t udpopt; nwio_ipopt_t ipopt; asynchio_t asyn; time_t timeout; struct timeval tv; struct sigaction sa; char *offset_arg, *offset_end; long arg; udp_device= ip_device= nil; offset_arg= nil; for (i = 1; i < argc && argv[i][0] == '-'; i++) { char *p= argv[i] + 1; if (p[0] == '-' && p[1] == 0) { i++; break; } while (*p != 0) { switch (*p++) { case 'U': if (udp_device != nil) usage(); if (*p == 0) { if (++i == argc) usage(); p= argv[i]; } udp_device= p; p= ""; break; case 'I': if (ip_device != nil) usage(); if (*p == 0) { if (++i == argc) usage(); p= argv[i]; } ip_device= p; p= ""; break; case 'o': if (offset_arg != nil) usage(); if (*p == 0) { if (++i == argc) usage(); p= argv[i]; } offset_arg= p; p= ""; break; case 'b': bcast= 1; break; case 's': /*obsolete*/ break; case 'd': debug= 1; break; default: usage(); } } } if (i != argc) usage(); /* Debug level signals. */ sa.sa_handler= sig_handler; sigemptyset(&sa.sa_mask); sa.sa_flags= 0; sigaction(SIGUSR1, &sa, nil); sigaction(SIGUSR2, &sa, nil); if (udp_device == nil && (udp_device= getenv("UDP_DEVICE")) == nil) udp_device= UDP_DEVICE; if (ip_device == nil && (ip_device= getenv("IP_DEVICE")) == nil) ip_device= IP_DEVICE; if (offset_arg == nil) { priority_offset= PRIO_OFF_DEF; } else { arg= strtol(offset_arg, &offset_end, 0); if (*offset_end != 0 || (priority_offset= arg) != arg) usage(); } if ((service= getservbyname("route", "udp")) == nil) { fprintf(stderr, "irdpd: unable to look up the port number for the 'route' service\n"); exit(1); } route_port= (udpport_t) service->s_port; if ((rip_fd= open(udp_device, O_RDWR)) < 0) fatal(udp_device); udpopt.nwuo_flags= NWUO_COPY | NWUO_LP_SET | NWUO_DI_LOC | NWUO_EN_BROAD | NWUO_RP_SET | NWUO_RA_ANY | NWUO_RWDATALL | NWUO_DI_IPOPT; udpopt.nwuo_locport= route_port; udpopt.nwuo_remport= route_port; if (ioctl(rip_fd, NWIOSUDPOPT, &udpopt) < 0) fatal("setting UDP options failed"); if ((irdp_fd= open(ip_device, O_RDWR)) < 0) fatal(ip_device); ipopt.nwio_flags= NWIO_COPY | NWIO_EN_LOC | NWIO_EN_BROAD | NWIO_REMANY | NWIO_PROTOSPEC | NWIO_HDR_O_SPEC | NWIO_RWDATALL; ipopt.nwio_tos= 0; ipopt.nwio_ttl= 1; ipopt.nwio_df= 0; ipopt.nwio_hdropt.iho_opt_siz= 0; ipopt.nwio_rem= htonl(0xFFFFFFFFL); ipopt.nwio_proto= IPPROTO_ICMP; if (ioctl(irdp_fd, NWIOSIPOPT, &ipopt) < 0) fatal("can't configure ICMP channel"); asyn_init(&asyn); while (1) { ssize_t r; if (do_rip) { /* Try a RIP read. */ r= asyn_read(&asyn, rip_fd, rip_buf, sizeof(rip_buf)); if (r < 0) { if (errno == EIO) fatal(udp_device); if (errno != EINPROGRESS) report(udp_device); } else { now= time(nil); rip_incoming(r); } } if (do_rdisc) { /* Try an IRDP read. */ r= asyn_read(&asyn, irdp_fd, irdp_buf, sizeof(irdp_buf)); if (r < 0) { if (errno == EIO) fatal(ip_device); if (errno != EINPROGRESS) report(ip_device); } else { now= time(nil); irdp_incoming(r); } } fflush(stdout); /* Compute the next wakeup call. */ timeout= next_sol < next_advert ? next_sol : next_advert; /* Wait for a RIP or IRDP packet or a timeout. */ tv.tv_sec= timeout; tv.tv_usec= 0; if (asyn_wait(&asyn, 0, timeout == NEVER ? nil : &tv) < 0) { /* Timeout? */ if (errno != EINTR && errno != EAGAIN) fatal("asyn_wait()"); now= time(nil); time_functions(); } } }
int asyn_close(asynchio_t *asyn, int fd) { asyn_init(asyn); }