DF-2296 / fwhctl.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | /* * fwhctl.c -- root-only control helper for the fwdev.c verification * harness (/dev/fwhctl0). Emulates the FireWire peer / OHCI hardware: * * fwhctl maxrec N set fabricated fc->maxrec (10=S400, 11=S800) * fwhctl inject LEN inject received iso packet with stream.len=LEN * fwhctl spray N SIZE spray N x SIZE canary chunks (mixed-size zone) * fwhctl unspray free sprayed chunks * fwhctl resp L F emulate peer block response of L bytes, fill F * fwhctl spraychk report canary corruption (kernel dmesg + exit) * fwhctl dump FILE dump the captured "wire" payload to FILE */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <sys/ioctl.h> #include <stdint.h> #include "fwharness.h" int main(int argc, char **argv) { struct fwh_sprayreq sr; struct fwh_respreq rr; struct fwh_chkreq cr; u_int32_t v; int fd; if (argc < 2) { fprintf(stderr, "usage: fwhctl maxrec N | inject LEN | " "spray N SIZE | unspray | resp L F | spraychk | " "dump FILE\n"); return 2; } fd = open("/dev/fwhctl0", O_RDWR); if (fd < 0) { perror("open /dev/fwhctl0"); return 1; } if (strcmp(argv[1], "maxrec") == 0) { v = (u_int32_t)strtoul(argv[2], NULL, 0); if (ioctl(fd, FWHIOC_MAXREC, &v) != 0) { perror("ioctl"); return 1; } } else if (strcmp(argv[1], "inject") == 0) { v = (u_int32_t)strtoul(argv[2], NULL, 0); if (ioctl(fd, FWHIOC_INJECT, &v) != 0) { perror("ioctl"); return 1; } } else if (strcmp(argv[1], "spray") == 0) { sr.n = (u_int32_t)strtoul(argv[2], NULL, 0); sr.size = (u_int32_t)strtoul(argv[3], NULL, 0); if (ioctl(fd, FWHIOC_SPRAY, &sr) != 0) { perror("ioctl"); return 1; } } else if (strcmp(argv[1], "unspray") == 0) { ioctl(fd, FWHIOC_UNSPRAY, &v); } else if (strcmp(argv[1], "resp") == 0) { rr.paylen = (u_int32_t)strtoul(argv[2], NULL, 0); rr.fill = (u_int32_t)strtoul(argv[3], NULL, 0); if (ioctl(fd, FWHIOC_RESP, &rr) != 0) { perror("ioctl"); return 1; } } else if (strcmp(argv[1], "spraychk") == 0) { memset(&cr, 0, sizeof(cr)); if (ioctl(fd, FWHIOC_SPRAYCHK, &cr) != 0) { perror("ioctl"); return 1; } printf("fwhctl: spraychk corrupt=%u badwords=%u\n", cr.corrupt, cr.badwords); return (cr.corrupt ? 3 : 0); } else if (strcmp(argv[1], "spraypop") == 0) { if (ioctl(fd, FWHIOC_SPRAYPOP, &v) != 0) { perror("ioctl"); return 1; } } else if (strcmp(argv[1], "sprayfree") == 0) { v = (u_int32_t)strtoul(argv[2], NULL, 0); if (ioctl(fd, FWHIOC_SPRAYFREE, &v) != 0) { perror("ioctl"); return 1; } } else if (strcmp(argv[1], "spraydump") == 0) { static struct fwh_dumpreq dr; FILE *out; u_int i, j; dr.start = (argc > 3) ? strtoul(argv[3], NULL, 0) : 0; dr.n = FWH_DUMP_CHUNKS; if (ioctl(fd, FWHIOC_SPRAYDUMP, &dr) != 0) { perror("ioctl"); return 1; } out = fopen(argv[2], "w"); if (out == NULL) { perror(argv[2]); return 1; } for (i = 0; i < dr.n; i++) { fprintf(out, "chunk %u size %u\n", dr.chunk[i].idx, dr.chunk[i].size); for (j = 0; j < FWH_DUMP_HDR / 4; j++) { if ((j % 4) == 0) fprintf(out, " %04x:", j * 4); fprintf(out, " %08x", dr.chunk[i].data[j]); if ((j % 4) == 3) fprintf(out, "\n"); } } fclose(out); printf("fwhctl: dumped %u spray chunks to %s\n", dr.n, argv[2]); } else if (strcmp(argv[1], "dump") == 0) { static u_char buf[256 * 1024]; int out, n; n = read(fd, buf, sizeof(buf)); if (n <= 0) { perror("read"); return 1; } out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644); if (out < 0) { perror(argv[2]); return 1; } if (write(out, buf, n) != n) { perror("write"); return 1; } close(out); printf("fwhctl: dumped %d bytes to %s\n", n, argv[2]); } else { fprintf(stderr, "unknown op %s\n", argv[1]); return 2; } return 0; } |