Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/libexec/rbootd/bpf.c
34822 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1988, 1992 The University of Utah and the Center
5
* for Software Science (CSS).
6
* Copyright (c) 1992, 1993
7
* The Regents of the University of California. All rights reserved.
8
*
9
* This code is derived from software contributed to Berkeley by
10
* the Center for Software Science of the University of Utah Computer
11
* Science Department. CSS requests users of this software to return
12
* to [email protected] any improvements that they make and grant
13
* CSS redistribution rights.
14
*
15
* Redistribution and use in source and binary forms, with or without
16
* modification, are permitted provided that the following conditions
17
* are met:
18
* 1. Redistributions of source code must retain the above copyright
19
* notice, this list of conditions and the following disclaimer.
20
* 2. Redistributions in binary form must reproduce the above copyright
21
* notice, this list of conditions and the following disclaimer in the
22
* documentation and/or other materials provided with the distribution.
23
* 3. Neither the name of the University nor the names of its contributors
24
* may be used to endorse or promote products derived from this software
25
* without specific prior written permission.
26
*
27
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37
* SUCH DAMAGE.
38
*
39
* From: Utah Hdr: bpf.c 3.1 92/07/06
40
* Author: Jeff Forys, University of Utah CSS
41
*/
42
43
#include <sys/param.h>
44
#include <sys/ioctl.h>
45
#include <sys/socket.h>
46
#include <sys/time.h>
47
48
#include <net/if.h>
49
#include <net/bpf.h>
50
51
#include <ctype.h>
52
#include <errno.h>
53
#include <fcntl.h>
54
#include <stdio.h>
55
#include <stdlib.h>
56
#include <string.h>
57
#include <syslog.h>
58
#include <unistd.h>
59
#include "defs.h"
60
#include "pathnames.h"
61
62
static int BpfFd = -1;
63
static unsigned BpfLen = 0;
64
static u_int8_t *BpfPkt = NULL;
65
66
/*
67
** BpfOpen -- Open and initialize a BPF device.
68
**
69
** Parameters:
70
** None.
71
**
72
** Returns:
73
** File descriptor of opened BPF device (for select() etc).
74
**
75
** Side Effects:
76
** If an error is encountered, the program terminates here.
77
*/
78
int
79
BpfOpen(void)
80
{
81
struct ifreq ifr;
82
char bpfdev[32];
83
int n = 0;
84
85
/*
86
* Open the first available BPF device.
87
*/
88
do {
89
(void) sprintf(bpfdev, _PATH_BPF, n++);
90
BpfFd = open(bpfdev, O_RDWR);
91
} while (BpfFd < 0 && (errno == EBUSY || errno == EPERM));
92
93
if (BpfFd < 0) {
94
syslog(LOG_ERR, "bpf: no available devices: %m");
95
Exit(0);
96
}
97
98
/*
99
* Set interface name for bpf device, get data link layer
100
* type and make sure it's type Ethernet.
101
*/
102
(void) strncpy(ifr.ifr_name, IntfName, sizeof(ifr.ifr_name));
103
if (ioctl(BpfFd, BIOCSETIF, (caddr_t)&ifr) < 0) {
104
syslog(LOG_ERR, "bpf: ioctl(BIOCSETIF,%s): %m", IntfName);
105
Exit(0);
106
}
107
108
/*
109
* Make sure we are dealing with an Ethernet device.
110
*/
111
if (ioctl(BpfFd, BIOCGDLT, (caddr_t)&n) < 0) {
112
syslog(LOG_ERR, "bpf: ioctl(BIOCGDLT): %m");
113
Exit(0);
114
}
115
if (n != DLT_EN10MB) {
116
syslog(LOG_ERR,"bpf: %s: data-link type %d unsupported",
117
IntfName, n);
118
Exit(0);
119
}
120
121
/*
122
* On read(), return packets immediately (do not buffer them).
123
*/
124
n = 1;
125
if (ioctl(BpfFd, BIOCIMMEDIATE, (caddr_t)&n) < 0) {
126
syslog(LOG_ERR, "bpf: ioctl(BIOCIMMEDIATE): %m");
127
Exit(0);
128
}
129
130
/*
131
* Try to enable the chip/driver's multicast address filter to
132
* grab our RMP address. If this fails, try promiscuous mode.
133
* If this fails, there's no way we are going to get any RMP
134
* packets so just exit here.
135
*/
136
#ifdef MSG_EOR
137
ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
138
#endif
139
ifr.ifr_addr.sa_family = AF_UNSPEC;
140
memmove((char *)&ifr.ifr_addr.sa_data[0], &RmpMcastAddr[0], RMP_ADDRLEN);
141
if (ioctl(BpfFd, BIOCPROMISC, (caddr_t)0) < 0) {
142
syslog(LOG_ERR, "bpf: can't set promiscuous mode: %m");
143
Exit(0);
144
}
145
146
/*
147
* Ask BPF how much buffer space it requires and allocate one.
148
*/
149
if (ioctl(BpfFd, BIOCGBLEN, (caddr_t)&BpfLen) < 0) {
150
syslog(LOG_ERR, "bpf: ioctl(BIOCGBLEN): %m");
151
Exit(0);
152
}
153
if (BpfPkt == NULL)
154
BpfPkt = (u_int8_t *)malloc(BpfLen);
155
156
if (BpfPkt == NULL) {
157
syslog(LOG_ERR, "bpf: out of memory (%u bytes for bpfpkt)",
158
BpfLen);
159
Exit(0);
160
}
161
162
/*
163
* Write a little program to snarf RMP Boot packets and stuff
164
* it down BPF's throat (i.e. set up the packet filter).
165
*/
166
{
167
#define RMP ((struct rmp_packet *)0)
168
static struct bpf_insn bpf_insn[] = {
169
{ BPF_LD|BPF_B|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dsap },
170
{ BPF_JMP|BPF_JEQ|BPF_K, 0, 5, IEEE_DSAP_HP },
171
{ BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.cntrl },
172
{ BPF_JMP|BPF_JEQ|BPF_K, 0, 3, IEEE_CNTL_HP },
173
{ BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dxsap },
174
{ BPF_JMP|BPF_JEQ|BPF_K, 0, 1, HPEXT_DXSAP },
175
{ BPF_RET|BPF_K, 0, 0, RMP_MAX_PACKET },
176
{ BPF_RET|BPF_K, 0, 0, 0x0 }
177
};
178
#undef RMP
179
static struct bpf_program bpf_pgm = {
180
sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn
181
};
182
183
if (ioctl(BpfFd, BIOCSETF, (caddr_t)&bpf_pgm) < 0) {
184
syslog(LOG_ERR, "bpf: ioctl(BIOCSETF): %m");
185
Exit(0);
186
}
187
}
188
189
return(BpfFd);
190
}
191
192
/*
193
** BPF GetIntfName -- Return the name of a network interface attached to
194
** the system, or 0 if none can be found. The interface
195
** must be configured up; the lowest unit number is
196
** preferred; loopback is ignored.
197
**
198
** Parameters:
199
** errmsg - if no network interface found, *errmsg explains why.
200
**
201
** Returns:
202
** A (static) pointer to interface name, or NULL on error.
203
**
204
** Side Effects:
205
** None.
206
*/
207
char *
208
BpfGetIntfName(char **errmsg)
209
{
210
struct ifreq ibuf[8], *ifrp, *ifend, *mp;
211
struct ifconf ifc;
212
int fd;
213
int minunit, n;
214
char *cp;
215
static char device[sizeof(ifrp->ifr_name)];
216
static char errbuf[128] = "No Error!";
217
218
if (errmsg != NULL)
219
*errmsg = errbuf;
220
221
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
222
(void) strcpy(errbuf, "bpf: socket: %m");
223
return(NULL);
224
}
225
ifc.ifc_len = sizeof ibuf;
226
ifc.ifc_buf = (caddr_t)ibuf;
227
228
if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
229
ifc.ifc_len < sizeof(struct ifreq)) {
230
(void) strcpy(errbuf, "bpf: ioctl(SIOCGIFCONF): %m");
231
return(NULL);
232
}
233
ifrp = ibuf;
234
ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
235
236
mp = NULL;
237
minunit = 666;
238
for (; ifrp < ifend; ++ifrp) {
239
if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) {
240
(void) strcpy(errbuf, "bpf: ioctl(SIOCGIFFLAGS): %m");
241
return(NULL);
242
}
243
244
/*
245
* If interface is down or this is the loopback interface,
246
* ignore it.
247
*/
248
if ((ifrp->ifr_flags & IFF_UP) == 0 ||
249
#ifdef IFF_LOOPBACK
250
(ifrp->ifr_flags & IFF_LOOPBACK))
251
#else
252
(strcmp(ifrp->ifr_name, "lo0") == 0))
253
#endif
254
continue;
255
256
for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp)
257
;
258
n = atoi(cp);
259
if (n < minunit) {
260
minunit = n;
261
mp = ifrp;
262
}
263
}
264
265
(void) close(fd);
266
if (mp == NULL) {
267
(void) strcpy(errbuf, "bpf: no interfaces found");
268
return(NULL);
269
}
270
271
(void) strcpy(device, mp->ifr_name);
272
return(device);
273
}
274
275
/*
276
** BpfRead -- Read packets from a BPF device and fill in `rconn'.
277
**
278
** Parameters:
279
** rconn - filled in with next packet.
280
** doread - is True if we can issue a read() syscall.
281
**
282
** Returns:
283
** True if `rconn' contains a new packet, False otherwise.
284
**
285
** Side Effects:
286
** None.
287
*/
288
int
289
BpfRead(RMPCONN *rconn, int doread)
290
{
291
int datlen, caplen, hdrlen;
292
static u_int8_t *bp = NULL, *ep = NULL;
293
int cc;
294
295
/*
296
* The read() may block, or it may return one or more packets.
297
* We let the caller decide whether or not we can issue a read().
298
*/
299
if (doread) {
300
if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) {
301
syslog(LOG_ERR, "bpf: read: %m");
302
return(0);
303
} else {
304
bp = BpfPkt;
305
ep = BpfPkt + cc;
306
}
307
}
308
309
#define bhp ((struct bpf_hdr *)bp)
310
/*
311
* If there is a new packet in the buffer, stuff it into `rconn'
312
* and return a success indication.
313
*/
314
if (bp < ep) {
315
datlen = bhp->bh_datalen;
316
caplen = bhp->bh_caplen;
317
hdrlen = bhp->bh_hdrlen;
318
319
if (caplen != datlen)
320
syslog(LOG_ERR,
321
"bpf: short packet dropped (%d of %d bytes)",
322
caplen, datlen);
323
else if (caplen > sizeof(struct rmp_packet))
324
syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)",
325
caplen);
326
else {
327
rconn->rmplen = caplen;
328
memmove((char *)&rconn->tstamp, (char *)&bhp->bh_tstamp,
329
sizeof(struct timeval));
330
memmove((char *)&rconn->rmp, (char *)bp + hdrlen, caplen);
331
}
332
bp += BPF_WORDALIGN(caplen + hdrlen);
333
return(1);
334
}
335
#undef bhp
336
337
return(0);
338
}
339
340
/*
341
** BpfWrite -- Write packet to BPF device.
342
**
343
** Parameters:
344
** rconn - packet to send.
345
**
346
** Returns:
347
** True if write succeeded, False otherwise.
348
**
349
** Side Effects:
350
** None.
351
*/
352
int
353
BpfWrite(RMPCONN *rconn)
354
{
355
if (write(BpfFd, (char *)&rconn->rmp, rconn->rmplen) < 0) {
356
syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn));
357
return(0);
358
}
359
360
return(1);
361
}
362
363
/*
364
** BpfClose -- Close a BPF device.
365
**
366
** Parameters:
367
** None.
368
**
369
** Returns:
370
** Nothing.
371
**
372
** Side Effects:
373
** None.
374
*/
375
void
376
BpfClose(void)
377
{
378
struct ifreq ifr;
379
380
if (BpfPkt != NULL) {
381
free((char *)BpfPkt);
382
BpfPkt = NULL;
383
}
384
385
if (BpfFd == -1)
386
return;
387
388
#ifdef MSG_EOR
389
ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
390
#endif
391
ifr.ifr_addr.sa_family = AF_UNSPEC;
392
memmove((char *)&ifr.ifr_addr.sa_data[0], &RmpMcastAddr[0], RMP_ADDRLEN);
393
if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0)
394
(void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0);
395
396
(void) close(BpfFd);
397
BpfFd = -1;
398
}
399
400