This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / sys / netinet / ip_icmp.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
38e82238 33 * from: @(#)ip_icmp.c 7.15 (Berkeley) 4/20/91
fde1aeb2 34 * $Id: ip_icmp.c,v 1.5 1993/11/25 01:35:07 wollman Exp $
15637ed4
RG
35 */
36
37#include "param.h"
38#include "systm.h"
39#include "malloc.h"
40#include "mbuf.h"
41#include "protosw.h"
42#include "socket.h"
43#include "time.h"
44#include "kernel.h"
45
46#include "../net/route.h"
47#include "../net/if.h"
48
49#include "in.h"
50#include "in_systm.h"
51#include "in_var.h"
52#include "ip.h"
53#include "ip_icmp.h"
54#include "icmp_var.h"
55
56/*
57 * ICMP routines: error generation, receive packet processing, and
58 * routines to turnaround packets back to the originator, and
59 * host table maintenance routines.
60 */
15637ed4 61
2cb63509
GW
62#define satosin(sa) ((struct sockaddr_in *)(sa))
63static void icmp_reflect(struct mbuf *);
64static void icmp_send(struct mbuf *, struct mbuf *);
65
66
15637ed4
RG
67/*
68 * Generate an error packet of type error
69 * in response to bad packet ip.
70 */
2cb63509
GW
71void
72icmp_error(n, type, code, dest, mtu)
15637ed4
RG
73 struct mbuf *n;
74 int type, code;
75 struct in_addr dest;
2cb63509 76 int mtu; /* mtu for ICMP_UNREACH_SRCFRAG */
15637ed4
RG
77{
78 register struct ip *oip = mtod(n, struct ip *), *nip;
79 register unsigned oiplen = oip->ip_hl << 2;
80 register struct icmp *icp;
4c45483e 81 register struct mbuf *m = 0;
15637ed4 82 unsigned icmplen;
2cb63509 83 u_long oaddr;
15637ed4
RG
84
85#ifdef ICMPPRINTFS
86 if (icmpprintfs)
87 printf("icmp_error(%x, %d, %d)\n", oip, type, code);
88#endif
89 if (type != ICMP_REDIRECT)
90 icmpstat.icps_error++;
2cb63509
GW
91
92 /*
93 * Quoth RFC 1122 (Requirements for Internet Hosts):
94 *
95 * An ICMP error message MUST NOT be sent as the result of
96 * receiving:
97 * - an ICMP error message, or
98 * - a datagram destined to an IP broadcast or IP multicast
99 * address, or
100 * - a datagram sent as a link-layer broadcast, or
101 * - a non-initial fragment, or
102 * - a datagram whose source address does not define a single
103 * host -- e.g., a zero address, a loopback address, a
104 * broadcast address, a multicast address, or a Class E
105 * address.
106 *
107 * NOTE: THESE RESTRICTIONS TAKE PRECEDENCE OVER ANY REQUIREMENT
108 * ELSEWHERE IN THIS DOCUMENT FOR SENDING ICMP ERROR MESSAGES.
109 */
110
111 oaddr = ntohl(oip->ip_src.s_addr);
112
113 /*
114 * Don't send error messages to multicast or broadcast addresses.
115 */
116 if (IN_MULTICAST(oaddr)
117 || oaddr == INADDR_BROADCAST
118 || n->m_flags & (M_BCAST | M_MCAST)) {
119 icmpstat.icps_oldmcast++;
120 goto freeit;
121 }
122
123 /*
124 * Don't send error messages to zero addresses or class E's.
125 */
126 if (IN_EXPERIMENTAL(oaddr)
127 || ! in_lnaof(oip->ip_src)
128 || ! in_netof(oip->ip_src)) {
129 icmpstat.icps_oldbadaddr++;
130 goto freeit;
131 }
132
133 /*
134 * Don't send error messages to loopback addresses.
135 * As a special (unauthorized) exception, we check to see
136 * if the packet came from the loopback interface. If it
137 * did, then we should allow the errors through, because
138 * the upper layers rely on them.
139 */
140 if(in_netof(oip->ip_src) == IN_LOOPBACKNET
141 && !(m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK)) {
142 icmpstat.icps_oldbadaddr++;
143 goto freeit;
144 }
145
15637ed4
RG
146 /*
147 * Don't send error if not the first fragment of message.
148 * Don't error if the old packet protocol was ICMP
149 * error message, only known informational types.
150 */
151 if (oip->ip_off &~ (IP_MF|IP_DF))
152 goto freeit;
153 if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
154 n->m_len >= oiplen + ICMP_MINLEN &&
155 !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
156 icmpstat.icps_oldicmp++;
157 goto freeit;
158 }
159
160 /*
161 * First, formulate icmp message
162 */
163 m = m_gethdr(M_DONTWAIT, MT_HEADER);
164 if (m == NULL)
165 goto freeit;
166 icmplen = oiplen + min(8, oip->ip_len);
167 m->m_len = icmplen + ICMP_MINLEN;
168 MH_ALIGN(m, m->m_len);
169 icp = mtod(m, struct icmp *);
170 if ((u_int)type > ICMP_MAXTYPE)
171 panic("icmp_error");
172 icmpstat.icps_outhist[type]++;
173 icp->icmp_type = type;
174 if (type == ICMP_REDIRECT)
175 icp->icmp_gwaddr = dest;
2cb63509
GW
176 else if (type == ICMP_UNREACH && code == ICMP_UNREACH_NEEDFRAG) {
177 icp->icmp_mtu = htons(mtu);
178 icp->icmp_mtuvoid = 0;
179 } else {
15637ed4 180 icp->icmp_void = 0;
2cb63509 181 }
15637ed4
RG
182 if (type == ICMP_PARAMPROB) {
183 icp->icmp_pptr = code;
184 code = 0;
185 }
186 icp->icmp_code = code;
187 bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
188 nip = &icp->icmp_ip;
189 nip->ip_len = htons((u_short)(nip->ip_len + oiplen));
190
191 /*
192 * Now, copy old ip header (without options)
193 * in front of icmp message.
194 */
195 if (m->m_data - sizeof(struct ip) < m->m_pktdat)
196 panic("icmp len");
197 m->m_data -= sizeof(struct ip);
198 m->m_len += sizeof(struct ip);
199 m->m_pkthdr.len = m->m_len;
200 m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
201 nip = mtod(m, struct ip *);
202 bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
203 nip->ip_len = m->m_len;
204 nip->ip_hl = sizeof(struct ip) >> 2;
205 nip->ip_p = IPPROTO_ICMP;
206 icmp_reflect(m);
207
208freeit:
209 m_freem(n);
210}
211
212static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
213static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
214static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
215static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
15637ed4
RG
216
217/*
218 * Process a received ICMP message.
219 */
2cb63509 220void
15637ed4
RG
221icmp_input(m, hlen)
222 register struct mbuf *m;
223 int hlen;
224{
225 register struct icmp *icp;
226 register struct ip *ip = mtod(m, struct ip *);
227 int icmplen = ip->ip_len;
228 register int i;
229 struct in_ifaddr *ia;
fde1aeb2
GW
230 in_ctlinput_t *ctlfunc;
231 int code;
15637ed4
RG
232
233 /*
234 * Locate icmp structure in mbuf, and check
235 * that not corrupted and of at least minimum length.
236 */
237#ifdef ICMPPRINTFS
238 if (icmpprintfs)
239 printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
240#endif
241 if (icmplen < ICMP_MINLEN) {
242 icmpstat.icps_tooshort++;
243 goto freeit;
244 }
245 i = hlen + MIN(icmplen, ICMP_ADVLENMIN);
246 if (m->m_len < i && (m = m_pullup(m, i)) == 0) {
247 icmpstat.icps_tooshort++;
248 return;
249 }
250 ip = mtod(m, struct ip *);
251 m->m_len -= hlen;
252 m->m_data += hlen;
253 icp = mtod(m, struct icmp *);
254 if (in_cksum(m, icmplen)) {
255 icmpstat.icps_checksum++;
256 goto freeit;
257 }
258 m->m_len += hlen;
259 m->m_data -= hlen;
260
261#ifdef ICMPPRINTFS
262 /*
263 * Message type specific processing.
264 */
265 if (icmpprintfs)
266 printf("icmp_input, type %d code %d\n", icp->icmp_type,
267 icp->icmp_code);
268#endif
269 if (icp->icmp_type > ICMP_MAXTYPE)
270 goto raw;
271 icmpstat.icps_inhist[icp->icmp_type]++;
272 code = icp->icmp_code;
273 switch (icp->icmp_type) {
274
275 case ICMP_UNREACH:
2cb63509 276 if (code > ICMP_UNREACH_MAXCODE)
15637ed4 277 goto badcode;
2cb63509
GW
278 if (code == ICMP_UNREACH_NEEDFRAG) {
279#ifdef MTUDISC
280 /*
281 * Need to adjust the routing tables immediately;
282 * when ULP's get the PRC_MSGSIZE, it is their
283 * responsibility to notice it and update their
284 * internal ideas of MTU-derived protocol parameters.
285 */
286 in_mtureduce(icp->icmp_ip.ip_dst,
287 ntohs(icp->icmp_mtu));
288 code = PRC_MSGSIZE;
289#endif /* MTUDISC */
290 } else {
291 code += PRC_UNREACH_NET;
292 }
15637ed4
RG
293 goto deliver;
294
295 case ICMP_TIMXCEED:
2cb63509 296 if (code > ICMP_TIMXCEED_MAXCODE)
15637ed4
RG
297 goto badcode;
298 code += PRC_TIMXCEED_INTRANS;
299 goto deliver;
300
301 case ICMP_PARAMPROB:
2cb63509 302 if (code > ICMP_PARAMPROB_MAXCODE)
15637ed4 303 goto badcode;
2cb63509 304 code += PRC_PARAMPROB;
15637ed4
RG
305 goto deliver;
306
307 case ICMP_SOURCEQUENCH:
308 if (code)
309 goto badcode;
310 code = PRC_QUENCH;
311 deliver:
312 /*
313 * Problem with datagram; advise higher level routines.
314 */
315 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
316 icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
317 icmpstat.icps_badlen++;
318 goto freeit;
319 }
320 NTOHS(icp->icmp_ip.ip_len);
321#ifdef ICMPPRINTFS
322 if (icmpprintfs)
323 printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
324#endif
325 icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
326 if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
327 (*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
fde1aeb2 328 &icp->icmp_ip);
15637ed4
RG
329 break;
330
331 badcode:
332 icmpstat.icps_badcode++;
333 break;
334
2cb63509
GW
335 /*
336 * Always respond to pings from valid addresses.
337 * Don't respond to broadcast pings unless ipbroadcastecho
338 * is set. Don't respond to multicast pings unless
339 * ipbraodcastecho is set AND we support multicasting
340 * to begin with. (Per RFC 1122, we may choose either.)
341 */
15637ed4 342 case ICMP_ECHO:
2cb63509
GW
343 {
344 u_long srcaddr = ntohl(icp->icmp_ip.ip_src.s_addr);
345#ifdef MULTICAST
346 if(IN_MULTICAST(srcaddr) && !ipbroadcastecho)
347 break;
348#else /* not MULTICAST */
349 if(IN_MULTICAST(srcaddr))
350 break;
351#endif /* not MULTICAST */
352 if((srcaddr == INADDR_BROADCAST
353 || m->m_flags & M_BCAST)
354 && !ipbroadcastecho)
355 break;
356 }
357
15637ed4
RG
358 icp->icmp_type = ICMP_ECHOREPLY;
359 goto reflect;
360
361 case ICMP_TSTAMP:
362 if (icmplen < ICMP_TSLEN) {
363 icmpstat.icps_badlen++;
364 break;
365 }
366 icp->icmp_type = ICMP_TSTAMPREPLY;
367 icp->icmp_rtime = iptime();
368 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */
369 goto reflect;
370
2cb63509
GW
371 /*
372 * Per RFC 1122, only respond to ICMP mask requests
373 * if the administrator has SPECIFICALLY CONFIGURED
374 * this host as an address mask agent.
375 */
15637ed4 376 case ICMP_MASKREQ:
2cb63509
GW
377 if (!ipmaskagent)
378 break;
15637ed4
RG
379 if (icmplen < ICMP_MASKLEN ||
380 (ia = ifptoia(m->m_pkthdr.rcvif)) == 0)
381 break;
382 icp->icmp_type = ICMP_MASKREPLY;
383 icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
384 if (ip->ip_src.s_addr == 0) {
385 if (ia->ia_ifp->if_flags & IFF_BROADCAST)
386 ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
387 else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
388 ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
389 }
390reflect:
391 ip->ip_len += hlen; /* since ip_input deducts this */
392 icmpstat.icps_reflect++;
393 icmpstat.icps_outhist[icp->icmp_type]++;
394 icmp_reflect(m);
395 return;
396
397 case ICMP_REDIRECT:
398 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
399 icmpstat.icps_badlen++;
400 break;
401 }
402 /*
403 * Short circuit routing redirects to force
404 * immediate change in the kernel's routing
405 * tables. The message is also handed to anyone
406 * listening on a raw socket (e.g. the routing
407 * daemon for use in updating its tables).
408 */
409 icmpgw.sin_addr = ip->ip_src;
410 icmpdst.sin_addr = icp->icmp_gwaddr;
411#ifdef ICMPPRINTFS
412 if (icmpprintfs)
413 printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst,
414 icp->icmp_gwaddr);
415#endif
2cb63509
GW
416 /*
417 * Per RFC 1122, throw away redirects that
418 * suggested places we can't get to, or
419 * an interface other than the one the packet
420 * arrived on.
421 *
422 * It also says that we SHOULD throw away
423 * redirects that come from someone other
424 * than the current first-hop gateway for the
425 * specified destination.
426 *
427 * These are both implemented as general policy
428 * by rtredirect().
429 */
15637ed4 430 if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) {
15637ed4
RG
431 icmpsrc.sin_addr =
432 in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY);
433 in_sockmaskof(icp->icmp_ip.ip_dst, &icmpmask);
434 rtredirect((struct sockaddr *)&icmpsrc,
435 (struct sockaddr *)&icmpdst,
436 (struct sockaddr *)&icmpmask, RTF_GATEWAY,
437 (struct sockaddr *)&icmpgw, (struct rtentry **)0);
438 icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
439 pfctlinput(PRC_REDIRECT_NET,
440 (struct sockaddr *)&icmpsrc);
441 } else {
442 icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
443 rtredirect((struct sockaddr *)&icmpsrc,
444 (struct sockaddr *)&icmpdst,
445 (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
446 (struct sockaddr *)&icmpgw, (struct rtentry **)0);
447 pfctlinput(PRC_REDIRECT_HOST,
448 (struct sockaddr *)&icmpsrc);
449 }
450 break;
451
452 /*
453 * No kernel processing for the following;
454 * just fall through to send to raw listener.
455 */
456 case ICMP_ECHOREPLY:
457 case ICMP_TSTAMPREPLY:
458 case ICMP_IREQREPLY:
459 case ICMP_MASKREPLY:
460 default:
461 break;
462 }
463
464raw:
465 icmpsrc.sin_addr = ip->ip_src;
466 icmpdst.sin_addr = ip->ip_dst;
467 (void) raw_input(m, &icmproto, (struct sockaddr *)&icmpsrc,
468 (struct sockaddr *)&icmpdst);
469 return;
470
471freeit:
472 m_freem(m);
473}
474
475/*
476 * Reflect the ip packet back to the source
477 */
2cb63509 478static void
15637ed4
RG
479icmp_reflect(m)
480 struct mbuf *m;
481{
482 register struct ip *ip = mtod(m, struct ip *);
483 register struct in_ifaddr *ia;
484 struct in_addr t;
485 struct mbuf *opts = 0, *ip_srcroute();
486 int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
487
488 t = ip->ip_dst;
489 ip->ip_dst = ip->ip_src;
490 /*
491 * If the incoming packet was addressed directly to us,
492 * use dst as the src for the reply. Otherwise (broadcast
493 * or anonymous), use the address which corresponds
494 * to the incoming interface.
495 */
496 for (ia = in_ifaddr; ia; ia = ia->ia_next) {
497 if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
498 break;
499 if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
500 t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
501 break;
502 }
503 if (ia == (struct in_ifaddr *)0)
504 ia = ifptoia(m->m_pkthdr.rcvif);
505 if (ia == (struct in_ifaddr *)0)
506 ia = in_ifaddr;
507 t = IA_SIN(ia)->sin_addr;
508 ip->ip_src = t;
509 ip->ip_ttl = MAXTTL;
510
511 if (optlen > 0) {
512 register u_char *cp;
513 int opt, cnt;
514 u_int len;
515
516 /*
517 * Retrieve any source routing from the incoming packet;
518 * add on any record-route or timestamp options.
519 */
520 cp = (u_char *) (ip + 1);
521 if ((opts = ip_srcroute()) == 0 &&
522 (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
523 opts->m_len = sizeof(struct in_addr);
524 mtod(opts, struct in_addr *)->s_addr = 0;
525 }
526 if (opts) {
527#ifdef ICMPPRINTFS
528 if (icmpprintfs)
529 printf("icmp_reflect optlen %d rt %d => ",
530 optlen, opts->m_len);
531#endif
532 for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
533 opt = cp[IPOPT_OPTVAL];
534 if (opt == IPOPT_EOL)
535 break;
536 if (opt == IPOPT_NOP)
537 len = 1;
538 else {
539 len = cp[IPOPT_OLEN];
540 if (len <= 0 || len > cnt)
541 break;
542 }
543 /*
544 * should check for overflow, but it "can't happen"
545 */
546 if (opt == IPOPT_RR || opt == IPOPT_TS) {
547 bcopy((caddr_t)cp,
548 mtod(opts, caddr_t) + opts->m_len, len);
549 opts->m_len += len;
550 }
551 }
552 if (opts->m_len % 4 != 0) {
553 *(mtod(opts, caddr_t) + opts->m_len) = IPOPT_EOL;
554 opts->m_len++;
555 }
556#ifdef ICMPPRINTFS
557 if (icmpprintfs)
558 printf("%d\n", opts->m_len);
559#endif
560 }
561 /*
562 * Now strip out original options by copying rest of first
563 * mbuf's data back, and adjust the IP length.
564 */
565 ip->ip_len -= optlen;
566 ip->ip_hl = sizeof(struct ip) >> 2;
567 m->m_len -= optlen;
568 if (m->m_flags & M_PKTHDR)
569 m->m_pkthdr.len -= optlen;
570 optlen += sizeof(struct ip);
571 bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
572 (unsigned)(m->m_len - sizeof(struct ip)));
573 }
574 icmp_send(m, opts);
575 if (opts)
576 (void)m_free(opts);
577}
578
579struct in_ifaddr *
580ifptoia(ifp)
581 struct ifnet *ifp;
582{
583 register struct in_ifaddr *ia;
584
585 for (ia = in_ifaddr; ia; ia = ia->ia_next)
586 if (ia->ia_ifp == ifp)
587 return (ia);
588 return ((struct in_ifaddr *)0);
589}
590
591/*
592 * Send an icmp packet back to the ip level,
593 * after supplying a checksum.
594 */
2cb63509 595static void
15637ed4
RG
596icmp_send(m, opts)
597 register struct mbuf *m;
598 struct mbuf *opts;
599{
600 register struct ip *ip = mtod(m, struct ip *);
601 register int hlen;
602 register struct icmp *icp;
603
604 hlen = ip->ip_hl << 2;
605 m->m_data += hlen;
606 m->m_len -= hlen;
607 icp = mtod(m, struct icmp *);
608 icp->icmp_cksum = 0;
609 icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
610 m->m_data -= hlen;
611 m->m_len += hlen;
612#ifdef ICMPPRINTFS
613 if (icmpprintfs)
614 printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
615#endif
616 (void) ip_output(m, opts, (struct route *)0, 0);
617}
618
619n_time
620iptime()
621{
622 struct timeval atv;
623 u_long t;
624
625 microtime(&atv);
626 t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
627 return (htonl(t));
628}