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.15 2000/01/25 01:17:01 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
: ""));
135 #endif /* USE_UPF_SEND */
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 */
143 void if_register_receive (info
)
144 struct interface_info
*info
;
151 /* Open a UPF device and hang it on this interface... */
152 info
-> rfdesc
= if_register_upf (info
);
154 /* Allow the copyall flag to be set... */
155 if (ioctl(info
-> rfdesc
, EIOCALLOWCOPYALL
, &flag
) < 0)
156 log_fatal ("Can't set ALLOWCOPYALL: %m");
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)
162 log_fatal ("Can't clear pfilt bits: %m");
164 /* Set the ENBATCH and ENCOPYALL bits... */
165 bits
= ENBATCH
| ENCOPYALL
;
166 if (ioctl (info
-> rfdesc
, EIOCMBIS
, &bits
) < 0)
167 log_fatal ("Can't set ENBATCH|ENCOPYALL: %m");
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
174 pf
.enf_FilterLen
= 0;
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
;
189 if (ioctl (info
-> rfdesc
, EIOCSETF
, &pf
) < 0)
190 log_fatal ("Can't install packet filter program: %m");
191 if (!quiet_interface_discovery
)
192 log_info ("Listening on UPF/%s/%s%s%s",
194 print_hw_addr (info
-> hw_address
.hbuf
[0],
195 info
-> hw_address
.hlen
- 1,
196 &info
-> hw_address
.hbuf
[1]),
197 (info
-> shared_network
? "/" : ""),
198 (info
-> shared_network
?
199 info
-> shared_network
-> name
: ""));
201 #endif /* USE_UPF_RECEIVE */
204 ssize_t
send_packet (interface
, packet
, raw
, len
, from
, to
, hto
)
205 struct interface_info
*interface
;
206 struct packet
*packet
;
207 struct dhcp_packet
*raw
;
210 struct sockaddr_in
*to
;
211 struct hardware
*hto
;
214 unsigned char buf
[256];
215 struct iovec iov
[2];
218 if (!strcmp (interface
-> name
, "fallback"))
219 return send_fallback (interface
, packet
, raw
,
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
);
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
;
234 result
= writev(interface
-> wfdesc
, iov
, 2);
236 log_error ("send_packet: %m");
239 #endif /* USE_UPF_SEND */
241 #ifdef USE_UPF_RECEIVE
242 ssize_t
receive_packet (interface
, buf
, len
, from
, hfrom
)
243 struct interface_info
*interface
;
246 struct sockaddr_in
*from
;
247 struct hardware
*hfrom
;
252 unsigned char ibuf
[1500 + sizeof (struct enstamp
)];
255 length
= read (interface
-> rfdesc
, ibuf
, sizeof ibuf
);
259 bufix
= sizeof (struct enstamp
);
260 /* Decode the physical header... */
261 offset
= decode_hw_header (interface
, ibuf
, bufix
, hfrom
);
263 /* If a physical layer checksum failed (dunno of any
264 physical layer that supports this, but WTH), skip this
273 /* Decode the IP and UDP headers... */
274 offset
= decode_udp_ip_header (interface
, ibuf
, bufix
,
275 from
, (unsigned char *)0, length
);
277 /* If the IP or UDP checksum was bad, skip the packet... */
284 /* Copy out the data in the packet... */
285 memcpy (buf
, &ibuf
[bufix
], length
);
289 int can_unicast_without_arp (ip
)
290 struct interface_info
*ip
;
295 int can_receive_unicast_unconfigured (ip
)
296 struct interface_info
*ip
;
301 void maybe_setup_fallback ()
304 struct interface_info
*fbi
;
305 fbi
= setup_fallback ();
307 if_register_fallback (fbi
);
309 fbi
-> type
= dhcp_type_interface
;
310 status
= omapi_register_io_object ((omapi_object_t
*)fbi
,
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
));