]> git.ipfire.org Git - thirdparty/dhcp.git/blob - common/upf.c
Add can_receive_unicast_unconfigured
[thirdparty/dhcp.git] / common / upf.c
1 /* upf.c
2
3 Ultrix PacketFilter interface code.
4
5 /*
6 * Copyright (c) 1995, 1996, 1997, 1998, 1999
7 * The Internet Software Consortium. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38 * Enterprises. To learn more about the Internet Software Consortium,
39 * see ``http://www.vix.com/isc''. To learn more about Vixie
40 * Enterprises, see ``http://www.vix.com''.
41 */
42
43 #ifndef lint
44 static char copyright[] =
45 "$Id: upf.c,v 1.7 1999/03/13 18:53:15 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
46 #endif /* not lint */
47
48 #include "dhcpd.h"
49 #if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE)
50 #include <sys/ioctl.h>
51 #include <sys/uio.h>
52
53 #include <net/pfilt.h>
54 #include <netinet/in_systm.h>
55 #include "includes/netinet/ip.h"
56 #include "includes/netinet/udp.h"
57 #include "includes/netinet/if_ether.h"
58
59 /* Reinitializes the specified interface after an address change. This
60 is not required for packet-filter APIs. */
61
62 #ifdef USE_UPF_SEND
63 void if_reinitialize_send (info)
64 struct interface_info *info;
65 {
66 }
67 #endif
68
69 #ifdef USE_UPF_RECEIVE
70 void if_reinitialize_receive (info)
71 struct interface_info *info;
72 {
73 }
74 #endif
75
76 /* Called by get_interface_list for each interface that's discovered.
77 Opens a packet filter for each interface and adds it to the select
78 mask. */
79
80 int if_register_upf (info)
81 struct interface_info *info;
82 {
83 int sock;
84 char filename[50];
85 int b;
86 struct endevp param;
87
88 /* Open a UPF device */
89 for (b = 0; 1; b++) {
90 #ifndef NO_SNPRINTF
91 snprintf(filename, sizeof(filename), "/dev/pf/pfilt%d", b);
92 #else
93 sprintf(filename, "/dev/pf/pfilt%d", b);
94 #endif
95 sock = open (filename, O_RDWR, 0);
96 if (sock < 0) {
97 if (errno == EBUSY) {
98 continue;
99 } else {
100 log_fatal ("Can't find free upf: %m");
101 }
102 } else {
103 break;
104 }
105 }
106
107 /* Set the UPF device to point at this interface. */
108 if (ioctl (sock, EIOCSETIF, info -> ifp) < 0)
109 log_fatal ("Can't attach interface %s to upf device %s: %m",
110 info -> name, filename);
111
112 /* Get the hardware address. */
113 if (ioctl (sock, EIOCDEVP, &param) < 0)
114 log_fatal ("Can't get interface %s hardware address: %m",
115 info -> name);
116
117 /* We only know how to do ethernet. */
118 if (param.end_dev_type != ENDT_10MB)
119 log_fatal ("Invalid device type on network interface %s: %d",
120 info -> name, param.end_dev_type);
121
122 if (param.end_addr_len != 6)
123 log_fatal ("Invalid hardware address length on %s: %d",
124 info -> name, param.end_addr_len);
125
126 info -> hw_address.hlen = 6;
127 info -> hw_address.htype = ARPHRD_ETHER;
128 memcpy (&info -> hw_address.haddr [0], param.end_addr, 6);
129
130 return sock;
131 }
132 #endif /* USE_UPF_SEND || USE_UPF_RECEIVE */
133
134 #ifdef USE_UPF_SEND
135 void if_register_send (info)
136 struct interface_info *info;
137 {
138 /* If we're using the upf API for sending and receiving,
139 we don't need to register this interface twice. */
140 #ifndef USE_UPF_RECEIVE
141 info -> wfdesc = if_register_upf (info, interface);
142 #else
143 info -> wfdesc = info -> rfdesc;
144 #endif
145 if (!quiet_interface_discovery)
146 log_info ("Sending on UPF/%s/%s%s%s",
147 info -> name,
148 print_hw_addr (info -> hw_address.htype,
149 info -> hw_address.hlen,
150 info -> hw_address.haddr),
151 (info -> shared_network ? "/" : ""),
152 (info -> shared_network ?
153 info -> shared_network -> name : ""));
154 }
155 #endif /* USE_UPF_SEND */
156
157 #ifdef USE_UPF_RECEIVE
158 /* Packet filter program...
159 XXX Changes to the filter program may require changes to the constant
160 offsets used in if_register_send to patch the UPF program! XXX */
161
162
163 void if_register_receive (info)
164 struct interface_info *info;
165 {
166 int flag = 1;
167 u_int32_t addr;
168 struct enfilter pf;
169 u_int32_t bits;
170
171 /* Open a UPF device and hang it on this interface... */
172 info -> rfdesc = if_register_upf (info);
173
174 /* Allow the copyall flag to be set... */
175 if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0)
176 log_fatal ("Can't set ALLOWCOPYALL: %m");
177
178 /* Clear all the packet filter mode bits first... */
179 flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC |
180 ENNONEXCL | ENCOPYALL);
181 if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0)
182 log_fatal ("Can't clear pfilt bits: %m");
183
184 /* Set the ENBATCH and ENCOPYALL bits... */
185 bits = ENBATCH | ENCOPYALL;
186 if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0)
187 log_fatal ("Can't set ENBATCH|ENCOPYALL: %m");
188
189 /* Set up the UPF filter program. */
190 /* XXX Unlike the BPF filter program, this one won't work if the
191 XXX IP packet is fragmented or if there are options on the IP
192 XXX header. */
193 pf.enf_Priority = 0;
194 pf.enf_FilterLen = 0;
195
196 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6;
197 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
198 pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP);
199 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT;
200 pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP);
201 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11;
202 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND;
203 pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF);
204 pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND;
205 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18;
206 pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND;
207 pf.enf_Filter [pf.enf_FilterLen++] = local_port;
208
209 if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0)
210 log_fatal ("Can't install packet filter program: %m");
211 if (!quiet_interface_discovery)
212 log_info ("Listening on UPF/%s/%s%s%s",
213 info -> name,
214 print_hw_addr (info -> hw_address.htype,
215 info -> hw_address.hlen,
216 info -> hw_address.haddr),
217 (info -> shared_network ? "/" : ""),
218 (info -> shared_network ?
219 info -> shared_network -> name : ""));
220 }
221 #endif /* USE_UPF_RECEIVE */
222
223 #ifdef USE_UPF_SEND
224 ssize_t send_packet (interface, packet, raw, len, from, to, hto)
225 struct interface_info *interface;
226 struct packet *packet;
227 struct dhcp_packet *raw;
228 size_t len;
229 struct in_addr from;
230 struct sockaddr_in *to;
231 struct hardware *hto;
232 {
233 int bufp = 0;
234 unsigned char buf [256];
235 struct iovec iov [2];
236 int result;
237
238 if (!strcmp (interface -> name, "fallback"))
239 return send_fallback (interface, packet, raw,
240 len, from, to, hto);
241
242 /* Assemble the headers... */
243 assemble_hw_header (interface, buf, &bufp, hto);
244 assemble_udp_ip_header (interface, buf, &bufp, from.s_addr,
245 to -> sin_addr.s_addr, to -> sin_port,
246 (unsigned char *)raw, len);
247
248 /* Fire it off */
249 iov [0].iov_base = (char *)buf;
250 iov [0].iov_len = bufp;
251 iov [1].iov_base = (char *)raw;
252 iov [1].iov_len = len;
253
254 result = writev(interface -> wfdesc, iov, 2);
255 if (result < 0)
256 warn ("send_packet: %m");
257 return result;
258 }
259 #endif /* USE_UPF_SEND */
260
261 #ifdef USE_UPF_RECEIVE
262 ssize_t receive_packet (interface, buf, len, from, hfrom)
263 struct interface_info *interface;
264 unsigned char *buf;
265 size_t len;
266 struct sockaddr_in *from;
267 struct hardware *hfrom;
268 {
269 int nread;
270 int length = 0;
271 int offset = 0;
272 unsigned char ibuf [1500 + sizeof (struct enstamp)];
273 int bufix = 0;
274
275 length = read (interface -> rfdesc, ibuf, sizeof ibuf);
276 if (length <= 0)
277 return length;
278
279 bufix = sizeof (struct enstamp);
280 /* Decode the physical header... */
281 offset = decode_hw_header (interface, ibuf, bufix, hfrom);
282
283 /* If a physical layer checksum failed (dunno of any
284 physical layer that supports this, but WTH), skip this
285 packet. */
286 if (offset < 0) {
287 return 0;
288 }
289
290 bufix += offset;
291 length -= offset;
292
293 /* Decode the IP and UDP headers... */
294 offset = decode_udp_ip_header (interface, ibuf, bufix,
295 from, (unsigned char *)0, length);
296
297 /* If the IP or UDP checksum was bad, skip the packet... */
298 if (offset < 0)
299 return 0;
300
301 bufix += offset;
302 length -= offset;
303
304 /* Copy out the data in the packet... */
305 memcpy (buf, &ibuf [bufix], length);
306 return length;
307 }
308
309 int can_unicast_without_arp ()
310 {
311 return 1;
312 }
313
314 int can_receive_unicast_unconfigured ()
315 {
316 return 1;
317 }
318
319 void maybe_setup_fallback ()
320 {
321 struct interface_info *fbi;
322 fbi = setup_fallback ();
323 if (fbi) {
324 if_register_fallback (fbi);
325 add_protocol ("fallback", fallback_interface -> wfdesc,
326 fallback_discard, fallback_interface);
327 }
328 }
329 #endif