3 Ultrix PacketFilter interface code. */
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:
13 * http://www.isc.org/isc-license-1.0.html.
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.
19 * Support and other services are available for ISC products - see
20 * http://www.isc.org for more information.
24 static char copyright
[] =
25 "$Id: upf.c,v 1.16 2000/03/06 19:39:54 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
29 #if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE)
30 #include <sys/ioctl.h>
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"
39 /* Reinitializes the specified interface after an address change. This
40 is not required for packet-filter APIs. */
43 void if_reinitialize_send (info
)
44 struct interface_info
*info
;
49 #ifdef USE_UPF_RECEIVE
50 void if_reinitialize_receive (info
)
51 struct interface_info
*info
;
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
60 int if_register_upf (info
)
61 struct interface_info
*info
;
68 /* Open a UPF device */
71 snprintf(filename
, sizeof(filename
), "/dev/pf/pfilt%d", b
);
73 sprintf(filename
, "/dev/pf/pfilt%d", b
);
75 sock
= open (filename
, O_RDWR
, 0);
80 log_fatal ("Can't find free upf: %m");
87 /* Set the UPF device to point at this interface. */
88 if (ioctl (sock
, EIOCSETIF
, info
-> ifp
) < 0)
89 log_fatal ("Can't attach interface %s to upf device %s: %m",
90 info
-> name
, filename
);
92 /* Get the hardware address. */
93 if (ioctl (sock
, EIOCDEVP
, ¶m
) < 0)
94 log_fatal ("Can't get interface %s hardware address: %m",
97 /* We only know how to do ethernet. */
98 if (param
.end_dev_type
!= ENDT_10MB
)
99 log_fatal ("Invalid device type on network interface %s: %d",
100 info
-> name
, param
.end_dev_type
);
102 if (param
.end_addr_len
!= 6)
103 log_fatal ("Invalid hardware address length on %s: %d",
104 info
-> name
, param
.end_addr_len
);
106 info
-> hw_address
.hlen
= 7;
107 info
-> hw_address
.hbuf
[0] = ARPHRD_ETHER
;
108 memcpy (&info
-> hw_address
.hbuf
[1], param
.end_addr
, 6);
112 #endif /* USE_UPF_SEND || USE_UPF_RECEIVE */
115 void if_register_send (info
)
116 struct interface_info
*info
;
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
);
123 info
-> wfdesc
= info
-> rfdesc
;
125 if (!quiet_interface_discovery
)
126 log_info ("Sending on UPF/%s/%s%s%s",
128 print_hw_addr (info
-> hw_address
.hbuf
[0],
129 info
-> hw_address
.hlen
- 1,
130 &info
-> hw_address
.hbuf
[1]),
131 (info
-> shared_network
? "/" : ""),
132 (info
-> shared_network
?
133 info
-> shared_network
-> name
: ""));
136 void if_deregister_send (info
)
137 struct interface_info
*info
;
139 #ifndef USE_UPF_RECEIVE
140 close (info
-> wfdesc
);
143 if (!quiet_interface_discovery
)
144 log_info ("Disabling output on UPF/%s/%s%s%s",
146 print_hw_addr (info
-> hw_address
.hbuf
[0],
147 info
-> hw_address
.hlen
- 1,
148 &info
-> hw_address
.hbuf
[1]),
149 (info
-> shared_network
? "/" : ""),
150 (info
-> shared_network
?
151 info
-> shared_network
-> name
: ""));
153 #endif /* USE_UPF_SEND */
155 #ifdef USE_UPF_RECEIVE
156 /* Packet filter program...
157 XXX Changes to the filter program may require changes to the constant
158 offsets used in if_register_send to patch the UPF program! XXX */
161 void if_register_receive (info
)
162 struct interface_info
*info
;
169 /* Open a UPF device and hang it on this interface... */
170 info
-> rfdesc
= if_register_upf (info
);
172 /* Allow the copyall flag to be set... */
173 if (ioctl(info
-> rfdesc
, EIOCALLOWCOPYALL
, &flag
) < 0)
174 log_fatal ("Can't set ALLOWCOPYALL: %m");
176 /* Clear all the packet filter mode bits first... */
177 flag
= (ENHOLDSIG
| ENBATCH
| ENTSTAMP
| ENPROMISC
|
178 ENNONEXCL
| ENCOPYALL
);
179 if (ioctl (info
-> rfdesc
, EIOCMBIC
, &flag
) < 0)
180 log_fatal ("Can't clear pfilt bits: %m");
182 /* Set the ENBATCH and ENCOPYALL bits... */
183 bits
= ENBATCH
| ENCOPYALL
;
184 if (ioctl (info
-> rfdesc
, EIOCMBIS
, &bits
) < 0)
185 log_fatal ("Can't set ENBATCH|ENCOPYALL: %m");
187 /* Set up the UPF filter program. */
188 /* XXX Unlike the BPF filter program, this one won't work if the
189 XXX IP packet is fragmented or if there are options on the IP
192 pf
.enf_FilterLen
= 0;
194 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_PUSHWORD
+ 6;
195 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_PUSHLIT
+ ENF_CAND
;
196 pf
.enf_Filter
[pf
.enf_FilterLen
++] = htons (ETHERTYPE_IP
);
197 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_PUSHLIT
;
198 pf
.enf_Filter
[pf
.enf_FilterLen
++] = htons (IPPROTO_UDP
);
199 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_PUSHWORD
+ 11;
200 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_PUSHLIT
+ ENF_AND
;
201 pf
.enf_Filter
[pf
.enf_FilterLen
++] = htons (0xFF);
202 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_CAND
;
203 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_PUSHWORD
+ 18;
204 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_PUSHLIT
+ ENF_CAND
;
205 pf
.enf_Filter
[pf
.enf_FilterLen
++] = local_port
;
207 if (ioctl (info
-> rfdesc
, EIOCSETF
, &pf
) < 0)
208 log_fatal ("Can't install packet filter program: %m");
209 if (!quiet_interface_discovery
)
210 log_info ("Listening on UPF/%s/%s%s%s",
212 print_hw_addr (info
-> hw_address
.hbuf
[0],
213 info
-> hw_address
.hlen
- 1,
214 &info
-> hw_address
.hbuf
[1]),
215 (info
-> shared_network
? "/" : ""),
216 (info
-> shared_network
?
217 info
-> shared_network
-> name
: ""));
220 void if_deregister_receive (info
)
221 struct interface_info
*info
;
223 close (info
-> rfdesc
);
225 if (!quiet_interface_discovery
)
226 log_info ("Disabling input on UPF/%s/%s%s%s",
228 print_hw_addr (info
-> hw_address
.hbuf
[0],
229 info
-> hw_address
.hlen
- 1,
230 &info
-> hw_address
.hbuf
[1]),
231 (info
-> shared_network
? "/" : ""),
232 (info
-> shared_network
?
233 info
-> shared_network
-> name
: ""));
235 #endif /* USE_UPF_RECEIVE */
238 ssize_t
send_packet (interface
, packet
, raw
, len
, from
, to
, hto
)
239 struct interface_info
*interface
;
240 struct packet
*packet
;
241 struct dhcp_packet
*raw
;
244 struct sockaddr_in
*to
;
245 struct hardware
*hto
;
248 unsigned char buf
[256];
249 struct iovec iov
[2];
252 if (!strcmp (interface
-> name
, "fallback"))
253 return send_fallback (interface
, packet
, raw
,
256 /* Assemble the headers... */
257 assemble_hw_header (interface
, buf
, &bufp
, hto
);
258 assemble_udp_ip_header (interface
, buf
, &bufp
, from
.s_addr
,
259 to
-> sin_addr
.s_addr
, to
-> sin_port
,
260 (unsigned char *)raw
, len
);
263 iov
[0].iov_base
= (char *)buf
;
264 iov
[0].iov_len
= bufp
;
265 iov
[1].iov_base
= (char *)raw
;
266 iov
[1].iov_len
= len
;
268 result
= writev(interface
-> wfdesc
, iov
, 2);
270 log_error ("send_packet: %m");
273 #endif /* USE_UPF_SEND */
275 #ifdef USE_UPF_RECEIVE
276 ssize_t
receive_packet (interface
, buf
, len
, from
, hfrom
)
277 struct interface_info
*interface
;
280 struct sockaddr_in
*from
;
281 struct hardware
*hfrom
;
286 unsigned char ibuf
[1500 + sizeof (struct enstamp
)];
289 length
= read (interface
-> rfdesc
, ibuf
, sizeof ibuf
);
293 bufix
= sizeof (struct enstamp
);
294 /* Decode the physical header... */
295 offset
= decode_hw_header (interface
, ibuf
, bufix
, hfrom
);
297 /* If a physical layer checksum failed (dunno of any
298 physical layer that supports this, but WTH), skip this
307 /* Decode the IP and UDP headers... */
308 offset
= decode_udp_ip_header (interface
, ibuf
, bufix
,
309 from
, (unsigned char *)0, length
);
311 /* If the IP or UDP checksum was bad, skip the packet... */
318 /* Copy out the data in the packet... */
319 memcpy (buf
, &ibuf
[bufix
], length
);
323 int can_unicast_without_arp (ip
)
324 struct interface_info
*ip
;
329 int can_receive_unicast_unconfigured (ip
)
330 struct interface_info
*ip
;
335 void maybe_setup_fallback ()
338 struct interface_info
*fbi
;
339 fbi
= setup_fallback ();
341 if_register_fallback (fbi
);
343 fbi
-> type
= dhcp_type_interface
;
344 status
= omapi_register_io_object ((omapi_object_t
*)fbi
,
346 fallback_discard
, 0, 0);
347 if (status
!= ISC_R_SUCCESS
)
348 log_fatal ("Can't register I/O handle for %s: %s",
349 fbi
-> name
, isc_result_totext (status
));