|
@@ -5,39 +5,30 @@
|
|
#include <stdlib.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/types.h>
|
|
|
|
+#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <fcntl.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/in.h>
|
|
#include "dat.h"
|
|
#include "dat.h"
|
|
#include "fns.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
|
|
void
|
|
aoead(int fd) // advertise the virtual blade
|
|
aoead(int fd) // advertise the virtual blade
|
|
{
|
|
{
|
|
- int len;
|
|
|
|
uchar buf[2000];
|
|
uchar buf[2000];
|
|
Conf *p;
|
|
Conf *p;
|
|
|
|
+ int i;
|
|
|
|
|
|
p = (Conf *)buf;
|
|
p = (Conf *)buf;
|
|
memset(p, 0, sizeof *p);
|
|
memset(p, 0, sizeof *p);
|
|
@@ -49,12 +40,21 @@ aoead(int fd) // advertise the virtual blade
|
|
p->h.min = slot;
|
|
p->h.min = slot;
|
|
p->h.cmd = Config;
|
|
p->h.cmd = Config;
|
|
p->bufcnt = htons(Bufcount);
|
|
p->bufcnt = htons(Bufcount);
|
|
|
|
+ p->scnt = maxscnt = (getmtu(sfd, ifname) - sizeof (Ata)) / 512;
|
|
p->firmware = htons(FWV);
|
|
p->firmware = htons(FWV);
|
|
p->vercmd = 0x10 | Qread;
|
|
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");
|
|
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
|
|
int
|
|
@@ -82,68 +82,77 @@ aoeata(Ata *p) // do ATA reqeust
|
|
{
|
|
{
|
|
Ataregs r;
|
|
Ataregs r;
|
|
int len = 60;
|
|
int len = 60;
|
|
|
|
+ int n;
|
|
|
|
|
|
- if (p->sectors && (p->aflag & Write) == 0)
|
|
|
|
- len = sizeof (Ata);
|
|
|
|
r.lba = getlba(p->lba);
|
|
r.lba = getlba(p->lba);
|
|
r.sectors = p->sectors;
|
|
r.sectors = p->sectors;
|
|
r.feature = p->err;
|
|
r.feature = p->err;
|
|
r.cmd = p->cmd;
|
|
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->sectors = r.sectors;
|
|
p->err = r.err;
|
|
p->err = r.err;
|
|
p->cmd = r.status;
|
|
p->cmd = r.status;
|
|
return len;
|
|
return len;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#define QCMD(x) ((x)->vercmd & 0xf)
|
|
|
|
+
|
|
|
|
+// yes, this makes unnecessary copies.
|
|
|
|
+
|
|
int
|
|
int
|
|
confcmd(Conf *p) // process conf request
|
|
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:
|
|
case Qtest:
|
|
- len = qcget(buf, 1024);
|
|
|
|
- if (len != ntohs(p->len))
|
|
|
|
|
|
+ if (len != nconfig)
|
|
return 0;
|
|
return 0;
|
|
- if (memcmp(buf, p->data, len) != 0)
|
|
|
|
- return 0;
|
|
|
|
- memmove(p->data, buf, len);
|
|
|
|
- break;
|
|
|
|
|
|
+ // fall thru
|
|
case Qprefix:
|
|
case Qprefix:
|
|
- len = qcget(buf, 1024);
|
|
|
|
- len2 = ntohs(p->len);
|
|
|
|
- if (len2 > len)
|
|
|
|
|
|
+ if (len > nconfig)
|
|
return 0;
|
|
return 0;
|
|
- if (memcmp(buf, p->data, len2) != 0)
|
|
|
|
|
|
+ if (memcmp(config, p->data, len))
|
|
return 0;
|
|
return 0;
|
|
- memmove(p->data, buf, len);
|
|
|
|
- p->len = htons(len);
|
|
|
|
|
|
+ // fall thru
|
|
|
|
+ case Qread:
|
|
break;
|
|
break;
|
|
case Qset:
|
|
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.flags |= Error;
|
|
p->h.error = ConfigErr;
|
|
p->h.error = ConfigErr;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
// fall thru
|
|
// fall thru
|
|
case Qfset:
|
|
case Qfset:
|
|
- len = ntohs(p->len);
|
|
|
|
- qcset(p->data, len);
|
|
|
|
|
|
+ nconfig = len;
|
|
|
|
+ memcpy(config, p->data, nconfig);
|
|
break;
|
|
break;
|
|
default:
|
|
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->bufcnt = htons(Bufcount);
|
|
|
|
+ p->scnt = maxscnt = (getmtu(sfd, ifname) - sizeof (Ata)) / 512;
|
|
p->firmware = htons(FWV);
|
|
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
|
|
void
|
|
@@ -156,7 +165,8 @@ doaoe(Aoehdr *p)
|
|
len = aoeata((Ata*)p);
|
|
len = aoeata((Ata*)p);
|
|
break;
|
|
break;
|
|
case Config:
|
|
case Config:
|
|
- if ((len = confcmd((Conf *)p)) == 0)
|
|
|
|
|
|
+ len = confcmd((Conf *)p);
|
|
|
|
+ if (len == 0)
|
|
return;
|
|
return;
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
@@ -179,20 +189,22 @@ void
|
|
aoe(void)
|
|
aoe(void)
|
|
{
|
|
{
|
|
Aoehdr *p;
|
|
Aoehdr *p;
|
|
- uchar buf[1400];
|
|
|
|
|
|
+ uchar *buf;
|
|
int n, sh;
|
|
int n, sh;
|
|
|
|
+ enum { bufsz = 1<<16, };
|
|
|
|
|
|
|
|
+ buf = malloc(bufsz);
|
|
aoead(sfd);
|
|
aoead(sfd);
|
|
|
|
|
|
for (;;) {
|
|
for (;;) {
|
|
- n = getpkt(sfd, buf, sizeof buf);
|
|
|
|
|
|
+ n = getpkt(sfd, buf, bufsz);
|
|
if (n < 0) {
|
|
if (n < 0) {
|
|
perror("read network");
|
|
perror("read network");
|
|
exit(1);
|
|
exit(1);
|
|
}
|
|
}
|
|
if (n < 60)
|
|
if (n < 60)
|
|
continue;
|
|
continue;
|
|
- p = (Aoehdr *)buf;
|
|
|
|
|
|
+ p = (Aoehdr *) buf;
|
|
if (ntohs(p->type) != 0x88a2)
|
|
if (ntohs(p->type) != 0x88a2)
|
|
continue;
|
|
continue;
|
|
if (p->flags & Resp)
|
|
if (p->flags & Resp)
|
|
@@ -202,40 +214,119 @@ aoe(void)
|
|
continue;
|
|
continue;
|
|
if (p->min != slot && p->min != (uchar)~0)
|
|
if (p->min != slot && p->min != (uchar)~0)
|
|
continue;
|
|
continue;
|
|
|
|
+ if (nmasks && !maskok(p->src))
|
|
|
|
+ continue;
|
|
doaoe(p);
|
|
doaoe(p);
|
|
}
|
|
}
|
|
|
|
+ free(buf);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
void
|
|
usage(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);
|
|
progname);
|
|
exit(1);
|
|
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
|
|
int
|
|
main(int argc, char **argv)
|
|
main(int argc, char **argv)
|
|
{
|
|
{
|
|
|
|
+ int ch, omode = O_RDONLY;
|
|
|
|
+ struct stat s;
|
|
|
|
+
|
|
setbuf(stdin, NULL);
|
|
setbuf(stdin, NULL);
|
|
atainit();
|
|
atainit();
|
|
progname = *argv;
|
|
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();
|
|
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) {
|
|
if (bfd == -1) {
|
|
perror("open");
|
|
perror("open");
|
|
exit(1);
|
|
exit(1);
|
|
}
|
|
}
|
|
- shelf = atoi(argv[1]);
|
|
|
|
- slot = atoi(argv[2]);
|
|
|
|
|
|
+ shelf = atoi(argv[0]);
|
|
|
|
+ slot = atoi(argv[1]);
|
|
size = getsize(bfd);
|
|
size = getsize(bfd);
|
|
size /= 512;
|
|
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);
|
|
fflush(stdout);
|
|
aoe();
|
|
aoe();
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
+
|