Logo Search packages:      
Sourcecode: vblade version File versions  Download package

aoe.c

// aoe.c: the ATA over Ethernet virtual EtherDrive (R) blade
#include "config.h"
#include <stdio.h>
#include <string.h>
#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"

enum {
      Nmasks= 32,
      Alen= 6,
};

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
{
      uchar buf[2000];
      Conf *p;
      int i;

      p = (Conf *)buf;
      memset(p, 0, sizeof *p);
      memset(p->h.dst, 0xff, 6);
      memmove(p->h.src, mac, 6);
      p->h.type = htons(0x88a2);
      p->h.flags = Resp;
      p->h.maj = htons(shelf);
      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;
      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
isbcast(uchar *ea)            // replace with assembler routine
{
      uchar *b = (uchar *)"\377\377\377\377\377\377";

      return memcmp(ea, b, 6) == 0;
}

long long
getlba(uchar *p)
{
      vlong v;
      int i;

      v = 0;
      for (i = 0; i < 6; i++)
            v |= (vlong)(*p++) << i * 8;
      return v;
}

int
aoeata(Ata *p)    // do ATA reqeust
{
      Ataregs r;
      int len = 60;
      int n;

      r.lba = getlba(p->lba);
      r.sectors = p->sectors;
      r.feature = p->err;
      r.cmd = p->cmd;
      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
{
      int len;

      len = ntohs(p->len);
      if (QCMD(p) != Qread)
      if (len > Nconfig)
            return 0;   // if you can't play nice ...
      switch (QCMD(p)) {
      case Qtest:
            if (len != nconfig)
                  return 0;
            // fall thru
      case Qprefix:
            if (len > nconfig)
                  return 0;
            if (memcmp(config, p->data, len))
                  return 0;
            // fall thru
      case Qread:
            break;
      case Qset:
            if (nconfig)
            if (nconfig != len || memcmp(config, p->data, len)) {
                  p->h.flags |= Error;
                  p->h.error = ConfigErr;
                  break;
            }
            // fall thru
      case Qfset:
            nconfig = len;
            memcpy(config, p->data, nconfig);
            break;
      default:
            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 | QCMD(p);   // aoe v.1
      return nconfig + sizeof *p - sizeof p->data;
}

void
doaoe(Aoehdr *p)
{
      int len;

      switch (p->cmd) {
      case ATAcmd:
            len = aoeata((Ata*)p);
            break;
      case Config:
            len = confcmd((Conf *)p);
            if (len == 0)
                  return;
            break;
      default:
            p->error = BadCmd;
            len = 1024;
            break;
      }
      memmove(p->dst, p->src, 6);
      memmove(p->src, mac, 6);
      p->maj = htons(shelf);
      p->min = slot;
      p->flags |= Resp;
      if (putpkt(sfd, (uchar *) p, len) == -1) {
            perror("write to network");
            exit(1);
      }
}

void
aoe(void)
{
      Aoehdr *p;
      uchar *buf;
      int n, sh;
      enum { bufsz = 1<<16, };

      buf = malloc(bufsz);
      aoead(sfd);

      for (;;) {
            n = getpkt(sfd, buf, bufsz);
            if (n < 0) {
                  perror("read network");
                  exit(1);
            }
            if (n < 60)
                  continue;
            p = (Aoehdr *) buf;
            if (ntohs(p->type) != 0x88a2)
                  continue;
            if (p->flags & Resp)
                  continue;
            sh = ntohs(p->maj);
            if (sh != shelf && sh != (ushort)~0)
                  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 [ -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;
      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();
      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[0]);
      slot = atoi(argv[1]);
      size = getsize(bfd);
      size /= 512;
      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;
}


Generated by  Doxygen 1.6.0   Back to index