Added sample rpld.conf file to load gPXE
[rpld.git] / bpf-nit.c
1 /*************************************************
2 *     rpld - an IBM style RIPL server            *
3 *************************************************/
4
5 /*
6  * bpf support code
7  * Copyright (C) 2001 YAMAMOTO Takashi <yamt@netbsd.org>.
8  *
9  * By using this file, you agree to the terms and conditions set
10  * forth in the LICENCE file which can be found at the top level of
11  * the rpld distribution.
12  */
13
14 static char rcsid[] =
15   "$Id: bpf-nit.c,v 1.5 2001/11/01 15:30:35 root Exp root $";
16
17 /*
18  * $Log: bpf-nit.c,v $
19  * Revision 1.5  2001/11/01 15:30:35  root
20  * #
21  *
22  * Revision 1.4  2001/11/01 15:28:23  root
23  * #
24  *
25  * Revision 1.3  2001/11/01 15:28:07  root
26  * #
27  *
28  * Revision 1.2  2001/11/01 15:26:29  root
29  * #
30  *
31  * Revision 1.1  2001/11/01 15:24:26  root
32  * #
33  *
34  *
35  */
36
37 #include <sys/ioctl.h>
38 #include <sys/socket.h>
39 #include <sys/types.h>
40 #include <sys/time.h>
41
42 #include <net/bpf.h>
43 #include <net/if.h>
44 #include <net/if_dl.h>
45 #include <net/if_ether.h>
46
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <ifaddrs.h>
50 #include <limits.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55
56 #include "project.h"
57 #include "nit.h"
58
59 #define BPF "/dev/bpf"
60 #ifndef min
61 #define min(a,b) (((a)<(b))?(a):(b))
62 #endif
63
64 static int bpf_open (const char *);
65
66 struct nit
67 {
68   int fd;
69   unsigned char lladdr[ETHER_ADDR_LEN];
70   size_t bufsize;
71   unsigned char *buf;
72 };
73
74 static void
75 get_hwaddr (unsigned char *name, unsigned char *addr)
76 {
77   struct ifaddrs *ifa0, *ifa;
78   struct sockaddr_dl *sdl = 0;
79
80   if (getifaddrs (&ifa0) == -1)
81     {
82       syslog (LOG_ERR, "get_hwaddr");
83       return;
84     }
85
86   for (ifa = ifa0; ifa; ifa = ifa->ifa_next)
87     {
88       if (ifa->ifa_addr->sa_family == AF_LINK)
89         {
90           if (!strcmp (ifa->ifa_name, (char *) name))
91             {
92               sdl = (void *) ifa->ifa_addr;
93             }
94         }
95     }
96
97   if (sdl && sdl->sdl_alen == ETHER_ADDR_LEN)
98     memcpy (addr, LLADDR (sdl), ETHER_ADDR_LEN);
99   else
100     syslog (LOG_ERR, "can't get hwaddr of %s", name);
101
102   freeifaddrs (ifa0);
103 }
104
105 void
106 nit_close (struct nit *n)
107 {
108
109   if (!n)
110     return;
111
112   close (n->fd);
113   free (n->buf);
114   free (n);
115 }
116
117 struct nit *
118 nit_open (char *name)
119 {
120   struct nit *nit = 0;
121
122   if (strlen (name) >= IFNAMSIZ)
123     {
124       syslog (LOG_ERR, "nit_open: too long if name");
125       goto err;
126     }
127
128   nit = malloc (sizeof (*nit));
129   if (!nit)
130     {
131       syslog (LOG_ERR, "nit_open: %s", strerror (errno));
132       goto err;
133     }
134
135   nit->bufsize = BPF_MAXBUFSIZE;
136   nit->buf = malloc (nit->bufsize);
137   if (!nit->buf)
138     {
139       syslog (LOG_ERR, "nit_open: %s", strerror (errno));
140       goto err;
141     }
142
143   nit->fd = bpf_open (name);
144   if (nit->fd == -1)
145     goto err;
146   get_hwaddr (name, nit->lladdr);
147
148   return nit;
149 err:
150   if (nit)
151     free (nit);
152
153   return 0;
154 }
155
156 unsigned char *
157 nit_mac (struct nit *n)
158 {
159
160   return n->lladdr;
161 }
162
163 int
164 nit_send (struct nit *n, unsigned char *frame, int len, unsigned char *to)
165 {
166   struct ether_header eh;
167   struct iovec iov[2];
168   ssize_t size;
169
170   memset (&eh, 0, sizeof (eh));
171   memcpy (eh.ether_dhost, to, ETHER_ADDR_LEN);
172   memcpy (eh.ether_shost, n->lladdr, ETHER_ADDR_LEN);
173
174   iov[0].iov_base = &eh;
175   iov[0].iov_len = sizeof (eh);
176   iov[1].iov_base = frame;
177   iov[1].iov_len = len;
178
179   size = writev (n->fd, iov, 2);
180   if (size != len + sizeof (eh))
181     {
182       syslog (LOG_ERR, "nit_send: %s", strerror (errno));
183       return -1;
184     }
185
186   return len;
187 }
188
189  /*ARGSUSED*/ int
190 nit_multicast (struct nit *n, unsigned char *mcaddr)
191 {
192   u_int flag = 1;
193
194   /* XXX */
195   if (ioctl (n->fd, BIOCPROMISC, &flag) == -1)
196     {
197       syslog (1, "BIOCPROMISC: %s", strerror (errno));
198       return -1;
199     }
200
201   return 0;
202 }
203
204 int
205 nit_recv (struct nit *n, unsigned char *buf, int len,
206           unsigned char *ufrom, struct timeval *tv)
207 {
208   fd_set fds;
209   ssize_t size;
210   int r;
211   struct bpf_hdr *bh;
212   struct ether_header *eh;
213   unsigned char *p;
214   u_int16_t etype;
215
216   FD_ZERO (&fds);
217   FD_SET (n->fd, &fds);
218
219   for (;;)
220     {
221       r = select (n->fd + 1, &fds, 0, 0, tv);
222       if (r > 0)
223         break;
224       if (r == 0)
225         return 0;
226       if (r == -1 && errno == EINTR)
227         continue;
228       syslog (LOG_ERR, "nit_recv: select: %s", strerror (errno));
229       return -1;
230     }
231
232   if (FD_ISSET (n->fd, &fds))
233     {
234       size = read (n->fd, n->buf, n->bufsize);
235       if (size == -1)
236         {
237           syslog (LOG_ERR, "read: %s", strerror (errno));
238           return -1;
239         }
240     }
241   else
242     return 0;                   /* XXX */
243
244   bh = (void *) n->buf;
245   size = min (len, bh->bh_datalen - ETHER_HDR_LEN);
246   p = n->buf + bh->bh_hdrlen;
247   eh = (void *) p;
248   p += ETHER_HDR_LEN;
249   if (!memcmp (eh->ether_shost, n->lladdr, ETHER_ADDR_LEN))
250     return 0;                   /* myself */
251   etype = ntohs (eh->ether_type);
252   if (etype > ETHERMTU || etype < ETHERMIN)
253     return 0;
254   size = min (size, etype);
255   memcpy (ufrom, eh->ether_shost, ETHER_ADDR_LEN);
256   memcpy (buf, p, size);
257
258   return size;
259 }
260
261 int
262 bpf_open (const char *ifname)
263 {
264   int fd;
265   int i, n;
266   char filename[PATH_MAX + 1];
267   u_int bufsize;
268   u_int flag;
269   struct ifreq ifr;
270
271   for (i = 0; i < 9; i++)
272     {
273       snprintf (filename, sizeof (filename), BPF "%u", i);
274       fd = open (filename, O_RDWR, 0);
275       if (fd == -1)
276         {
277           if (errno == EBUSY)
278             continue;
279           break;
280         }
281       else
282         break;
283     }
284
285   if (fd == -1)
286     {
287       syslog (1, "bpf_open: %s", filename);
288       goto err;
289     }
290
291   bufsize = BPF_MAXBUFSIZE;
292   if (ioctl (fd, BIOCSBLEN, &bufsize) == -1)
293     syslog (LOG_WARNING, "BIOCSBLEN: %s", strerror (errno));
294
295   memset (&ifr, 0, sizeof (ifr));
296   strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
297   if (ioctl (fd, BIOCSETIF, &ifr) == -1)
298     {
299       syslog (LOG_ERR, "BIOCSETIF: %s: %s", ifname, strerror (errno));
300       goto err;
301     }
302
303   flag = 1;
304   if (ioctl (fd, BIOCIMMEDIATE, &flag) == -1)
305     {
306       syslog (LOG_ERR, "BIOCIMMEDIATE: %s", strerror (errno));
307       goto err;
308     }
309
310   flag = 1;
311   if (ioctl (fd, BIOCSHDRCMPLT, &flag) == -1)
312     {
313       syslog (LOG_ERR, "BIOCSHDRCMPLT: %s", strerror (errno));
314       goto err;
315     }
316
317   return fd;
318 err:
319   if (fd != -1)
320     close (fd);
321
322   return -1;
323 }