3 Ultrix PacketFilter interface code. */
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1996-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
23 * Redwood City, CA 94063
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
36 static char copyright
[] =
37 "$Id$ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
41 #if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE)
42 #include <sys/ioctl.h>
45 #include <net/pfilt.h>
46 #include <netinet/in_systm.h>
47 #include "includes/netinet/ip.h"
48 #include "includes/netinet/udp.h"
49 #include "includes/netinet/if_ether.h"
51 /* Reinitializes the specified interface after an address change. This
52 is not required for packet-filter APIs. */
55 void if_reinitialize_send (info
)
56 struct interface_info
*info
;
61 #ifdef USE_UPF_RECEIVE
62 void if_reinitialize_receive (info
)
63 struct interface_info
*info
;
68 /* Called by get_interface_list for each interface that's discovered.
69 Opens a packet filter for each interface and adds it to the select
72 int if_register_upf (info
)
73 struct interface_info
*info
;
80 /* Open a UPF device */
82 /* %Audit% Cannot exceed 36 bytes. %2004.06.17,Safe% */
83 sprintf(filename
, "/dev/pf/pfilt%d", b
);
85 sock
= open (filename
, O_RDWR
, 0);
90 log_fatal ("Can't find free upf: %m");
97 /* Set the UPF device to point at this interface. */
98 if (ioctl (sock
, EIOCSETIF
, info
-> ifp
) < 0)
99 log_fatal ("Can't attach interface %s to upf device %s: %m",
100 info
-> name
, filename
);
102 /* Get the hardware address. */
103 if (ioctl (sock
, EIOCDEVP
, ¶m
) < 0)
104 log_fatal ("Can't get interface %s hardware address: %m",
107 /* We only know how to do ethernet. */
108 if (param
.end_dev_type
!= ENDT_10MB
)
109 log_fatal ("Invalid device type on network interface %s: %d",
110 info
-> name
, param
.end_dev_type
);
112 if (param
.end_addr_len
!= 6)
113 log_fatal ("Invalid hardware address length on %s: %d",
114 info
-> name
, param
.end_addr_len
);
116 info
-> hw_address
.hlen
= 7;
117 info
-> hw_address
.hbuf
[0] = ARPHRD_ETHER
;
118 memcpy (&info
-> hw_address
.hbuf
[1], param
.end_addr
, 6);
122 #endif /* USE_UPF_SEND || USE_UPF_RECEIVE */
125 void if_register_send (info
)
126 struct interface_info
*info
;
128 /* If we're using the upf API for sending and receiving,
129 we don't need to register this interface twice. */
130 #ifndef USE_UPF_RECEIVE
131 info
-> wfdesc
= if_register_upf (info
, interface
);
133 info
-> wfdesc
= info
-> rfdesc
;
135 if (!quiet_interface_discovery
)
136 log_info ("Sending on UPF/%s/%s%s%s",
138 print_hw_addr (info
-> hw_address
.hbuf
[0],
139 info
-> hw_address
.hlen
- 1,
140 &info
-> hw_address
.hbuf
[1]),
141 (info
-> shared_network
? "/" : ""),
142 (info
-> shared_network
?
143 info
-> shared_network
-> name
: ""));
146 void if_deregister_send (info
)
147 struct interface_info
*info
;
149 #ifndef USE_UPF_RECEIVE
150 close (info
-> wfdesc
);
153 if (!quiet_interface_discovery
)
154 log_info ("Disabling output on UPF/%s/%s%s%s",
156 print_hw_addr (info
-> hw_address
.hbuf
[0],
157 info
-> hw_address
.hlen
- 1,
158 &info
-> hw_address
.hbuf
[1]),
159 (info
-> shared_network
? "/" : ""),
160 (info
-> shared_network
?
161 info
-> shared_network
-> name
: ""));
163 #endif /* USE_UPF_SEND */
165 #ifdef USE_UPF_RECEIVE
166 /* Packet filter program...
167 XXX Changes to the filter program may require changes to the constant
168 offsets used in if_register_send to patch the UPF program! XXX */
171 void if_register_receive (info
)
172 struct interface_info
*info
;
179 /* Open a UPF device and hang it on this interface... */
180 info
-> rfdesc
= if_register_upf (info
);
182 /* Allow the copyall flag to be set... */
183 if (ioctl(info
-> rfdesc
, EIOCALLOWCOPYALL
, &flag
) < 0)
184 log_fatal ("Can't set ALLOWCOPYALL: %m");
186 /* Clear all the packet filter mode bits first... */
187 flag
= (ENHOLDSIG
| ENBATCH
| ENTSTAMP
| ENPROMISC
|
188 ENNONEXCL
| ENCOPYALL
);
189 if (ioctl (info
-> rfdesc
, EIOCMBIC
, &flag
) < 0)
190 log_fatal ("Can't clear pfilt bits: %m");
192 /* Set the ENBATCH and ENCOPYALL bits... */
193 bits
= ENBATCH
| ENCOPYALL
;
194 if (ioctl (info
-> rfdesc
, EIOCMBIS
, &bits
) < 0)
195 log_fatal ("Can't set ENBATCH|ENCOPYALL: %m");
197 /* Set up the UPF filter program. */
198 /* XXX Unlike the BPF filter program, this one won't work if the
199 XXX IP packet is fragmented or if there are options on the IP
202 pf
.enf_FilterLen
= 0;
204 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_PUSHWORD
+ 6;
205 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_PUSHLIT
+ ENF_CAND
;
206 pf
.enf_Filter
[pf
.enf_FilterLen
++] = htons (ETHERTYPE_IP
);
207 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_PUSHLIT
;
208 pf
.enf_Filter
[pf
.enf_FilterLen
++] = htons (IPPROTO_UDP
);
209 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_PUSHWORD
+ 11;
210 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_PUSHLIT
+ ENF_AND
;
211 pf
.enf_Filter
[pf
.enf_FilterLen
++] = htons (0xFF);
212 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_CAND
;
213 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_PUSHWORD
+ 18;
214 pf
.enf_Filter
[pf
.enf_FilterLen
++] = ENF_PUSHLIT
+ ENF_CAND
;
215 pf
.enf_Filter
[pf
.enf_FilterLen
++] = local_port
;
217 if (ioctl (info
-> rfdesc
, EIOCSETF
, &pf
) < 0)
218 log_fatal ("Can't install packet filter program: %m");
219 if (!quiet_interface_discovery
)
220 log_info ("Listening on UPF/%s/%s%s%s",
222 print_hw_addr (info
-> hw_address
.hbuf
[0],
223 info
-> hw_address
.hlen
- 1,
224 &info
-> hw_address
.hbuf
[1]),
225 (info
-> shared_network
? "/" : ""),
226 (info
-> shared_network
?
227 info
-> shared_network
-> name
: ""));
230 void if_deregister_receive (info
)
231 struct interface_info
*info
;
233 close (info
-> rfdesc
);
235 if (!quiet_interface_discovery
)
236 log_info ("Disabling input on UPF/%s/%s%s%s",
238 print_hw_addr (info
-> hw_address
.hbuf
[0],
239 info
-> hw_address
.hlen
- 1,
240 &info
-> hw_address
.hbuf
[1]),
241 (info
-> shared_network
? "/" : ""),
242 (info
-> shared_network
?
243 info
-> shared_network
-> name
: ""));
245 #endif /* USE_UPF_RECEIVE */
248 ssize_t
send_packet (interface
, packet
, raw
, len
, from
, to
, hto
)
249 struct interface_info
*interface
;
250 struct packet
*packet
;
251 struct dhcp_packet
*raw
;
254 struct sockaddr_in
*to
;
255 struct hardware
*hto
;
257 unsigned hbufp
= 0, ibufp
= 0;
260 struct iovec iov
[3];
264 if (!strcmp (interface
-> name
, "fallback"))
265 return send_fallback (interface
, packet
, raw
,
268 /* Assemble the headers... */
269 assemble_hw_header (interface
, (unsigned char *)hw
, &hbufp
, hto
);
270 assemble_udp_ip_header (interface
,
271 (unsigned char *)ip
, &ibufp
, from
.s_addr
,
272 to
-> sin_addr
.s_addr
, to
-> sin_port
,
273 (unsigned char *)raw
, len
);
276 iov
[0].iov_base
= ((char *)hw
);
277 iov
[0].iov_len
= hbufp
;
278 iov
[1].iov_base
= ((char *)ip
);
279 iov
[1].iov_len
= ibufp
;
280 iov
[2].iov_base
= (char *)raw
;
281 iov
[2].iov_len
= len
;
283 result
= writev(interface
-> wfdesc
, iov
, 3);
285 log_error ("send_packet: %m");
288 #endif /* USE_UPF_SEND */
290 #ifdef USE_UPF_RECEIVE
291 ssize_t
receive_packet (interface
, buf
, len
, from
, hfrom
)
292 struct interface_info
*interface
;
295 struct sockaddr_in
*from
;
296 struct hardware
*hfrom
;
301 unsigned char ibuf
[1500 + sizeof (struct enstamp
)];
304 length
= read (interface
-> rfdesc
, ibuf
, sizeof ibuf
);
308 bufix
= sizeof (struct enstamp
);
309 /* Decode the physical header... */
310 offset
= decode_hw_header (interface
, ibuf
, bufix
, hfrom
);
312 /* If a physical layer checksum failed (dunno of any
313 physical layer that supports this, but WTH), skip this
322 /* Decode the IP and UDP headers... */
323 offset
= decode_udp_ip_header (interface
, ibuf
, bufix
,
326 /* If the IP or UDP checksum was bad, skip the packet... */
333 /* Copy out the data in the packet... */
334 memcpy (buf
, &ibuf
[bufix
], length
);
338 int can_unicast_without_arp (ip
)
339 struct interface_info
*ip
;
344 int can_receive_unicast_unconfigured (ip
)
345 struct interface_info
*ip
;
350 int supports_multiple_interfaces (ip
)
351 struct interface_info
*ip
;
356 void maybe_setup_fallback ()
359 struct interface_info
*fbi
= (struct interface_info
*)0;
360 if (setup_fallback (&fbi
, MDL
)) {
361 if_register_fallback (fbi
);
362 status
= omapi_register_io_object ((omapi_object_t
*)fbi
,
364 fallback_discard
, 0, 0);
365 if (status
!= ISC_R_SUCCESS
)
366 log_fatal ("Can't register I/O handle for %s: %s",
367 fbi
-> name
, isc_result_totext (status
));
368 interface_dereference (&fbi
, MDL
);