]>
Commit | Line | Data |
---|---|---|
179f54ab TL |
1 | /* upf.c |
2 | ||
2d1b06e0 | 3 | Ultrix PacketFilter interface code. */ |
179f54ab TL |
4 | |
5 | /* | |
f39b6e00 TL |
6 | * Copyright (c) 1996-1999 Internet Software Consortium. |
7 | * Use is subject to license terms which appear in the file named | |
8 | * ISC-LICENSE that should have accompanied this file when you | |
9 | * received it. If a file named ISC-LICENSE did not accompany this | |
10 | * file, or you are not sure the one you have is correct, you may | |
11 | * obtain an applicable copy of the license at: | |
179f54ab | 12 | * |
f39b6e00 | 13 | * http://www.isc.org/isc-license-1.0.html. |
179f54ab | 14 | * |
f39b6e00 TL |
15 | * This file is part of the ISC DHCP distribution. The documentation |
16 | * associated with this file is listed in the file DOCUMENTATION, | |
17 | * included in the top-level directory of this release. | |
179f54ab | 18 | * |
f39b6e00 TL |
19 | * Support and other services are available for ISC products - see |
20 | * http://www.isc.org for more information. | |
179f54ab TL |
21 | */ |
22 | ||
23 | #ifndef lint | |
24 | static char copyright[] = | |
8ca11339 | 25 | "$Id: upf.c,v 1.14 1999/10/07 06:47:49 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; |
179f54ab TL |
26 | #endif /* not lint */ |
27 | ||
28 | #include "dhcpd.h" | |
29 | #if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE) | |
30 | #include <sys/ioctl.h> | |
31 | #include <sys/uio.h> | |
32 | ||
33 | #include <net/pfilt.h> | |
34 | #include <netinet/in_systm.h> | |
35 | #include "includes/netinet/ip.h" | |
36 | #include "includes/netinet/udp.h" | |
37 | #include "includes/netinet/if_ether.h" | |
38 | ||
39 | /* Reinitializes the specified interface after an address change. This | |
40 | is not required for packet-filter APIs. */ | |
41 | ||
42 | #ifdef USE_UPF_SEND | |
43 | void if_reinitialize_send (info) | |
44 | struct interface_info *info; | |
45 | { | |
46 | } | |
47 | #endif | |
48 | ||
49 | #ifdef USE_UPF_RECEIVE | |
50 | void if_reinitialize_receive (info) | |
51 | struct interface_info *info; | |
52 | { | |
53 | } | |
54 | #endif | |
55 | ||
56 | /* Called by get_interface_list for each interface that's discovered. | |
57 | Opens a packet filter for each interface and adds it to the select | |
58 | mask. */ | |
59 | ||
60 | int if_register_upf (info) | |
61 | struct interface_info *info; | |
62 | { | |
63 | int sock; | |
64 | char filename[50]; | |
65 | int b; | |
66 | struct endevp param; | |
67 | ||
68 | /* Open a UPF device */ | |
69 | for (b = 0; 1; b++) { | |
70 | #ifndef NO_SNPRINTF | |
71 | snprintf(filename, sizeof(filename), "/dev/pf/pfilt%d", b); | |
72 | #else | |
73 | sprintf(filename, "/dev/pf/pfilt%d", b); | |
74 | #endif | |
75 | sock = open (filename, O_RDWR, 0); | |
76 | if (sock < 0) { | |
77 | if (errno == EBUSY) { | |
78 | continue; | |
79 | } else { | |
8ae2d595 | 80 | log_fatal ("Can't find free upf: %m"); |
179f54ab TL |
81 | } |
82 | } else { | |
83 | break; | |
84 | } | |
85 | } | |
86 | ||
87 | /* Set the UPF device to point at this interface. */ | |
88 | if (ioctl (sock, EIOCSETIF, info -> ifp) < 0) | |
8ae2d595 | 89 | log_fatal ("Can't attach interface %s to upf device %s: %m", |
179f54ab TL |
90 | info -> name, filename); |
91 | ||
92 | /* Get the hardware address. */ | |
93 | if (ioctl (sock, EIOCDEVP, ¶m) < 0) | |
8ae2d595 | 94 | log_fatal ("Can't get interface %s hardware address: %m", |
179f54ab TL |
95 | info -> name); |
96 | ||
97 | /* We only know how to do ethernet. */ | |
98 | if (param.end_dev_type != ENDT_10MB) | |
8ae2d595 | 99 | log_fatal ("Invalid device type on network interface %s: %d", |
179f54ab TL |
100 | info -> name, param.end_dev_type); |
101 | ||
102 | if (param.end_addr_len != 6) | |
8ae2d595 | 103 | log_fatal ("Invalid hardware address length on %s: %d", |
179f54ab TL |
104 | info -> name, param.end_addr_len); |
105 | ||
106 | info -> hw_address.hlen = 6; | |
107 | info -> hw_address.htype = ARPHRD_ETHER; | |
108 | memcpy (&info -> hw_address.haddr [0], param.end_addr, 6); | |
109 | ||
110 | return sock; | |
111 | } | |
112 | #endif /* USE_UPF_SEND || USE_UPF_RECEIVE */ | |
113 | ||
114 | #ifdef USE_UPF_SEND | |
115 | void if_register_send (info) | |
116 | struct interface_info *info; | |
117 | { | |
118 | /* If we're using the upf API for sending and receiving, | |
119 | we don't need to register this interface twice. */ | |
120 | #ifndef USE_UPF_RECEIVE | |
121 | info -> wfdesc = if_register_upf (info, interface); | |
122 | #else | |
123 | info -> wfdesc = info -> rfdesc; | |
124 | #endif | |
3648a2a1 | 125 | if (!quiet_interface_discovery) |
74f45f96 | 126 | log_info ("Sending on UPF/%s/%s%s%s", |
3648a2a1 TL |
127 | info -> name, |
128 | print_hw_addr (info -> hw_address.htype, | |
129 | info -> hw_address.hlen, | |
130 | info -> hw_address.haddr), | |
74f45f96 | 131 | (info -> shared_network ? "/" : ""), |
3648a2a1 | 132 | (info -> shared_network ? |
74f45f96 | 133 | info -> shared_network -> name : "")); |
179f54ab TL |
134 | } |
135 | #endif /* USE_UPF_SEND */ | |
136 | ||
137 | #ifdef USE_UPF_RECEIVE | |
138 | /* Packet filter program... | |
139 | XXX Changes to the filter program may require changes to the constant | |
140 | offsets used in if_register_send to patch the UPF program! XXX */ | |
141 | ||
142 | ||
143 | void if_register_receive (info) | |
144 | struct interface_info *info; | |
145 | { | |
146 | int flag = 1; | |
147 | u_int32_t addr; | |
148 | struct enfilter pf; | |
149 | u_int32_t bits; | |
150 | ||
151 | /* Open a UPF device and hang it on this interface... */ | |
152 | info -> rfdesc = if_register_upf (info); | |
153 | ||
154 | /* Allow the copyall flag to be set... */ | |
155 | if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0) | |
8ae2d595 | 156 | log_fatal ("Can't set ALLOWCOPYALL: %m"); |
179f54ab TL |
157 | |
158 | /* Clear all the packet filter mode bits first... */ | |
159 | flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC | | |
160 | ENNONEXCL | ENCOPYALL); | |
161 | if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0) | |
8ae2d595 | 162 | log_fatal ("Can't clear pfilt bits: %m"); |
179f54ab TL |
163 | |
164 | /* Set the ENBATCH and ENCOPYALL bits... */ | |
165 | bits = ENBATCH | ENCOPYALL; | |
166 | if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) | |
8ae2d595 | 167 | log_fatal ("Can't set ENBATCH|ENCOPYALL: %m"); |
179f54ab TL |
168 | |
169 | /* Set up the UPF filter program. */ | |
170 | /* XXX Unlike the BPF filter program, this one won't work if the | |
171 | XXX IP packet is fragmented or if there are options on the IP | |
172 | XXX header. */ | |
173 | pf.enf_Priority = 0; | |
174 | pf.enf_FilterLen = 0; | |
175 | ||
176 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6; | |
177 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; | |
178 | pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP); | |
179 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT; | |
180 | pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP); | |
181 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11; | |
182 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND; | |
183 | pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF); | |
184 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND; | |
185 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18; | |
186 | pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; | |
187 | pf.enf_Filter [pf.enf_FilterLen++] = local_port; | |
188 | ||
189 | if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0) | |
8ae2d595 | 190 | log_fatal ("Can't install packet filter program: %m"); |
3648a2a1 | 191 | if (!quiet_interface_discovery) |
74f45f96 | 192 | log_info ("Listening on UPF/%s/%s%s%s", |
3648a2a1 TL |
193 | info -> name, |
194 | print_hw_addr (info -> hw_address.htype, | |
195 | info -> hw_address.hlen, | |
196 | info -> hw_address.haddr), | |
74f45f96 | 197 | (info -> shared_network ? "/" : ""), |
3648a2a1 | 198 | (info -> shared_network ? |
74f45f96 | 199 | info -> shared_network -> name : "")); |
179f54ab TL |
200 | } |
201 | #endif /* USE_UPF_RECEIVE */ | |
202 | ||
203 | #ifdef USE_UPF_SEND | |
4595a58c | 204 | ssize_t send_packet (interface, packet, raw, len, from, to, hto) |
179f54ab TL |
205 | struct interface_info *interface; |
206 | struct packet *packet; | |
207 | struct dhcp_packet *raw; | |
208 | size_t len; | |
209 | struct in_addr from; | |
210 | struct sockaddr_in *to; | |
211 | struct hardware *hto; | |
212 | { | |
8ca11339 | 213 | unsigned bufp = 0; |
179f54ab TL |
214 | unsigned char buf [256]; |
215 | struct iovec iov [2]; | |
74f45f96 | 216 | int result; |
179f54ab | 217 | |
d2bc90bd TL |
218 | if (!strcmp (interface -> name, "fallback")) |
219 | return send_fallback (interface, packet, raw, | |
220 | len, from, to, hto); | |
221 | ||
179f54ab TL |
222 | /* Assemble the headers... */ |
223 | assemble_hw_header (interface, buf, &bufp, hto); | |
224 | assemble_udp_ip_header (interface, buf, &bufp, from.s_addr, | |
225 | to -> sin_addr.s_addr, to -> sin_port, | |
226 | (unsigned char *)raw, len); | |
227 | ||
228 | /* Fire it off */ | |
229 | iov [0].iov_base = (char *)buf; | |
230 | iov [0].iov_len = bufp; | |
231 | iov [1].iov_base = (char *)raw; | |
232 | iov [1].iov_len = len; | |
233 | ||
74f45f96 TL |
234 | result = writev(interface -> wfdesc, iov, 2); |
235 | if (result < 0) | |
c5b0f529 | 236 | log_error ("send_packet: %m"); |
74f45f96 | 237 | return result; |
179f54ab TL |
238 | } |
239 | #endif /* USE_UPF_SEND */ | |
240 | ||
241 | #ifdef USE_UPF_RECEIVE | |
4595a58c | 242 | ssize_t receive_packet (interface, buf, len, from, hfrom) |
179f54ab TL |
243 | struct interface_info *interface; |
244 | unsigned char *buf; | |
245 | size_t len; | |
246 | struct sockaddr_in *from; | |
247 | struct hardware *hfrom; | |
248 | { | |
249 | int nread; | |
250 | int length = 0; | |
251 | int offset = 0; | |
252 | unsigned char ibuf [1500 + sizeof (struct enstamp)]; | |
253 | int bufix = 0; | |
254 | ||
255 | length = read (interface -> rfdesc, ibuf, sizeof ibuf); | |
256 | if (length <= 0) | |
257 | return length; | |
258 | ||
259 | bufix = sizeof (struct enstamp); | |
260 | /* Decode the physical header... */ | |
261 | offset = decode_hw_header (interface, ibuf, bufix, hfrom); | |
262 | ||
263 | /* If a physical layer checksum failed (dunno of any | |
264 | physical layer that supports this, but WTH), skip this | |
265 | packet. */ | |
266 | if (offset < 0) { | |
267 | return 0; | |
268 | } | |
269 | ||
270 | bufix += offset; | |
271 | length -= offset; | |
272 | ||
273 | /* Decode the IP and UDP headers... */ | |
274 | offset = decode_udp_ip_header (interface, ibuf, bufix, | |
275 | from, (unsigned char *)0, length); | |
276 | ||
277 | /* If the IP or UDP checksum was bad, skip the packet... */ | |
278 | if (offset < 0) | |
279 | return 0; | |
280 | ||
281 | bufix += offset; | |
282 | length -= offset; | |
283 | ||
284 | /* Copy out the data in the packet... */ | |
285 | memcpy (buf, &ibuf [bufix], length); | |
286 | return length; | |
287 | } | |
d2bc90bd | 288 | |
21d21e91 TL |
289 | int can_unicast_without_arp (ip) |
290 | struct interface_info *ip; | |
d2bc90bd TL |
291 | { |
292 | return 1; | |
293 | } | |
294 | ||
21d21e91 TL |
295 | int can_receive_unicast_unconfigured (ip) |
296 | struct interface_info *ip; | |
b547818b TL |
297 | { |
298 | return 1; | |
299 | } | |
300 | ||
d2bc90bd TL |
301 | void maybe_setup_fallback () |
302 | { | |
acc21512 | 303 | isc_result_t status; |
d2bc90bd TL |
304 | struct interface_info *fbi; |
305 | fbi = setup_fallback (); | |
306 | if (fbi) { | |
307 | if_register_fallback (fbi); | |
acc21512 TL |
308 | fbi -> refcnt = 1; |
309 | fbi -> type = dhcp_type_interface; | |
e92653f1 | 310 | status = omapi_register_io_object ((omapi_object_t *)fbi, |
acc21512 TL |
311 | if_readsocket, 0, |
312 | fallback_discard, 0, 0); | |
313 | if (status != ISC_R_SUCCESS) | |
314 | log_fatal ("Can't register I/O handle for %s: %s", | |
315 | fbi -> name, isc_result_totext (status)); | |
d2bc90bd TL |
316 | } |
317 | } | |
179f54ab | 318 | #endif |