Flash the Chrome EC lightbar when pf blocks a packet
1/*
2 * Copyright (c) 2016 joshua stein <jcs@jcs.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <sys/ioctl.h>
18#include <sys/socket.h>
19#include <err.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <pcap.h>
23#include <pwd.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <time.h>
27#include <unistd.h>
28
29#ifdef __amd64__
30#include <machine/chromeecvar.h>
31#else
32#error "this requires amd64"
33#endif
34
35int chromeec;
36time_t last_flash;
37
38void chromeec_set_seq(int);
39void chromeec_load_program(void);
40void have_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
41
42int
43main(int argc, char **argv)
44{
45 pcap_handler phandler = have_packet;
46 pcap_t *hpcap;
47 struct passwd *pw;
48 char errbuf[PCAP_ERRBUF_SIZE];
49
50 if ((pw = getpwnam("nobody")) == NULL)
51 errx(1, "nobody?");
52 endpwent();
53
54 if ((hpcap = pcap_open_live("pflog0", 1, 1, 500, errbuf)) == NULL)
55 errx(1, "failed pcap_open_live(pflog0): %s", errbuf);
56
57 if (pcap_datalink(hpcap) != DLT_PFLOG)
58 errx(1, "invalid datalink type");
59
60 if (ioctl(pcap_fileno(hpcap), BIOCLOCK) < 0)
61 err(1, "BIOCLOCK");
62
63 if ((chromeec = open("/dev/chromeec", O_RDWR)) == -1)
64 err(1, "open /dev/chromeec");
65
66 if (chroot("/var/empty") != 0 || chdir("/") != 0)
67 err(1, "suk");
68 if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
69 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
70 err(1, "setresgid/setresuid");
71
72 chromeec_load_program();
73 last_flash = time(NULL);
74
75 while (1) {
76 if (pcap_dispatch(hpcap, 1, phandler, NULL) < 0)
77 errx(1, "%s", pcap_geterr(hpcap));
78 }
79
80 return (0);
81}
82
83void chromeec_set_seq(int param)
84{
85 if (ioctl(chromeec, CHROMEEC_IOC_LIGHTBAR_SET_SEQ, ¶m) < 0)
86 err(1, "ioctl");
87}
88
89void chromeec_load_program(void)
90{
91 struct chromeec_lightbar_program p = { 0 };
92 int i = 0;
93
94 /* red */
95 p.data[i++] = CHROMEEC_LIGHTBAR_OPCODE_SET_COLOR_SINGLE;
96 p.data[i++] = 0xf4;
97 p.data[i++] = 0xff;
98
99 /* ramp as fast as possible */
100 p.data[i++] = CHROMEEC_LIGHTBAR_OPCODE_SET_RAMP_DELAY;
101 p.data[i++] = 0x00;
102 p.data[i++] = 0x00;
103 p.data[i++] = 0x00;
104 p.data[i++] = 0x01;
105
106 /* cycle once and end */
107 p.data[i++] = CHROMEEC_LIGHTBAR_OPCODE_ON;
108 p.data[i++] = CHROMEEC_LIGHTBAR_OPCODE_CYCLE_ONCE;
109 p.data[i++] = CHROMEEC_LIGHTBAR_OPCODE_OFF;
110 p.data[i++] = CHROMEEC_LIGHTBAR_OPCODE_HALT;
111
112 p.size = i;
113
114 /* if the ec happens to be in SEQ_STOP it won't respond, so force it
115 * back into s0 */
116 chromeec_set_seq(CHROMEEC_LIGHTBAR_SEQ_S0);
117
118 if (ioctl(chromeec, CHROMEEC_IOC_LIGHTBAR_SET_PROGRAM, &p) < 0)
119 err(1, "ioctl");
120}
121
122void
123have_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
124{
125 if (time(NULL) - last_flash <= 0)
126 return;
127
128 last_flash = time(NULL);
129
130 chromeec_set_seq(CHROMEEC_LIGHTBAR_SEQ_PROGRAM);
131}