123182Smckusick /* 2*40684Skarels * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 332787Sbostic * All rights reserved. 423182Smckusick * 532787Sbostic * Redistribution and use in source and binary forms are permitted 634854Sbostic * provided that the above copyright notice and this paragraph are 734854Sbostic * duplicated in all such forms and that any documentation, 834854Sbostic * advertising materials, and other materials related to such 934854Sbostic * distribution and use acknowledge that the software was developed 1034854Sbostic * by the University of California, Berkeley. The name of the 1134854Sbostic * University may not be used to endorse or promote products derived 1234854Sbostic * from this software without specific prior written permission. 1334854Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434854Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534854Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1632787Sbostic * 17*40684Skarels * @(#)ip_icmp.c 7.13 (Berkeley) 04/03/90 1823182Smckusick */ 194785Swnj 2017059Sbloom #include "param.h" 2117059Sbloom #include "systm.h" 22*40684Skarels #include "malloc.h" 2317059Sbloom #include "mbuf.h" 2417059Sbloom #include "protosw.h" 2517059Sbloom #include "socket.h" 2617059Sbloom #include "time.h" 2717059Sbloom #include "kernel.h" 288694Sroot 298694Sroot #include "../net/route.h" 3018373Skarels #include "../net/if.h" 3110891Ssam 3217059Sbloom #include "in.h" 3317059Sbloom #include "in_systm.h" 3418373Skarels #include "in_var.h" 3517059Sbloom #include "ip.h" 3617059Sbloom #include "ip_icmp.h" 3717059Sbloom #include "icmp_var.h" 384785Swnj 394785Swnj /* 404785Swnj * ICMP routines: error generation, receive packet processing, and 414785Swnj * routines to turnaround packets back to the originator, and 424785Swnj * host table maintenance routines. 434785Swnj */ 44*40684Skarels #ifdef ICMPPRINTFS 456608Ssam int icmpprintfs = 0; 4615027Smckusick #endif 474785Swnj 484785Swnj /* 496583Ssam * Generate an error packet of type error 506583Ssam * in response to bad packet ip. 514785Swnj */ 52*40684Skarels /*VARARGS3*/ 53*40684Skarels icmp_error(n, type, code, dest) 54*40684Skarels struct mbuf *n; 5512764Ssam int type, code; 5624811Skarels struct in_addr dest; 574785Swnj { 58*40684Skarels register struct ip *oip = mtod(n, struct ip *), *nip; 596583Ssam register unsigned oiplen = oip->ip_hl << 2; 606583Ssam register struct icmp *icp; 6135794Skarels register struct mbuf *m; 6226383Skarels unsigned icmplen; 634785Swnj 6415027Smckusick #ifdef ICMPPRINTFS 656590Ssam if (icmpprintfs) 666590Ssam printf("icmp_error(%x, %d, %d)\n", oip, type, code); 6715027Smckusick #endif 6826034Skarels if (type != ICMP_REDIRECT) 6926034Skarels icmpstat.icps_error++; 704785Swnj /* 7124811Skarels * Don't send error if not the first fragment of message. 7231399Skarels * Don't error if the old packet protocol was ICMP 7331399Skarels * error message, only known informational types. 744785Swnj */ 7524811Skarels if (oip->ip_off &~ (IP_MF|IP_DF)) 76*40684Skarels goto freeit; 7731399Skarels if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && 78*40684Skarels n->m_len >= oiplen + ICMP_MINLEN && 7931399Skarels !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) { 8011532Ssam icmpstat.icps_oldicmp++; 81*40684Skarels goto freeit; 8211532Ssam } 834785Swnj 844785Swnj /* 856583Ssam * First, formulate icmp message 864785Swnj */ 87*40684Skarels m = m_gethdr(M_DONTWAIT, MT_HEADER); 8811532Ssam if (m == NULL) 89*40684Skarels goto freeit; 9035794Skarels icmplen = oiplen + min(8, oip->ip_len); 9124811Skarels m->m_len = icmplen + ICMP_MINLEN; 92*40684Skarels MH_ALIGN(m, m->m_len); 936583Ssam icp = mtod(m, struct icmp *); 9424811Skarels if ((u_int)type > ICMP_MAXTYPE) 9511532Ssam panic("icmp_error"); 9611532Ssam icmpstat.icps_outhist[type]++; 974785Swnj icp->icmp_type = type; 9824811Skarels if (type == ICMP_REDIRECT) 9924811Skarels icp->icmp_gwaddr = dest; 10024811Skarels else 10124811Skarels icp->icmp_void = 0; 1024785Swnj if (type == ICMP_PARAMPROB) { 1034785Swnj icp->icmp_pptr = code; 1046583Ssam code = 0; 1056583Ssam } 1066583Ssam icp->icmp_code = code; 10724811Skarels bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen); 1086590Ssam nip = &icp->icmp_ip; 10935794Skarels nip->ip_len = htons((u_short)(nip->ip_len + oiplen)); 1104785Swnj 1114785Swnj /* 11236817Skarels * Now, copy old ip header (without options) 11336817Skarels * in front of icmp message. 1144785Swnj */ 115*40684Skarels if (m->m_data - sizeof(struct ip) < m->m_pktdat) 11624811Skarels panic("icmp len"); 117*40684Skarels m->m_data -= sizeof(struct ip); 11836817Skarels m->m_len += sizeof(struct ip); 119*40684Skarels m->m_pkthdr.len = m->m_len; 120*40684Skarels m->m_pkthdr.rcvif = n->m_pkthdr.rcvif; 1216583Ssam nip = mtod(m, struct ip *); 1226583Ssam bcopy((caddr_t)oip, (caddr_t)nip, oiplen); 12327063Skarels nip->ip_len = m->m_len; 12436817Skarels nip->ip_hl = sizeof(struct ip) >> 2; 1256583Ssam nip->ip_p = IPPROTO_ICMP; 126*40684Skarels icmp_reflect(m); 1274785Swnj 128*40684Skarels freeit: 129*40684Skarels m_freem(n); 1304785Swnj } 1314785Swnj 1326583Ssam static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP }; 133*40684Skarels static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET }; 134*40684Skarels static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET }; 135*40684Skarels static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET }; 136*40684Skarels struct sockaddr_in icmpmask = { 8, 0 }; 13724811Skarels struct in_ifaddr *ifptoia(); 1386583Ssam 1394785Swnj /* 1404801Swnj * Process a received ICMP message. 1414785Swnj */ 142*40684Skarels icmp_input(m, hlen) 14327194Skarels register struct mbuf *m; 144*40684Skarels int hlen; 1454785Swnj { 1464801Swnj register struct icmp *icp; 1474801Swnj register struct ip *ip = mtod(m, struct ip *); 148*40684Skarels int icmplen = ip->ip_len; 14916171Skarels register int i; 15024811Skarels struct in_ifaddr *ia; 15116171Skarels int (*ctlfunc)(), code; 1525172Swnj extern u_char ip_protox[]; 15318373Skarels extern struct in_addr in_makeaddr(); 1544785Swnj 1554785Swnj /* 1564785Swnj * Locate icmp structure in mbuf, and check 1574785Swnj * that not corrupted and of at least minimum length. 1584785Swnj */ 15915027Smckusick #ifdef ICMPPRINTFS 1606590Ssam if (icmpprintfs) 1616590Ssam printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen); 16215027Smckusick #endif 16315913Skarels if (icmplen < ICMP_MINLEN) { 16411532Ssam icmpstat.icps_tooshort++; 165*40684Skarels goto freeit; 16611532Ssam } 16724811Skarels i = hlen + MIN(icmplen, ICMP_ADVLENMIN); 168*40684Skarels if (m->m_len < i && (m = m_pullup(m, i)) == 0) { 16915831Skarels icmpstat.icps_tooshort++; 17015831Skarels return; 17115831Skarels } 17216171Skarels ip = mtod(m, struct ip *); 1734785Swnj m->m_len -= hlen; 174*40684Skarels m->m_data += hlen; 1756583Ssam icp = mtod(m, struct icmp *); 17616171Skarels if (in_cksum(m, icmplen)) { 17711532Ssam icmpstat.icps_checksum++; 178*40684Skarels goto freeit; 1796583Ssam } 18027063Skarels m->m_len += hlen; 181*40684Skarels m->m_data -= hlen; 1824785Swnj 18315027Smckusick #ifdef ICMPPRINTFS 1844785Swnj /* 1854785Swnj * Message type specific processing. 1864785Swnj */ 1876590Ssam if (icmpprintfs) 1886590Ssam printf("icmp_input, type %d code %d\n", icp->icmp_type, 18915027Smckusick icp->icmp_code); 19015027Smckusick #endif 19124811Skarels if (icp->icmp_type > ICMP_MAXTYPE) 19227194Skarels goto raw; 19311532Ssam icmpstat.icps_inhist[icp->icmp_type]++; 19415027Smckusick code = icp->icmp_code; 19511532Ssam switch (icp->icmp_type) { 1964785Swnj 1974785Swnj case ICMP_UNREACH: 19815027Smckusick if (code > 5) 19915027Smckusick goto badcode; 20015027Smckusick code += PRC_UNREACH_NET; 20115027Smckusick goto deliver; 20215027Smckusick 2034785Swnj case ICMP_TIMXCEED: 20415027Smckusick if (code > 1) 20515027Smckusick goto badcode; 20615027Smckusick code += PRC_TIMXCEED_INTRANS; 20715027Smckusick goto deliver; 20815027Smckusick 2094785Swnj case ICMP_PARAMPROB: 21015027Smckusick if (code) 21115027Smckusick goto badcode; 21215027Smckusick code = PRC_PARAMPROB; 21315027Smckusick goto deliver; 21415027Smckusick 2154785Swnj case ICMP_SOURCEQUENCH: 21615027Smckusick if (code) 21715027Smckusick goto badcode; 21815027Smckusick code = PRC_QUENCH; 21915027Smckusick deliver: 2204785Swnj /* 22115027Smckusick * Problem with datagram; advise higher level routines. 2224785Swnj */ 223*40684Skarels if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) || 224*40684Skarels icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) { 22511532Ssam icmpstat.icps_badlen++; 226*40684Skarels goto freeit; 22711532Ssam } 228*40684Skarels NTOHS(icp->icmp_ip.ip_len); 22915027Smckusick #ifdef ICMPPRINTFS 2306590Ssam if (icmpprintfs) 2316590Ssam printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); 23215027Smckusick #endif 23324811Skarels icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 2349030Sroot if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput) 235*40684Skarels (*ctlfunc)(code, (struct sockaddr *)&icmpsrc, 236*40684Skarels (caddr_t) &icp->icmp_ip); 23727063Skarels break; 2384785Swnj 23915027Smckusick badcode: 24015027Smckusick icmpstat.icps_badcode++; 24127063Skarels break; 24215027Smckusick 2434785Swnj case ICMP_ECHO: 2444785Swnj icp->icmp_type = ICMP_ECHOREPLY; 2454785Swnj goto reflect; 2464785Swnj 2474785Swnj case ICMP_TSTAMP: 24811532Ssam if (icmplen < ICMP_TSLEN) { 24911532Ssam icmpstat.icps_badlen++; 25027063Skarels break; 25111532Ssam } 2524785Swnj icp->icmp_type = ICMP_TSTAMPREPLY; 2534923Swnj icp->icmp_rtime = iptime(); 2544785Swnj icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 2554785Swnj goto reflect; 2564785Swnj 2574785Swnj case ICMP_IREQ: 25818373Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 259*40684Skarels if (in_netof(ip->ip_src) == 0 && 260*40684Skarels (ia = ifptoia(m->m_pkthdr.rcvif))) 26124811Skarels ip->ip_src = in_makeaddr(in_netof(IA_SIN(ia)->sin_addr), 26218373Skarels in_lnaof(ip->ip_src)); 26318373Skarels icp->icmp_type = ICMP_IREQREPLY; 2644785Swnj goto reflect; 2654785Swnj 26624811Skarels case ICMP_MASKREQ: 267*40684Skarels if (icmplen < ICMP_MASKLEN || 268*40684Skarels (ia = ifptoia(m->m_pkthdr.rcvif)) == 0) 26927063Skarels break; 27030362Skarels icp->icmp_type = ICMP_MASKREPLY; 271*40684Skarels icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr; 27224811Skarels if (ip->ip_src.s_addr == 0) { 27324811Skarels if (ia->ia_ifp->if_flags & IFF_BROADCAST) 27424811Skarels ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr; 27524811Skarels else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) 27624811Skarels ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; 27724811Skarels } 27827063Skarels reflect: 27927063Skarels ip->ip_len += hlen; /* since ip_input deducts this */ 28027063Skarels icmpstat.icps_reflect++; 28127063Skarels icmpstat.icps_outhist[icp->icmp_type]++; 282*40684Skarels icmp_reflect(m); 28327063Skarels return; 28424811Skarels 28511549Ssam case ICMP_REDIRECT: 28611532Ssam if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) { 28711532Ssam icmpstat.icps_badlen++; 28827063Skarels break; 28911532Ssam } 29011549Ssam /* 29111549Ssam * Short circuit routing redirects to force 29211549Ssam * immediate change in the kernel's routing 29311549Ssam * tables. The message is also handed to anyone 29411549Ssam * listening on a raw socket (e.g. the routing 29517046Skarels * daemon for use in updating its tables). 29611549Ssam */ 29724811Skarels icmpgw.sin_addr = ip->ip_src; 29815831Skarels icmpdst.sin_addr = icp->icmp_gwaddr; 29924811Skarels #ifdef ICMPPRINTFS 30024811Skarels if (icmpprintfs) 30124811Skarels printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst, 30224811Skarels icp->icmp_gwaddr); 30324811Skarels #endif 30417046Skarels if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) { 305*40684Skarels u_long in_netof(); 30617046Skarels icmpsrc.sin_addr = 30718373Skarels in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY); 308*40684Skarels in_sockmaskof(icp->icmp_ip.ip_dst, &icmpmask); 30917046Skarels rtredirect((struct sockaddr *)&icmpsrc, 310*40684Skarels (struct sockaddr *)&icmpdst, 311*40684Skarels (struct sockaddr *)&icmpmask, RTF_GATEWAY, 312*40684Skarels (struct sockaddr *)&icmpgw, (struct rtentry **)0); 31327194Skarels icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 31424811Skarels pfctlinput(PRC_REDIRECT_NET, 31524811Skarels (struct sockaddr *)&icmpsrc); 31617046Skarels } else { 31717046Skarels icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 31817046Skarels rtredirect((struct sockaddr *)&icmpsrc, 319*40684Skarels (struct sockaddr *)&icmpdst, 320*40684Skarels (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, 321*40684Skarels (struct sockaddr *)&icmpgw, (struct rtentry **)0); 32224811Skarels pfctlinput(PRC_REDIRECT_HOST, 32324811Skarels (struct sockaddr *)&icmpsrc); 32417046Skarels } 32527063Skarels break; 32615831Skarels 32727063Skarels /* 32827063Skarels * No kernel processing for the following; 32927063Skarels * just fall through to send to raw listener. 33027063Skarels */ 33115831Skarels case ICMP_ECHOREPLY: 33215831Skarels case ICMP_TSTAMPREPLY: 33315831Skarels case ICMP_IREQREPLY: 33424811Skarels case ICMP_MASKREPLY: 3354785Swnj default: 33627063Skarels break; 3374785Swnj } 33827063Skarels 33927194Skarels raw: 34027063Skarels icmpsrc.sin_addr = ip->ip_src; 34127063Skarels icmpdst.sin_addr = ip->ip_dst; 342*40684Skarels (void) raw_input(m, &icmproto, (struct sockaddr *)&icmpsrc, 34327063Skarels (struct sockaddr *)&icmpdst); 3449185Ssam return; 34527063Skarels 346*40684Skarels freeit: 34727063Skarels m_freem(m); 3484785Swnj } 3494785Swnj 3504785Swnj /* 3514785Swnj * Reflect the ip packet back to the source 3524785Swnj */ 353*40684Skarels icmp_reflect(m) 354*40684Skarels struct mbuf *m; 3554785Swnj { 356*40684Skarels register struct ip *ip = mtod(m, struct ip *); 35718373Skarels register struct in_ifaddr *ia; 35824811Skarels struct in_addr t; 35928926Skarels struct mbuf *opts = 0, *ip_srcroute(); 36027063Skarels int optlen = (ip->ip_hl << 2) - sizeof(struct ip); 3614785Swnj 3626583Ssam t = ip->ip_dst; 36324811Skarels ip->ip_dst = ip->ip_src; 36424811Skarels /* 36524811Skarels * If the incoming packet was addressed directly to us, 36624811Skarels * use dst as the src for the reply. Otherwise (broadcast 36724811Skarels * or anonymous), use the address which corresponds 36824811Skarels * to the incoming interface. 36924811Skarels */ 37024811Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) { 37124811Skarels if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) 37218373Skarels break; 37324811Skarels if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && 37424811Skarels t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) 37524811Skarels break; 37624811Skarels } 37724811Skarels if (ia == (struct in_ifaddr *)0) 378*40684Skarels ia = ifptoia(m->m_pkthdr.rcvif); 37928344Skarels if (ia == (struct in_ifaddr *)0) 38028344Skarels ia = in_ifaddr; 38128344Skarels t = IA_SIN(ia)->sin_addr; 38224811Skarels ip->ip_src = t; 38330971Skarels ip->ip_ttl = MAXTTL; 38424811Skarels 38527063Skarels if (optlen > 0) { 38636817Skarels register u_char *cp; 387*40684Skarels int opt, cnt; 38836817Skarels u_int len; 38936817Skarels 39026034Skarels /* 39136817Skarels * Retrieve any source routing from the incoming packet; 39236817Skarels * add on any record-route or timestamp options. 39326034Skarels */ 39436817Skarels cp = (u_char *) (ip + 1); 39536948Skarels if ((opts = ip_srcroute()) == 0 && 396*40684Skarels (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) { 39736948Skarels opts->m_len = sizeof(struct in_addr); 39836948Skarels mtod(opts, struct in_addr *)->s_addr = 0; 39936948Skarels } 40036948Skarels if (opts) { 40136948Skarels #ifdef ICMPPRINTFS 40236948Skarels if (icmpprintfs) 40336948Skarels printf("icmp_reflect optlen %d rt %d => ", 40436948Skarels optlen, opts->m_len); 40536948Skarels #endif 40636817Skarels for (cnt = optlen; cnt > 0; cnt -= len, cp += len) { 40736948Skarels opt = cp[IPOPT_OPTVAL]; 40836948Skarels if (opt == IPOPT_EOL) 40936948Skarels break; 41036948Skarels if (opt == IPOPT_NOP) 41136948Skarels len = 1; 41236948Skarels else { 41336948Skarels len = cp[IPOPT_OLEN]; 41436948Skarels if (len <= 0 || len > cnt) 41536948Skarels break; 41636948Skarels } 41736948Skarels /* 41836948Skarels * should check for overflow, but it "can't happen" 41936948Skarels */ 42036948Skarels if (opt == IPOPT_RR || opt == IPOPT_TS) { 42136948Skarels bcopy((caddr_t)cp, 42236948Skarels mtod(opts, caddr_t) + opts->m_len, len); 42336948Skarels opts->m_len += len; 42436948Skarels } 42536948Skarels } 42636948Skarels if (opts->m_len % 4 != 0) { 42736948Skarels *(mtod(opts, caddr_t) + opts->m_len) = IPOPT_EOL; 42836948Skarels opts->m_len++; 42936948Skarels } 43036948Skarels #ifdef ICMPPRINTFS 43136948Skarels if (icmpprintfs) 43236948Skarels printf("%d\n", opts->m_len); 43336948Skarels #endif 43436817Skarels } 43536948Skarels /* 43636948Skarels * Now strip out original options by copying rest of first 43736948Skarels * mbuf's data back, and adjust the IP length. 43836948Skarels */ 43926034Skarels ip->ip_len -= optlen; 44036817Skarels ip->ip_hl = sizeof(struct ip) >> 2; 44136948Skarels m->m_len -= optlen; 442*40684Skarels if (m->m_flags & M_PKTHDR) 443*40684Skarels m->m_pkthdr.len -= optlen; 44436948Skarels optlen += sizeof(struct ip); 44536948Skarels bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1), 446*40684Skarels (unsigned)(m->m_len - sizeof(struct ip))); 44724811Skarels } 448*40684Skarels icmp_send(m, opts); 44926034Skarels if (opts) 45026383Skarels (void)m_free(opts); 4514785Swnj } 4524785Swnj 45324811Skarels struct in_ifaddr * 45424811Skarels ifptoia(ifp) 45524811Skarels struct ifnet *ifp; 45624811Skarels { 45724811Skarels register struct in_ifaddr *ia; 45824811Skarels 45924811Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 46024811Skarels if (ia->ia_ifp == ifp) 46124811Skarels return (ia); 46224811Skarels return ((struct in_ifaddr *)0); 46324811Skarels } 46424811Skarels 4654785Swnj /* 4666583Ssam * Send an icmp packet back to the ip level, 4676583Ssam * after supplying a checksum. 4684785Swnj */ 469*40684Skarels icmp_send(m, opts) 470*40684Skarels register struct mbuf *m; 47126034Skarels struct mbuf *opts; 4724785Swnj { 473*40684Skarels register struct ip *ip = mtod(m, struct ip *); 4749185Ssam register int hlen; 4756583Ssam register struct icmp *icp; 4766583Ssam 4779185Ssam hlen = ip->ip_hl << 2; 478*40684Skarels m->m_data += hlen; 47927063Skarels m->m_len -= hlen; 4806583Ssam icp = mtod(m, struct icmp *); 4816583Ssam icp->icmp_cksum = 0; 4826583Ssam icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 483*40684Skarels m->m_data -= hlen; 4846583Ssam m->m_len += hlen; 48515027Smckusick #ifdef ICMPPRINTFS 4866590Ssam if (icmpprintfs) 4876590Ssam printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src); 48815027Smckusick #endif 48926034Skarels (void) ip_output(m, opts, (struct route *)0, 0); 4904785Swnj } 4914785Swnj 4924907Swnj n_time 4934923Swnj iptime() 4944801Swnj { 49525893Skarels struct timeval atv; 4964967Swnj u_long t; 4974801Swnj 49825893Skarels microtime(&atv); 49925893Skarels t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; 5004907Swnj return (htonl(t)); 5014801Swnj } 502