/* $Id: isiboot.c,v 1.2 1999/12/26 14:33:33 nisimura Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Tohru Nishimura. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #define TRACE(l, x) if ((l) <= dbg) printf x #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Following data format depends on m68k order, and aligned harmful * to RISC processors. */ struct frame { u_int8_t dst[6]; u_int8_t src[6]; u_int16_t type; u_int16_t fill_0; u_int16_t seqno; u_int8_t opcode; u_int8_t fill_1; u_int8_t pos[4]; u_int8_t siz[4]; unsigned char data[1]; }; #define FRAMETYPE 0x80df #define FRAMELEN 1468 #define CPY32(x,y) { \ u_int8_t *p = (y); \ (x) = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; \ } while (0) struct station { int fd; char name[33]; char ifname[IFNAMSIZ]; u_int8_t addr[6]; } station; struct session { struct session *next; int state; FILE *file; u_int8_t addr[6]; } *activelist, *freelist; #define NEWPOOL 10 #define WAITING 0 /* implicit state after receiving the first frame */ #define OPENING 1 /* waiting for OPEN after CONNECT is received */ #define TRANSFER 2 /* data transferring state after OPEN is well done */ static char *state[] = { "WAITING", "OPENING", "TRANSFER" }; #define CONNECT 0 #define OPEN 1 #define READ 2 #define CLOSE 4 static char *op[] = { "CONNECT", "OPEN", "READ", "WRITE", "CLOSE", "FIND" }; void createbpfport(char *, char **, int *, struct station *); struct session *search(u_int8_t *); void closedown(struct session *); void makepool(void); char *etheraddr(u_int8_t *); int pickif(char *, u_int8_t *); #define NEQ(x,y) strcmp(x,y) #define FRAME(X) ((X)+((struct bpf_hdr *)X)->bh_hdrlen) char usage[] = "usage: %s [-i interface] [-s directory] [-d tracelevel]\n"; char devbpf[] = "/dev/bpf?"; main(argc, argv) int argc; char *argv[]; { int cc, nread, iolen, pos, siz, dbg; char *ifname, *bootwd, *p, *iobuf; struct session *cp; struct frame *fp; struct pollfd pollfd; static u_int8_t om[6] = { 0, 0, 0xA, 0, 0, 0 }; /* XXX */ if (geteuid() != 0) fprintf(stderr, "WARNING: run by non root priviledge\n"); ifname = bootwd = NULL; dbg = 0; while ((cc = getopt(argc, argv, "i:s:d:")) != -1) { switch (cc) { case 'i': ifname = optarg; break; case 's': bootwd = optarg; break; case 'd': dbg = atoi(optarg); break; default: fprintf(stderr, usage, argv[0]); exit(1); } } argv += optind; argc -= optind; memset(station.name, 0, sizeof(station.name)); gethostname(station.name, sizeof(station.name) - 1); if ((p = strchr(station.name, '.')) != NULL) *p = '\0'; createbpfport(ifname, &iobuf, &iolen, &station); if (bootwd != NULL && chroot(bootwd) < 0) { perror(argv[0]); exit(1); } pollfd.fd = station.fd; pollfd.events = POLLIN; for (;;) { poll(&pollfd, 1, INFTIM); read(pollfd.fd, iobuf, iolen); /* returns 1468 */ fp = (struct frame *)FRAME(iobuf); if (memcmp(fp->dst, om, 3) == 0) continue; cp = search(fp->src); TRACE(2, ("[%s] ", etheraddr(fp->src))); switch (cp->state) { case WAITING: if (fp->opcode != CONNECT) continue; else if (NEQ(fp->data, station.name)) { TRACE(3, ("'%s' not for me\n", fp->data)); continue; } cp->state = OPENING; TRACE(2, ("new connection\n")); break; case OPENING: if (fp->opcode != OPEN) goto aborting; /* out of phase */ cp->file = fopen(fp->data, "r"); if (cp->file == NULL) { TRACE(1, ("filed to open '%s'\n", fp->data)); goto closedown; /* no such file */ } cp->state = TRANSFER; TRACE(2, ("opened '%s'\n", fp->data)); break; case TRANSFER: if (fp->opcode == CLOSE) { TRACE(2, ("connection closed\n")); goto closedown; /* close request */ } if (fp->opcode != READ) goto aborting; /* out of phase */ CPY32(siz, fp->siz); CPY32(pos, fp->pos); nread = siz; if (fseek(cp->file, pos, 0L) < 0 || fread(fp->data, 1, nread, cp->file) < nread) { memset(fp->siz, 0, 4); /* corrupted file */ } TRACE(3, ("%d@%d\n", siz, pos)); break; aborting: TRACE(1, ("out of phase\n")); closedown: closedown(cp); fp->opcode = CLOSE; break; } memcpy(fp->dst, fp->src, 6); memcpy(fp->src, station.addr, 6); write(pollfd.fd, fp, FRAMELEN); } /* NOTREACHED */ } struct session * search(client) u_int8_t client[]; { struct session *cp; for (cp = activelist; cp; cp = cp->next) { if (memcmp(client, cp->addr, 6) == 0) return cp; } if (freelist == NULL) makepool(); cp = freelist; freelist = cp->next; cp->next = activelist; activelist = cp; cp->state = WAITING; cp->file = NULL; bcopy(client, cp->addr, 6); return cp; } void closedown(cp) struct session *cp; { struct session *cpp; cpp = activelist; if (cpp == cp) activelist = cp->next; else { do { if (cpp->next == cp) break; } while (NULL != (cpp = cpp->next)); /* should never happen */ cpp->next = cp->next; } cp->next = freelist; freelist = cp; if (cp->file) fclose(cp->file); cp->file = NULL; bzero(cp->addr, 6); } void makepool() { struct session *cp; int n; freelist = cp = malloc(sizeof(struct session) * NEWPOOL); for (n = 0; n < NEWPOOL; n++) { cp->next = cp + 1; memset(cp->addr, 0, 6); cp++; } cp[-1].next = NULL; } char * etheraddr(e) u_int8_t e[]; { static char address[18]; sprintf(address, "%x:%x:%x:%x:%x:%x", e[0], e[1], e[2], e[3], e[4], e[5]); return address; } static struct bpf_insn bpf_insn[] = { #define FRAMEHEADER ((struct frame *)0) { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&FRAMEHEADER->type }, { BPF_JMP|BPF_JEQ|BPF_K, 0, 1, FRAMETYPE }, { BPF_RET|BPF_K, 0, 0, FRAMELEN }, { BPF_RET|BPF_K, 0, 0, 0x0 } #undef FRAMEHEADER }; static struct bpf_program bpf_pgm = { sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn }; void createbpfport(ifname, iobufp, iolenp, st) char *ifname; char **iobufp; int *iolenp; struct station *st; { int n, fd; char xname[IFNAMSIZ]; u_int8_t dladdr[6]; n = 0; do { devbpf[8] = n + '0'; fd = open(devbpf, O_RDWR, 0); if (fd > 0) goto found; } while (errno != ENOENT && ++n < 10); fprintf(stderr, "No bpf device available\n"); exit(1); found: memset(xname, 0, sizeof(memset)); if (ifname != NULL) strcpy(xname, ifname); if (pickif(xname, dladdr) < 0) { fprintf(stderr, "No network interface available\n"); exit(1); } ioctl(fd, BIOCSETIF, xname); ioctl(fd, BIOCGDLT, &n); /* XXX - should check whether EN10MB */ n = 1; ioctl(fd, BIOCIMMEDIATE, &n); ioctl(fd, BIOCGBLEN, &n); ioctl(fd, BIOCSETF, &bpf_pgm); *iobufp = (char *)malloc(n); *iolenp = n; st->fd = fd; memcpy(st->ifname, xname, IFNAMSIZ); memcpy(st->addr, dladdr, 6); } int pickif(xname, dladdr) char *xname; u_int8_t dladdr[6]; { #define MATCH(x,v) ((v)==((v)&(x))) int s, len, excess, error; struct ifconf ifconfs; struct ifreq *ifr, reqbuf[32]; s = socket(AF_INET, SOCK_DGRAM, 0); ifconfs.ifc_len = sizeof(reqbuf); ifconfs.ifc_buf = (caddr_t)reqbuf; ioctl(s, SIOCGIFCONF, &ifconfs); ifr = ifconfs.ifc_req; len = ifconfs.ifc_len; error = -1; while (len > 0) { excess = ifr->ifr_addr.sa_len - sizeof(struct sockaddr); if (ifr->ifr_addr.sa_family == AF_LINK) { struct sockaddr_dl *sdl = (void *)&ifr->ifr_addr; memcpy(dladdr, (caddr_t)LLADDR(sdl), sdl->sdl_alen); ioctl(s, SIOCGIFFLAGS, ifr); if (MATCH(ifr->ifr_flags, IFF_UP|IFF_BROADCAST)) { if (xname[0] == '\0') { strcpy(xname, ifr->ifr_name); error = 0; break; } else if (strcmp(xname, ifr->ifr_name) == 0) { error = 0; break; } } } ifr += 1; len -= sizeof(struct ifreq); if (excess > 0) { ifr = (struct ifreq *)((char *)ifr + excess); len -= excess; } } close(s); return error; #undef MATCH }