]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - VBLADE/vblade-master/freebsd.c
Adding root user check to ExtendPersistentImg (as in CreatePersistentImg) (#2633)
[Ventoy.git] / VBLADE / vblade-master / freebsd.c
1 /*
2 * Copyright (c) 2005, Stacey Son <sson (at) verio (dot) net>
3 * All rights reserved.
4 */
5
6 // freebsd.c: low level access routines for FreeBSD
7 #include "config.h"
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <sys/time.h>
15
16 #include <netinet/in.h>
17 #include <net/ethernet.h>
18 #include <net/bpf.h>
19 #include <net/if.h>
20 #include <net/if_arp.h>
21 #include <net/if_dl.h>
22 #include <net/route.h>
23
24 #include <sys/ioctl.h>
25 #include <sys/types.h>
26 #include <net/if.h>
27 #include <sys/stat.h>
28 #include <sys/disk.h>
29 #include <sys/select.h>
30 #include <sys/sysctl.h>
31
32 #include <fcntl.h>
33 #include <errno.h>
34
35 #include "dat.h"
36 #include "fns.h"
37
38 #define BPF_DEV "/dev/bpf0"
39
40 /* Packet buffer for getpkt() */
41 static uchar *pktbuf = NULL;
42 static int pktbufsz = 0;
43
44 int
45 dial(char *eth, int bufcnt)
46 {
47 char m;
48 int fd = -1;
49 struct bpf_version bv;
50 u_int v;
51 unsigned bufsize, linktype;
52 char device[sizeof BPF_DEV];
53 struct ifreq ifr;
54
55 struct bpf_program *bpf_program = create_bpf_program(shelf, slot);
56
57 strncpy(device, BPF_DEV, sizeof BPF_DEV);
58
59 /* find a bpf device we can use, check /dev/bpf[0-9] */
60 for (m = '0'; m <= '9'; m++) {
61 device[sizeof(BPF_DEV)-2] = m;
62
63 if ((fd = open(device, O_RDWR)) > 0)
64 break;
65 }
66
67 if (fd < 0) {
68 perror("open");
69 return -1;
70 }
71
72 if (ioctl(fd, BIOCVERSION, &bv) < 0) {
73 perror("BIOCVERSION");
74 goto bad;
75 }
76
77 if (bv.bv_major != BPF_MAJOR_VERSION ||
78 bv.bv_minor < BPF_MINOR_VERSION) {
79 fprintf(stderr,
80 "kernel bpf filter out of date\n");
81 goto bad;
82 }
83
84 /*
85 * Try finding a good size for the buffer; 65536 may be too
86 * big, so keep cutting it in half until we find a size
87 * that works, or run out of sizes to try.
88 *
89 */
90 for (v = 65536; v != 0; v >>= 1) {
91 (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
92
93 (void)strncpy(ifr.ifr_name, eth,
94 sizeof(ifr.ifr_name));
95 if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0)
96 break; /* that size worked; we're done */
97
98 if (errno != ENOBUFS) {
99 fprintf(stderr, "BIOCSETIF: %s: %s\n",
100 eth, strerror(errno));
101 goto bad;
102 }
103 }
104 if (v == 0) {
105 fprintf(stderr,
106 "BIOCSBLEN: %s: No buffer size worked\n", eth);
107 goto bad;
108 }
109
110 /* Allocate memory for the packet buffer */
111 pktbufsz = v;
112 if ((pktbuf = malloc(pktbufsz)) == NULL) {
113 perror("malloc");
114 goto bad;
115 }
116
117 /* Don't wait for buffer to be full or timeout */
118 v = 1;
119 if (ioctl(fd, BIOCIMMEDIATE, &v) < 0) {
120 perror("BIOCIMMEDIATE");
121 goto bad;
122 }
123
124 /* Only read incoming packets */
125 v = 0;
126 if (ioctl(fd, BIOCSSEESENT, &v) < 0) {
127 perror("BIOCSSEESENT");
128 goto bad;
129 }
130
131 /* Don't complete ethernet hdr */
132 v = 1;
133 if (ioctl(fd, BIOCSHDRCMPLT, &v) < 0) {
134 perror("BIOCSHDRCMPLT");
135 goto bad;
136 }
137
138 /* Get the data link layer type. */
139 if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
140 perror("BIOCGDLT");
141 goto bad;
142 }
143 linktype = v;
144
145 /* Get the filter buf size */
146 if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
147 perror("BIOCGBLEN");
148 goto bad;
149 }
150 bufsize = v;
151
152 if (ioctl(fd, BIOCSETF, (caddr_t)bpf_program) < 0) {
153 perror("BIOSETF");
154 goto bad;
155 }
156
157 free_bpf_program(bpf_program);
158 return(fd);
159
160 bad:
161 free_bpf_program(bpf_program);
162 close(fd);
163 return(-1);
164 }
165
166 int
167 getea(int s, char *eth, uchar *ea)
168 {
169 int mib[6];
170 size_t len;
171 char *buf, *next, *end;
172 struct if_msghdr *ifm;
173 struct sockaddr_dl *sdl;
174
175
176 mib[0] = CTL_NET; mib[1] = AF_ROUTE;
177 mib[2] = 0; mib[3] = AF_LINK;
178 mib[4] = NET_RT_IFLIST; mib[5] = 0;
179
180 if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
181 return (-1);
182 }
183
184 if (!(buf = (char *) malloc(len))) {
185 return (-1);
186 }
187
188 if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
189 free(buf);
190 return (-1);
191 }
192 end = buf + len;
193
194 for (next = buf; next < end; next += ifm->ifm_msglen) {
195 ifm = (struct if_msghdr *)next;
196 if (ifm->ifm_type == RTM_IFINFO) {
197 sdl = (struct sockaddr_dl *)(ifm + 1);
198 if (strncmp(&sdl->sdl_data[0], eth,
199 sdl->sdl_nlen) == 0) {
200 memcpy(ea, LLADDR(sdl), ETHER_ADDR_LEN);
201 break;
202 }
203
204 }
205
206 }
207
208 free(buf);
209 return(0);
210 }
211
212
213 #if 0
214 int
215 getsec(int fd, uchar *place, vlong lba, int nsec)
216 {
217 return pread(fd, place, nsec * 512, lba * 512);
218 }
219
220 int
221 putsec(int fd, uchar *place, vlong lba, int nsec)
222 {
223 return pwrite(fd, place, nsec * 512, lba * 512);
224 }
225 #endif
226
227 static int pktn = 0;
228 static uchar *pktbp = NULL;
229
230 int
231 getpkt(int fd, uchar *buf, int sz)
232 {
233 register struct bpf_hdr *bh;
234 register int pktlen, retlen;
235
236 if (pktn <= 0) {
237 if ((pktn = read(fd, pktbuf, pktbufsz)) < 0) {
238 perror("read");
239 exit(1);
240 }
241 pktbp = pktbuf;
242 }
243
244 bh = (struct bpf_hdr *) pktbp;
245 retlen = (int) bh->bh_caplen;
246 /* This memcpy() is currently needed */
247 memcpy(buf, (void *)(pktbp + bh->bh_hdrlen),
248 retlen > sz ? sz : retlen);
249 pktlen = bh->bh_hdrlen + bh->bh_caplen;
250
251 pktbp = pktbp + BPF_WORDALIGN(pktlen);
252 pktn -= (int) BPF_WORDALIGN(pktlen);
253
254 return retlen;
255 }
256
257 int
258 putpkt(int fd, uchar *buf, int sz)
259 {
260 return write(fd, buf, sz);
261 }
262
263 int
264 getmtu(int fd, char *name)
265 {
266 struct ifreq xx;
267 int s, n, p;
268
269 s = socket(AF_INET, SOCK_RAW, 0);
270 if (s == -1) {
271 perror("Can't get mtu");
272 return 1500;
273 }
274 xx.ifr_addr.sa_family = AF_INET;
275 snprintf(xx.ifr_name, sizeof xx.ifr_name, "%s", name);
276 n = ioctl(s, SIOCGIFMTU, &xx);
277 if (n == -1) {
278 perror("Can't get mtu");
279 return 1500;
280 }
281 close(s);
282 // FreeBSD bpf writes are capped at one PAGESIZE'd mbuf. As such we must
283 // limit our sector count. See FreeBSD PR 205164, OpenAoE/vblade #7.
284 p = getpagesize();
285 if (xx.ifr_mtu > p) {
286 return p;
287 }
288 return xx.ifr_mtu;
289 }
290
291 vlong
292 getsize(int fd)
293 {
294 off_t media_size;
295 vlong size;
296 struct stat s;
297 int n;
298
299 // Try getting disklabel from block dev
300 if ((n = ioctl(fd, DIOCGMEDIASIZE, &media_size)) != -1) {
301 size = media_size;
302 } else {
303 // must not be a block special dev
304 if (fstat(fd, &s) == -1) {
305 perror("getsize");
306 exit(1);
307 }
308 size = s.st_size;
309 }
310 printf("ioctl returned %d\n", n);
311 printf("%lld bytes\n", size);
312 return size;
313 }