3 Network Interface Tap (NIT) network interface code, by Ted Lemon
4 with one crucial tidbit of help from Stu Grossmen. */
7 * Copyright (c) 1996-2000 Internet Software Consortium.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of The Internet Software Consortium nor the names
20 * of its contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
24 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
31 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
32 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * This software has been written for the Internet Software Consortium
38 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
39 * To learn more about the Internet Software Consortium, see
40 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
41 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
42 * ``http://www.nominum.com''.
46 static char copyright
[] =
47 "$Id: nit.c,v 1.28 2000/03/17 03:59:01 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium. All rights reserved.\n";
51 #if defined (USE_NIT_SEND) || defined (USE_NIT_RECEIVE)
52 #include <sys/ioctl.h>
57 #include <net/nit_if.h>
58 #include <net/nit_pf.h>
59 #include <net/nit_buf.h>
60 #include <sys/stropts.h>
61 #include <net/packetfilt.h>
63 #include <netinet/in_systm.h>
64 #include "includes/netinet/ip.h"
65 #include "includes/netinet/udp.h"
66 #include "includes/netinet/if_ether.h"
68 /* Reinitializes the specified interface after an address change. This
69 is not required for packet-filter APIs. */
72 void if_reinitialize_send (info
)
73 struct interface_info
*info
;
78 #ifdef USE_NIT_RECEIVE
79 void if_reinitialize_receive (info
)
80 struct interface_info
*info
;
85 /* Called by get_interface_list for each interface that's discovered.
86 Opens a packet filter for each interface and adds it to the select
89 int if_register_nit (info
)
90 struct interface_info
*info
;
97 /* Open a NIT device */
98 sock
= open ("/dev/nit", O_RDWR
);
100 log_fatal ("Can't open NIT device for %s: %m", info
-> name
);
102 /* Set the NIT device to point at this interface. */
103 sio
.ic_cmd
= NIOCBIND
;
104 sio
.ic_len
= sizeof *(info
-> ifp
);
105 sio
.ic_dp
= (char *)(info
-> ifp
);
106 sio
.ic_timout
= INFTIM
;
107 if (ioctl (sock
, I_STR
, &sio
) < 0)
108 log_fatal ("Can't attach interface %s to nit device: %m",
111 /* Get the low-level address... */
112 sio
.ic_cmd
= SIOCGIFADDR
;
113 sio
.ic_len
= sizeof ifr
;
114 sio
.ic_dp
= (char *)&ifr
;
115 sio
.ic_timout
= INFTIM
;
116 if (ioctl (sock
, I_STR
, &sio
) < 0)
117 log_fatal ("Can't get physical layer address for %s: %m",
120 /* XXX code below assumes ethernet interface! */
121 info
-> hw_address
.hlen
= 7;
122 info
-> hw_address
.hbuf
[0] = ARPHRD_ETHER
;
123 memcpy (&info
-> hw_address
.jbuf
[1],
124 ifr
.ifr_ifru
.ifru_addr
.sa_data
, 6);
126 if (ioctl (sock
, I_PUSH
, "pf") < 0)
127 log_fatal ("Can't push packet filter onto NIT for %s: %m",
132 #endif /* USE_NIT_SEND || USE_NIT_RECEIVE */
135 void if_register_send (info
)
136 struct interface_info
*info
;
138 /* If we're using the nit API for sending and receiving,
139 we don't need to register this interface twice. */
140 #ifndef USE_NIT_RECEIVE
141 struct packetfilt pf
;
144 info
-> wfdesc
= if_register_nit (info
);
148 pf
.Pf_Filter
[0] = ENF_PUSHZERO
;
150 /* Set up an NIT filter that rejects everything... */
151 sio
.ic_cmd
= NIOCSETF
;
152 sio
.ic_len
= sizeof pf
;
153 sio
.ic_dp
= (char *)&pf
;
154 sio
.ic_timout
= INFTIM
;
155 if (ioctl (info
-> wfdesc
, I_STR
, &sio
) < 0)
156 log_fatal ("Can't set NIT filter: %m");
158 info
-> wfdesc
= info
-> rfdesc
;
160 if (!quiet_interface_discovery
)
161 log_info ("Sending on NIT/%s%s%s",
162 print_hw_addr (info
-> hw_address
.hbuf
[0],
163 info
-> hw_address
.hlen
- 1,
164 &info
-> hw_address
.hbuf
[1]),
165 (info
-> shared_network
? "/" : ""),
166 (info
-> shared_network
?
167 info
-> shared_network
-> name
: ""));
170 void if_deregister_send (info
)
171 struct interface_info
*info
;
173 /* If we're using the nit API for sending and receiving,
174 we don't need to register this interface twice. */
175 #ifndef USE_NIT_RECEIVE
176 close (info
-> wfdesc
);
179 if (!quiet_interface_discovery
)
180 log_info ("Disabling output on NIT/%s%s%s",
181 print_hw_addr (info
-> hw_address
.hbuf
[0],
182 info
-> hw_address
.hlen
- 1,
183 &info
-> hw_address
.hbuf
[1]),
184 (info
-> shared_network
? "/" : ""),
185 (info
-> shared_network
?
186 info
-> shared_network
-> name
: ""));
188 #endif /* USE_NIT_SEND */
190 #ifdef USE_NIT_RECEIVE
191 /* Packet filter program...
192 XXX Changes to the filter program may require changes to the constant
193 offsets used in if_register_send to patch the NIT program! XXX */
195 void if_register_receive (info
)
196 struct interface_info
*info
;
200 struct packetfilt pf
;
205 /* Open a NIT device and hang it on this interface... */
206 info
-> rfdesc
= if_register_nit (info
);
208 /* Set the snap length to 0, which means always take the whole
211 if (ioctl (info
-> rfdesc
, NIOCSSNAP
, &x
) < 0)
212 log_fatal ("Can't set NIT snap length on %s: %m", info
-> name
);
214 /* Set the stream to byte stream mode */
215 if (ioctl (info
-> rfdesc
, I_SRDOPT
, RMSGN
) != 0)
216 log_info ("I_SRDOPT failed on %s: %m", info
-> name
);
219 /* Push on the chunker... */
220 if (ioctl (info
-> rfdesc
, I_PUSH
, "nbuf") < 0)
221 log_fatal ("Can't push chunker onto NIT STREAM: %m");
223 /* Set the timeout to zero. */
226 if (ioctl (info
-> rfdesc
, NIOCSTIME
, &t
) < 0)
227 log_fatal ("Can't set chunk timeout: %m");
230 /* Ask for no header... */
232 if (ioctl (info
-> rfdesc
, NIOCSFLAGS
, &x
) < 0)
233 log_fatal ("Can't set NIT flags on %s: %m", info
-> name
);
235 /* Set up the NIT filter program. */
236 /* XXX Unlike the BPF filter program, this one won't work if the
237 XXX IP packet is fragmented or if there are options on the IP
242 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 6;
243 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
+ ENF_CAND
;
244 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (ETHERTYPE_IP
);
245 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
;
246 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (IPPROTO_UDP
);
247 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 11;
248 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
+ ENF_AND
;
249 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (0xFF);
250 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_CAND
;
251 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 18;
252 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
+ ENF_CAND
;
253 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = local_port
;
255 /* Install the filter... */
256 sio
.ic_cmd
= NIOCSETF
;
257 sio
.ic_len
= sizeof pf
;
258 sio
.ic_dp
= (char *)&pf
;
259 sio
.ic_timout
= INFTIM
;
260 if (ioctl (info
-> rfdesc
, I_STR
, &sio
) < 0)
261 log_fatal ("Can't set NIT filter on %s: %m", info
-> name
);
263 if (!quiet_interface_discovery
)
264 log_info ("Listening on NIT/%s%s%s",
265 print_hw_addr (info
-> hw_address
.hbuf
[0],
266 info
-> hw_address
.hlen
- 1,
267 &info
-> hw_address
.hbuf
[1]),
268 (info
-> shared_network
? "/" : ""),
269 (info
-> shared_network
?
270 info
-> shared_network
-> name
: ""));
273 void if_deregister_receive (info
)
274 struct interface_info
*info
;
276 /* If we're using the nit API for sending and receiving,
277 we don't need to register this interface twice. */
278 close (info
-> rfdesc
);
281 if (!quiet_interface_discovery
)
282 log_info ("Disabling input on NIT/%s%s%s",
283 print_hw_addr (info
-> hw_address
.hbuf
[0],
284 info
-> hw_address
.hlen
- 1,
285 &info
-> hw_address
.hbuf
[1]),
286 (info
-> shared_network
? "/" : ""),
287 (info
-> shared_network
?
288 info
-> shared_network
-> name
: ""));
290 #endif /* USE_NIT_RECEIVE */
293 ssize_t
send_packet (interface
, packet
, raw
, len
, from
, to
, hto
)
294 struct interface_info
*interface
;
295 struct packet
*packet
;
296 struct dhcp_packet
*raw
;
299 struct sockaddr_in
*to
;
300 struct hardware
*hto
;
303 unsigned char buf
[1536 + sizeof (struct sockaddr
)];
304 struct sockaddr
*junk
;
305 struct strbuf ctl
, data
;
307 struct sockaddr_in foo
;
310 if (!strcmp (interface
-> name
, "fallback"))
311 return send_fallback (interface
, packet
, raw
,
314 /* Start with the sockaddr struct... */
315 junk
= (struct sockaddr
*)&buf
[0];
316 bufp
= ((unsigned char *)&junk
-> sa_data
[0]) - &buf
[0];
318 /* Assemble the headers... */
319 assemble_hw_header (interface
, buf
, &bufp
, hto
);
321 assemble_udp_ip_header (interface
, buf
, &bufp
, from
.s_addr
,
322 to
-> sin_addr
.s_addr
, to
-> sin_port
,
325 /* Copy the data into the buffer (yuk). */
326 memcpy (buf
+ bufp
, raw
, len
);
328 /* Set up the sockaddr structure... */
330 junk
-> sa_len
= hw_end
- 2; /* XXX */
332 junk
-> sa_family
= AF_UNSPEC
;
334 #if 0 /* Already done. */
335 memcpy (junk
.sa_data
, buf
, hw_len
);
338 /* Set up the msg_buf structure... */
339 ctl
.buf
= (char *)&buf
[0];
340 ctl
.maxlen
= ctl
.len
= hw_end
;
341 data
.buf
= (char *)&buf
[hw_end
];
342 data
.maxlen
= data
.len
= bufp
+ len
- hw_end
;
344 result
= putmsg (interface
-> wfdesc
, &ctl
, &data
, 0);
346 log_error ("send_packet: %m");
349 #endif /* USE_NIT_SEND */
351 #ifdef USE_NIT_RECEIVE
352 ssize_t
receive_packet (interface
, buf
, len
, from
, hfrom
)
353 struct interface_info
*interface
;
356 struct sockaddr_in
*from
;
357 struct hardware
*hfrom
;
362 unsigned char ibuf
[1536];
365 length
= read (interface
-> rfdesc
, ibuf
, sizeof ibuf
);
369 /* Decode the physical header... */
370 offset
= decode_hw_header (interface
, ibuf
, bufix
, hfrom
);
372 /* If a physical layer checksum failed (dunno of any
373 physical layer that supports this, but WTH), skip this
382 /* Decode the IP and UDP headers... */
383 offset
= decode_udp_ip_header (interface
, ibuf
, bufix
,
384 from
, (unsigned char *)0, length
);
386 /* If the IP or UDP checksum was bad, skip the packet... */
393 /* Copy out the data in the packet... */
394 memcpy (buf
, &ibuf
[bufix
], length
);
398 int can_unicast_without_arp (ip
)
399 struct interface_info
*ip
;
404 int can_receive_unicast_unconfigured (ip
)
405 struct interface_info
*ip
;
410 void maybe_setup_fallback ()
413 struct interface_info
*fbi
;
414 fbi
= setup_fallback ();
416 if_register_fallback (fbi
);
418 fbi
-> type
= dhcp_type_interface
;
419 status
= omapi_register_io_object ((omapi_object_t
*)fbi
,
421 fallback_discard
, 0, 0);
422 if (status
!= ISC_R_SUCCESS
)
423 log_fatal ("Can't register I/O handle for %s: %s",
424 fbi
-> name
, isc_result_totext (status
));