|  | @@ -5,39 +5,30 @@
 | 
	
		
			
				|  |  |  #include <stdlib.h>
 | 
	
		
			
				|  |  |  #include <unistd.h>
 | 
	
		
			
				|  |  |  #include <sys/types.h>
 | 
	
		
			
				|  |  | +#include <sys/stat.h>
 | 
	
		
			
				|  |  |  #include <fcntl.h>
 | 
	
		
			
				|  |  |  #include <netinet/in.h>
 | 
	
		
			
				|  |  |  #include "dat.h"
 | 
	
		
			
				|  |  |  #include "fns.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -char cfg_str[1024];
 | 
	
		
			
				|  |  | -int cfg_str_len = 0;
 | 
	
		
			
				|  |  | +enum {
 | 
	
		
			
				|  |  | +	Nmasks= 32,
 | 
	
		
			
				|  |  | +	Alen= 6,
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -int
 | 
	
		
			
				|  |  | -qcget(uchar *p, int len)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -	if (len > cfg_str_len)
 | 
	
		
			
				|  |  | -		len = cfg_str_len;
 | 
	
		
			
				|  |  | -	memcpy(p, cfg_str, len);
 | 
	
		
			
				|  |  | -	return len;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -int
 | 
	
		
			
				|  |  | -qcset(uchar *p, int len)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -	if (len > sizeof(cfg_str))
 | 
	
		
			
				|  |  | -		len = sizeof(cfg_str);
 | 
	
		
			
				|  |  | -	memcpy(cfg_str, p, len);
 | 
	
		
			
				|  |  | -	cfg_str_len = len;
 | 
	
		
			
				|  |  | -	return len;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +uchar masks[Nmasks*Alen];
 | 
	
		
			
				|  |  | +int nmasks;
 | 
	
		
			
				|  |  | +char config[Nconfig];
 | 
	
		
			
				|  |  | +int nconfig = 0;
 | 
	
		
			
				|  |  | +int maxscnt = 2;
 | 
	
		
			
				|  |  | +char *ifname;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void
 | 
	
		
			
				|  |  |  aoead(int fd)			// advertise the virtual blade
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -	int len;
 | 
	
		
			
				|  |  |  	uchar buf[2000];
 | 
	
		
			
				|  |  |  	Conf *p;
 | 
	
		
			
				|  |  | +	int i;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	p = (Conf *)buf;
 | 
	
		
			
				|  |  |  	memset(p, 0, sizeof *p);
 | 
	
	
		
			
				|  | @@ -49,12 +40,21 @@ aoead(int fd)			// advertise the virtual blade
 | 
	
		
			
				|  |  |  	p->h.min = slot;
 | 
	
		
			
				|  |  |  	p->h.cmd = Config;
 | 
	
		
			
				|  |  |  	p->bufcnt = htons(Bufcount);
 | 
	
		
			
				|  |  | +	p->scnt = maxscnt = (getmtu(sfd, ifname) - sizeof (Ata)) / 512;
 | 
	
		
			
				|  |  |  	p->firmware = htons(FWV);
 | 
	
		
			
				|  |  |  	p->vercmd = 0x10 | Qread;
 | 
	
		
			
				|  |  | -	len = qcget(p->data, 1024);
 | 
	
		
			
				|  |  | -	p->len = htons(len);
 | 
	
		
			
				|  |  | -	if (putpkt(fd, buf, sizeof *p - sizeof p->data + len) == -1)
 | 
	
		
			
				|  |  | +	memcpy(p->data, config, nconfig);
 | 
	
		
			
				|  |  | +	p->len = htons(nconfig);
 | 
	
		
			
				|  |  | +	if (nmasks == 0)
 | 
	
		
			
				|  |  | +	if (putpkt(fd, buf, sizeof *p - sizeof p->data + nconfig) == -1) {
 | 
	
		
			
				|  |  |  		perror("putpkt aoe id");
 | 
	
		
			
				|  |  | +		return;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	for (i=0; i<nmasks; i++) {
 | 
	
		
			
				|  |  | +		memcpy(p->h.dst, &masks[i*Alen], Alen);
 | 
	
		
			
				|  |  | +		if (putpkt(fd, buf, sizeof *p - sizeof p->data + nconfig) == -1)
 | 
	
		
			
				|  |  | +			perror("putpkt aoe id");
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  int
 | 
	
	
		
			
				|  | @@ -82,68 +82,77 @@ aoeata(Ata *p)	// do ATA reqeust
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  	Ataregs r;
 | 
	
		
			
				|  |  |  	int len = 60;
 | 
	
		
			
				|  |  | +	int n;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	if (p->sectors && (p->aflag & Write) == 0)
 | 
	
		
			
				|  |  | -		len = sizeof (Ata);
 | 
	
		
			
				|  |  |  	r.lba = getlba(p->lba);
 | 
	
		
			
				|  |  |  	r.sectors = p->sectors;
 | 
	
		
			
				|  |  |  	r.feature = p->err;
 | 
	
		
			
				|  |  |  	r.cmd = p->cmd;
 | 
	
		
			
				|  |  | -	atacmd(&r, p->data);
 | 
	
		
			
				|  |  | +	if (atacmd(&r, (uchar *)(p+1), maxscnt*512) < 0) {
 | 
	
		
			
				|  |  | +		p->h.flags |= Error;
 | 
	
		
			
				|  |  | +		p->h.error = BadArg;
 | 
	
		
			
				|  |  | +		return len;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	if (!(p->aflag & Write))
 | 
	
		
			
				|  |  | +	if ((n = p->sectors)) {
 | 
	
		
			
				|  |  | +		n -= r.sectors;
 | 
	
		
			
				|  |  | +		len = sizeof (Ata) + (n*512);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  |  	p->sectors = r.sectors;
 | 
	
		
			
				|  |  |  	p->err = r.err;
 | 
	
		
			
				|  |  |  	p->cmd = r.status;
 | 
	
		
			
				|  |  |  	return len;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#define QCMD(x) ((x)->vercmd & 0xf)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// yes, this makes unnecessary copies.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  confcmd(Conf *p)	// process conf request
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -	uchar buf[1024];
 | 
	
		
			
				|  |  | -	int len = 0, len2;
 | 
	
		
			
				|  |  | +	int len;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	switch (p->vercmd & 0xf) {
 | 
	
		
			
				|  |  | -	case Qread:
 | 
	
		
			
				|  |  | -		len = qcget(p->data, 1024);
 | 
	
		
			
				|  |  | -		p->len = htons(len);
 | 
	
		
			
				|  |  | -		break;
 | 
	
		
			
				|  |  | +	len = ntohs(p->len);
 | 
	
		
			
				|  |  | +	if (QCMD(p) != Qread)
 | 
	
		
			
				|  |  | +	if (len > Nconfig)
 | 
	
		
			
				|  |  | +		return 0;	// if you can't play nice ...
 | 
	
		
			
				|  |  | +	switch (QCMD(p)) {
 | 
	
		
			
				|  |  |  	case Qtest:
 | 
	
		
			
				|  |  | -		len = qcget(buf, 1024);
 | 
	
		
			
				|  |  | -		if (len != ntohs(p->len))
 | 
	
		
			
				|  |  | +		if (len != nconfig)
 | 
	
		
			
				|  |  |  			return 0;
 | 
	
		
			
				|  |  | -		if (memcmp(buf, p->data, len) != 0)
 | 
	
		
			
				|  |  | -			return 0;
 | 
	
		
			
				|  |  | -		memmove(p->data, buf, len);
 | 
	
		
			
				|  |  | -		break;
 | 
	
		
			
				|  |  | +		// fall thru
 | 
	
		
			
				|  |  |  	case Qprefix:
 | 
	
		
			
				|  |  | -		len = qcget(buf, 1024);
 | 
	
		
			
				|  |  | -		len2 = ntohs(p->len);
 | 
	
		
			
				|  |  | -		if (len2 > len)
 | 
	
		
			
				|  |  | +		if (len > nconfig)
 | 
	
		
			
				|  |  |  			return 0;
 | 
	
		
			
				|  |  | -		if (memcmp(buf, p->data, len2) != 0)
 | 
	
		
			
				|  |  | +		if (memcmp(config, p->data, len))
 | 
	
		
			
				|  |  |  			return 0;
 | 
	
		
			
				|  |  | -		memmove(p->data, buf, len);
 | 
	
		
			
				|  |  | -		p->len = htons(len);
 | 
	
		
			
				|  |  | +		// fall thru
 | 
	
		
			
				|  |  | +	case Qread:
 | 
	
		
			
				|  |  |  		break;
 | 
	
		
			
				|  |  |  	case Qset:
 | 
	
		
			
				|  |  | -		len = qcget(buf, 1024);
 | 
	
		
			
				|  |  | -		if (len > 0 && (len != p->len || memcmp(buf, p->data, len))) {
 | 
	
		
			
				|  |  | +		if (nconfig)
 | 
	
		
			
				|  |  | +		if (nconfig != len || memcmp(config, p->data, len)) {
 | 
	
		
			
				|  |  |  			p->h.flags |= Error;
 | 
	
		
			
				|  |  |  			p->h.error = ConfigErr;
 | 
	
		
			
				|  |  |  			break;
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  		// fall thru
 | 
	
		
			
				|  |  |  	case Qfset:
 | 
	
		
			
				|  |  | -		len = ntohs(p->len);
 | 
	
		
			
				|  |  | -		qcset(p->data, len);
 | 
	
		
			
				|  |  | +		nconfig = len;
 | 
	
		
			
				|  |  | +		memcpy(config, p->data, nconfig);
 | 
	
		
			
				|  |  |  		break;
 | 
	
		
			
				|  |  |  	default:
 | 
	
		
			
				|  |  | -		p->h.flags |= BadArg;
 | 
	
		
			
				|  |  | +		p->h.flags |= Error;
 | 
	
		
			
				|  |  | +		p->h.error = BadArg;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | +	memmove(p->data, config, nconfig);
 | 
	
		
			
				|  |  | +	p->len = htons(nconfig);
 | 
	
		
			
				|  |  |  	p->bufcnt = htons(Bufcount);
 | 
	
		
			
				|  |  | +	p->scnt = maxscnt = (getmtu(sfd, ifname) - sizeof (Ata)) / 512;
 | 
	
		
			
				|  |  |  	p->firmware = htons(FWV);
 | 
	
		
			
				|  |  | -	p->vercmd |= 0x10;
 | 
	
		
			
				|  |  | -	return len + sizeof(Conf) - 1024;
 | 
	
		
			
				|  |  | +	p->vercmd = 0x10 | QCMD(p);	// aoe v.1
 | 
	
		
			
				|  |  | +	return nconfig + sizeof *p - sizeof p->data;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void
 | 
	
	
		
			
				|  | @@ -156,7 +165,8 @@ doaoe(Aoehdr *p)
 | 
	
		
			
				|  |  |  		len = aoeata((Ata*)p);
 | 
	
		
			
				|  |  |  		break;
 | 
	
		
			
				|  |  |  	case Config:
 | 
	
		
			
				|  |  | -		if ((len = confcmd((Conf *)p)) == 0)
 | 
	
		
			
				|  |  | +		len = confcmd((Conf *)p);
 | 
	
		
			
				|  |  | +		if (len == 0)
 | 
	
		
			
				|  |  |  			return;
 | 
	
		
			
				|  |  |  		break;
 | 
	
		
			
				|  |  |  	default:
 | 
	
	
		
			
				|  | @@ -179,20 +189,22 @@ void
 | 
	
		
			
				|  |  |  aoe(void)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |  	Aoehdr *p;
 | 
	
		
			
				|  |  | -	uchar buf[1400];
 | 
	
		
			
				|  |  | +	uchar *buf;
 | 
	
		
			
				|  |  |  	int n, sh;
 | 
	
		
			
				|  |  | +	enum { bufsz = 1<<16, };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	buf = malloc(bufsz);
 | 
	
		
			
				|  |  |  	aoead(sfd);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	for (;;) {
 | 
	
		
			
				|  |  | -		n = getpkt(sfd, buf, sizeof buf);
 | 
	
		
			
				|  |  | +		n = getpkt(sfd, buf, bufsz);
 | 
	
		
			
				|  |  |  		if (n < 0) {
 | 
	
		
			
				|  |  |  			perror("read network");
 | 
	
		
			
				|  |  |  			exit(1);
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  		if (n < 60)
 | 
	
		
			
				|  |  |  			continue;
 | 
	
		
			
				|  |  | -		p = (Aoehdr *)buf;
 | 
	
		
			
				|  |  | +		p = (Aoehdr *) buf;
 | 
	
		
			
				|  |  |  		if (ntohs(p->type) != 0x88a2)
 | 
	
		
			
				|  |  |  			continue;
 | 
	
		
			
				|  |  |  		if (p->flags & Resp)
 | 
	
	
		
			
				|  | @@ -202,40 +214,119 @@ aoe(void)
 | 
	
		
			
				|  |  |  			continue;
 | 
	
		
			
				|  |  |  		if (p->min != slot && p->min != (uchar)~0)
 | 
	
		
			
				|  |  |  			continue;
 | 
	
		
			
				|  |  | +		if (nmasks && !maskok(p->src))
 | 
	
		
			
				|  |  | +			continue;
 | 
	
		
			
				|  |  |  		doaoe(p);
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | +	free(buf);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void
 | 
	
		
			
				|  |  |  usage(void)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -	fprintf(stderr, "usage: %s <shelf> <slot> <ethn> <device>\n", 
 | 
	
		
			
				|  |  | +	fprintf(stderr, "usage: %s [ -m mac[,mac...] ] shelf slot netif filename\n", 
 | 
	
		
			
				|  |  |  		progname);
 | 
	
		
			
				|  |  |  	exit(1);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/* parseether from plan 9 */
 | 
	
		
			
				|  |  | +int
 | 
	
		
			
				|  |  | +parseether(uchar *to, char *from)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	char nip[4];
 | 
	
		
			
				|  |  | +	char *p;
 | 
	
		
			
				|  |  | +	int i;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	p = from;
 | 
	
		
			
				|  |  | +	for(i = 0; i < 6; i++){
 | 
	
		
			
				|  |  | +		if(*p == 0)
 | 
	
		
			
				|  |  | +			return -1;
 | 
	
		
			
				|  |  | +		nip[0] = *p++;
 | 
	
		
			
				|  |  | +		if(*p == 0)
 | 
	
		
			
				|  |  | +			return -1;
 | 
	
		
			
				|  |  | +		nip[1] = *p++;
 | 
	
		
			
				|  |  | +		nip[2] = 0;
 | 
	
		
			
				|  |  | +		to[i] = strtoul(nip, 0, 16);
 | 
	
		
			
				|  |  | +		if(*p == ':')
 | 
	
		
			
				|  |  | +			p++;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void
 | 
	
		
			
				|  |  | +setmask(char *ml)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	char *p;
 | 
	
		
			
				|  |  | +	int n;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for (; ml; ml=p) {
 | 
	
		
			
				|  |  | +		p = strchr(ml, ',');
 | 
	
		
			
				|  |  | +		if (p)
 | 
	
		
			
				|  |  | +			*p++ = '\0';
 | 
	
		
			
				|  |  | +		n = parseether(&masks[nmasks*Alen], ml);
 | 
	
		
			
				|  |  | +		if (n < 0)
 | 
	
		
			
				|  |  | +			fprintf(stderr, "ignoring mask %s, parseether failure\n", ml);
 | 
	
		
			
				|  |  | +		else
 | 
	
		
			
				|  |  | +			nmasks++;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +int
 | 
	
		
			
				|  |  | +maskok(uchar *ea)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int i, ok = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for (i=0; !ok && i<nmasks; i++)
 | 
	
		
			
				|  |  | +		ok = memcmp(ea, &masks[i*Alen], Alen) == 0;
 | 
	
		
			
				|  |  | +	return ok;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  main(int argc, char **argv)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | +	int ch, omode = O_RDONLY;
 | 
	
		
			
				|  |  | +	struct stat s;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	setbuf(stdin, NULL);
 | 
	
		
			
				|  |  |  	atainit();
 | 
	
		
			
				|  |  |  	progname = *argv;
 | 
	
		
			
				|  |  | -	if (argc != 5)
 | 
	
		
			
				|  |  | +	while ((ch = getopt(argc, argv, "m:")) != -1) {
 | 
	
		
			
				|  |  | +		switch (ch) {
 | 
	
		
			
				|  |  | +		case 'm':
 | 
	
		
			
				|  |  | +			setmask(optarg);
 | 
	
		
			
				|  |  | +			break;
 | 
	
		
			
				|  |  | +		case '?':
 | 
	
		
			
				|  |  | +		default:
 | 
	
		
			
				|  |  | +			usage();
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	argc -= optind;
 | 
	
		
			
				|  |  | +	argv += optind;
 | 
	
		
			
				|  |  | +	if (argc != 4)
 | 
	
		
			
				|  |  |  		usage();
 | 
	
		
			
				|  |  | -	bfd = open(argv[4], O_RDWR);
 | 
	
		
			
				|  |  | +	if (stat(argv[3], &s) < 0) {
 | 
	
		
			
				|  |  | +		perror("stat");
 | 
	
		
			
				|  |  | +		exit(1);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +	if (s.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))
 | 
	
		
			
				|  |  | +		omode = O_RDWR;
 | 
	
		
			
				|  |  | +	bfd = open(argv[3], omode);
 | 
	
		
			
				|  |  |  	if (bfd == -1) {
 | 
	
		
			
				|  |  |  		perror("open");
 | 
	
		
			
				|  |  |  		exit(1);
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	shelf = atoi(argv[1]);
 | 
	
		
			
				|  |  | -	slot = atoi(argv[2]);
 | 
	
		
			
				|  |  | +	shelf = atoi(argv[0]);
 | 
	
		
			
				|  |  | +	slot = atoi(argv[1]);
 | 
	
		
			
				|  |  |  	size = getsize(bfd);
 | 
	
		
			
				|  |  |  	size /= 512;
 | 
	
		
			
				|  |  | -	sfd = dial(argv[3]);
 | 
	
		
			
				|  |  | -	getea(sfd, argv[3], mac);
 | 
	
		
			
				|  |  | -	printf("pid %ld: e%d.%d, %lld sectors\n",
 | 
	
		
			
				|  |  | -		(long) getpid(), shelf, slot, size);
 | 
	
		
			
				|  |  | +	ifname = argv[2];
 | 
	
		
			
				|  |  | +	sfd = dial(ifname);
 | 
	
		
			
				|  |  | +	getea(sfd, ifname, mac);
 | 
	
		
			
				|  |  | +	printf("pid %ld: e%d.%d, %lld sectors %s\n",
 | 
	
		
			
				|  |  | +		(long) getpid(), shelf, slot, size,
 | 
	
		
			
				|  |  | +		omode == O_RDWR ? "O_RDWR" : "O_RDONLY");
 | 
	
		
			
				|  |  |  	fflush(stdout);
 | 
	
		
			
				|  |  |  	aoe();
 | 
	
		
			
				|  |  |  	return 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +
 |