📄 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;voidaoead(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"); }}intisbcast(uchar *ea) // replace with assembler routine{ uchar *b = (uchar *)"\377\377\377\377\377\377"; return memcmp(ea, b, 6) == 0;}long longgetlba(uchar *p){ vlong v; int i; v = 0; for (i = 0; i < 6; i++) v |= (vlong)(*p++) << i * 8; return v;}intaoeata(Ata *p, int pktlen) // 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, pktlen - sizeof(*p)) < 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.intconfcmd(Conf *p, int payload) // process conf request{ int len; len = ntohs(p->len); if (QCMD(p) != Qread) if (len > Nconfig || len > payload) 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;}voiddoaoe(Aoehdr *p, int n){ int len; enum { // config query header size CHDR_SIZ = sizeof(Conf) - sizeof(((Conf *)0)->data), }; switch (p->cmd) { case ATAcmd: if (n < sizeof(Ata)) return; len = aoeata((Ata*)p, n); break; case Config: if (n < CHDR_SIZ) return; len = confcmd((Conf *)p, n - CHDR_SIZ); 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); }}voidaoe(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 < sizeof(Aoehdr)) 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, n); } free(buf);}voidusage(void){ fprintf(stderr, "usage: %s [ -m mac[,mac...] ] shelf slot netif filename\n", progname); exit(1);}/* parseether from plan 9 */intparseether(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;}voidsetmask(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++; }}intmaskok(uchar *ea){ int i, ok = 0; for (i=0; !ok && i<nmasks; i++) ok = memcmp(ea, &masks[i*Alen], Alen) == 0; return ok;}intmain(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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -