3 Network Interface Tap (NIT) network interface code, by Ted Lemon
4 with one crucial tidbit of help from Stu Grossmen. */
7 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1996-2003 by Internet Software Consortium
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * Internet Systems Consortium, Inc.
24 * Redwood City, CA 94063
28 * This software has been written for Internet Systems Consortium
29 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
30 * To learn more about Internet Systems Consortium, see
31 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
32 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
33 * ``http://www.nominum.com''.
37 static char copyright
[] =
38 "$Id$ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
42 #if defined (USE_NIT_SEND) || defined (USE_NIT_RECEIVE)
43 #include <sys/ioctl.h>
48 #include <net/nit_if.h>
49 #include <net/nit_pf.h>
50 #include <net/nit_buf.h>
51 #include <sys/stropts.h>
52 #include <net/packetfilt.h>
54 #include <netinet/in_systm.h>
55 #include "includes/netinet/ip.h"
56 #include "includes/netinet/udp.h"
57 #include "includes/netinet/if_ether.h"
59 /* Reinitializes the specified interface after an address change. This
60 is not required for packet-filter APIs. */
63 void if_reinitialize_send (info
)
64 struct interface_info
*info
;
69 #ifdef USE_NIT_RECEIVE
70 void if_reinitialize_receive (info
)
71 struct interface_info
*info
;
76 /* Called by get_interface_list for each interface that's discovered.
77 Opens a packet filter for each interface and adds it to the select
80 int if_register_nit (info
)
81 struct interface_info
*info
;
88 /* Open a NIT device */
89 sock
= open ("/dev/nit", O_RDWR
);
91 log_fatal ("Can't open NIT device for %s: %m", info
-> name
);
93 /* Set the NIT device to point at this interface. */
94 sio
.ic_cmd
= NIOCBIND
;
95 sio
.ic_len
= sizeof *(info
-> ifp
);
96 sio
.ic_dp
= (char *)(info
-> ifp
);
97 sio
.ic_timout
= INFTIM
;
98 if (ioctl (sock
, I_STR
, &sio
) < 0)
99 log_fatal ("Can't attach interface %s to nit device: %m",
102 /* Get the low-level address... */
103 sio
.ic_cmd
= SIOCGIFADDR
;
104 sio
.ic_len
= sizeof ifr
;
105 sio
.ic_dp
= (char *)&ifr
;
106 sio
.ic_timout
= INFTIM
;
107 if (ioctl (sock
, I_STR
, &sio
) < 0)
108 log_fatal ("Can't get physical layer address for %s: %m",
111 /* XXX code below assumes ethernet interface! */
112 info
-> hw_address
.hlen
= 7;
113 info
-> hw_address
.hbuf
[0] = ARPHRD_ETHER
;
114 memcpy (&info
-> hw_address
.hbuf
[1],
115 ifr
.ifr_ifru
.ifru_addr
.sa_data
, 6);
117 if (ioctl (sock
, I_PUSH
, "pf") < 0)
118 log_fatal ("Can't push packet filter onto NIT for %s: %m",
123 #endif /* USE_NIT_SEND || USE_NIT_RECEIVE */
126 void if_register_send (info
)
127 struct interface_info
*info
;
129 /* If we're using the nit API for sending and receiving,
130 we don't need to register this interface twice. */
131 #ifndef USE_NIT_RECEIVE
132 struct packetfilt pf
;
135 info
-> wfdesc
= if_register_nit (info
);
139 pf
.Pf_Filter
[0] = ENF_PUSHZERO
;
141 /* Set up an NIT filter that rejects everything... */
142 sio
.ic_cmd
= NIOCSETF
;
143 sio
.ic_len
= sizeof pf
;
144 sio
.ic_dp
= (char *)&pf
;
145 sio
.ic_timout
= INFTIM
;
146 if (ioctl (info
-> wfdesc
, I_STR
, &sio
) < 0)
147 log_fatal ("Can't set NIT filter: %m");
149 info
-> wfdesc
= info
-> rfdesc
;
151 if (!quiet_interface_discovery
)
152 log_info ("Sending on NIT/%s%s%s",
153 print_hw_addr (info
-> hw_address
.hbuf
[0],
154 info
-> hw_address
.hlen
- 1,
155 &info
-> hw_address
.hbuf
[1]),
156 (info
-> shared_network
? "/" : ""),
157 (info
-> shared_network
?
158 info
-> shared_network
-> name
: ""));
161 void if_deregister_send (info
)
162 struct interface_info
*info
;
164 /* If we're using the nit API for sending and receiving,
165 we don't need to register this interface twice. */
166 #ifndef USE_NIT_RECEIVE
167 close (info
-> wfdesc
);
170 if (!quiet_interface_discovery
)
171 log_info ("Disabling output on NIT/%s%s%s",
172 print_hw_addr (info
-> hw_address
.hbuf
[0],
173 info
-> hw_address
.hlen
- 1,
174 &info
-> hw_address
.hbuf
[1]),
175 (info
-> shared_network
? "/" : ""),
176 (info
-> shared_network
?
177 info
-> shared_network
-> name
: ""));
179 #endif /* USE_NIT_SEND */
181 #ifdef USE_NIT_RECEIVE
182 /* Packet filter program...
183 XXX Changes to the filter program may require changes to the constant
184 offsets used in if_register_send to patch the NIT program! XXX */
186 void if_register_receive (info
)
187 struct interface_info
*info
;
191 struct packetfilt pf
;
196 /* Open a NIT device and hang it on this interface... */
197 info
-> rfdesc
= if_register_nit (info
);
199 /* Set the snap length to 0, which means always take the whole
202 if (ioctl (info
-> rfdesc
, NIOCSSNAP
, &x
) < 0)
203 log_fatal ("Can't set NIT snap length on %s: %m", info
-> name
);
205 /* Set the stream to byte stream mode */
206 if (ioctl (info
-> rfdesc
, I_SRDOPT
, RMSGN
) != 0)
207 log_info ("I_SRDOPT failed on %s: %m", info
-> name
);
210 /* Push on the chunker... */
211 if (ioctl (info
-> rfdesc
, I_PUSH
, "nbuf") < 0)
212 log_fatal ("Can't push chunker onto NIT STREAM: %m");
214 /* Set the timeout to zero. */
217 if (ioctl (info
-> rfdesc
, NIOCSTIME
, &t
) < 0)
218 log_fatal ("Can't set chunk timeout: %m");
221 /* Ask for no header... */
223 if (ioctl (info
-> rfdesc
, NIOCSFLAGS
, &x
) < 0)
224 log_fatal ("Can't set NIT flags on %s: %m", info
-> name
);
226 /* Set up the NIT filter program. */
227 /* XXX Unlike the BPF filter program, this one won't work if the
228 XXX IP packet is fragmented or if there are options on the IP
233 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 6;
234 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
+ ENF_CAND
;
235 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (ETHERTYPE_IP
);
236 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
;
237 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (IPPROTO_UDP
);
238 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 11;
239 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
+ ENF_AND
;
240 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = htons (0xFF);
241 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_CAND
;
242 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHWORD
+ 18;
243 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = ENF_PUSHLIT
+ ENF_CAND
;
244 pf
.Pf_Filter
[pf
.Pf_FilterLen
++] = local_port
;
246 /* Install the filter... */
247 sio
.ic_cmd
= NIOCSETF
;
248 sio
.ic_len
= sizeof pf
;
249 sio
.ic_dp
= (char *)&pf
;
250 sio
.ic_timout
= INFTIM
;
251 if (ioctl (info
-> rfdesc
, I_STR
, &sio
) < 0)
252 log_fatal ("Can't set NIT filter on %s: %m", info
-> name
);
254 if (!quiet_interface_discovery
)
255 log_info ("Listening on NIT/%s%s%s",
256 print_hw_addr (info
-> hw_address
.hbuf
[0],
257 info
-> hw_address
.hlen
- 1,
258 &info
-> hw_address
.hbuf
[1]),
259 (info
-> shared_network
? "/" : ""),
260 (info
-> shared_network
?
261 info
-> shared_network
-> name
: ""));
264 void if_deregister_receive (info
)
265 struct interface_info
*info
;
267 /* If we're using the nit API for sending and receiving,
268 we don't need to register this interface twice. */
269 close (info
-> rfdesc
);
272 if (!quiet_interface_discovery
)
273 log_info ("Disabling input on NIT/%s%s%s",
274 print_hw_addr (info
-> hw_address
.hbuf
[0],
275 info
-> hw_address
.hlen
- 1,
276 &info
-> hw_address
.hbuf
[1]),
277 (info
-> shared_network
? "/" : ""),
278 (info
-> shared_network
?
279 info
-> shared_network
-> name
: ""));
281 #endif /* USE_NIT_RECEIVE */
284 ssize_t
send_packet (interface
, packet
, raw
, len
, from
, to
, hto
)
285 struct interface_info
*interface
;
286 struct packet
*packet
;
287 struct dhcp_packet
*raw
;
290 struct sockaddr_in
*to
;
291 struct hardware
*hto
;
293 unsigned hbufp
, ibufp
;
295 double ih
[1536 / sizeof (double)];
296 unsigned char *buf
= (unsigned char *)ih
;
297 struct sockaddr
*junk
;
298 struct strbuf ctl
, data
;
299 struct sockaddr_in foo
;
302 if (!strcmp (interface
-> name
, "fallback"))
303 return send_fallback (interface
, packet
, raw
,
306 /* Start with the sockaddr struct... */
307 junk
= (struct sockaddr
*)&hh
[0];
308 hbufp
= (((unsigned char *)&junk
-> sa_data
[0]) -
309 (unsigned char *)&hh
[0]);
312 /* Assemble the headers... */
313 assemble_hw_header (interface
, (unsigned char *)junk
, &hbufp
, hto
);
314 assemble_udp_ip_header (interface
, buf
, &ibufp
,
315 from
.s_addr
, to
-> sin_addr
.s_addr
,
316 to
-> sin_port
, (unsigned char *)raw
, len
);
318 /* Copy the data into the buffer (yuk). */
319 memcpy (buf
+ ibufp
, raw
, len
);
321 /* Set up the sockaddr structure... */
323 junk
-> sa_len
= hbufp
- 2; /* XXX */
325 junk
-> sa_family
= AF_UNSPEC
;
327 /* Set up the msg_buf structure... */
328 ctl
.buf
= (char *)&hh
[0];
329 ctl
.maxlen
= ctl
.len
= hbufp
;
330 data
.buf
= (char *)&ih
[0];
331 data
.maxlen
= data
.len
= ibufp
+ len
;
333 result
= putmsg (interface
-> wfdesc
, &ctl
, &data
, 0);
335 log_error ("send_packet: %m");
338 #endif /* USE_NIT_SEND */
340 #ifdef USE_NIT_RECEIVE
341 ssize_t
receive_packet (interface
, buf
, len
, from
, hfrom
)
342 struct interface_info
*interface
;
345 struct sockaddr_in
*from
;
346 struct hardware
*hfrom
;
351 unsigned char ibuf
[1536];
354 length
= read (interface
-> rfdesc
, ibuf
, sizeof ibuf
);
358 /* Decode the physical header... */
359 offset
= decode_hw_header (interface
, ibuf
, bufix
, hfrom
);
361 /* If a physical layer checksum failed (dunno of any
362 physical layer that supports this, but WTH), skip this
371 /* Decode the IP and UDP headers... */
372 offset
= decode_udp_ip_header (interface
, ibuf
, bufix
,
375 /* If the IP or UDP checksum was bad, skip the packet... */
382 /* Copy out the data in the packet... */
383 memcpy (buf
, &ibuf
[bufix
], length
);
387 int can_unicast_without_arp (ip
)
388 struct interface_info
*ip
;
393 int can_receive_unicast_unconfigured (ip
)
394 struct interface_info
*ip
;
399 int supports_multiple_interfaces (ip
)
400 struct interface_info
*ip
;
405 void maybe_setup_fallback ()
408 struct interface_info
*fbi
= (struct interface_info
*)0;
409 if (setup_fallback (&fbi
, MDL
)) {
410 if_register_fallback (fbi
);
411 status
= omapi_register_io_object ((omapi_object_t
*)fbi
,
413 fallback_discard
, 0, 0);
414 if (status
!= ISC_R_SUCCESS
)
415 log_fatal ("Can't register I/O handle for %s: %s",
416 fbi
-> name
, isc_result_totext (status
));
417 interface_dereference (&fbi
, MDL
);