|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1982, 1986, 1988, 1993
28: * The Regents of the University of California. All rights reserved.
29: *
30: * Redistribution and use in source and binary forms, with or without
31: * modification, are permitted provided that the following conditions
32: * are met:
33: * 1. Redistributions of source code must retain the above copyright
34: * notice, this list of conditions and the following disclaimer.
35: * 2. Redistributions in binary form must reproduce the above copyright
36: * notice, this list of conditions and the following disclaimer in the
37: * documentation and/or other materials provided with the distribution.
38: * 3. All advertising materials mentioning features or use of this software
39: * must display the following acknowledgement:
40: * This product includes software developed by the University of
41: * California, Berkeley and its contributors.
42: * 4. Neither the name of the University nor the names of its contributors
43: * may be used to endorse or promote products derived from this software
44: * without specific prior written permission.
45: *
46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56: * SUCH DAMAGE.
57: *
58: * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94
59: */
60:
61: #import <sys/param.h>
62: #import <sys/systm.h>
63: #import <sys/malloc.h>
64: #import <sys/mbuf.h>
65: #import <sys/protosw.h>
66: #import <sys/socket.h>
67: #import <sys/time.h>
68: #import <sys/kernel.h>
69:
70: #import <net/if.h>
71: #import <net/route.h>
72:
73: #import <netinet/in.h>
74: #import <netinet/in_systm.h>
75: #import <netinet/in_var.h>
76: #import <netinet/ip.h>
77: #import <netinet/ip_var.h>
78: #import <netinet/ip_icmp.h>
79: #import <netinet/icmp_var.h>
80:
81: /*
82: * ICMP routines: error generation, receive packet processing, and
83: * routines to turnaround packets back to the originator, and
84: * host table maintenance routines.
85: */
86:
87: int icmpmaskrepl = 0;
88: int icmpbmcastecho = 0;
89: #ifdef ICMPPRINTFS
90: int icmpprintfs = 0;
91: #endif
92:
93: extern struct protosw inetsw[];
94:
95: #if NeXT
96: static struct in_ifaddr *
97: ifptoia(ifp)
98: struct ifnet *ifp;
99: {
100: register struct in_ifaddr *ia;
101:
102: for (ia = in_ifaddr; ia; ia = ia->ia_next)
103: if (ia->ia_ifp == ifp)
104: return (ia);
105: return ((struct in_ifaddr *)0);
106: }
107: #endif NeXT
108:
109: /*
110: * Generate an error packet of type error
111: * in response to bad packet ip.
112: */
113: void
114: icmp_error(n, type, code, dest, destifp)
115: struct mbuf *n;
116: int type, code;
117: n_long dest;
118: struct ifnet *destifp;
119: {
120: register struct ip *oip = mtod(n, struct ip *), *nip;
121: register unsigned oiplen = oip->ip_hl << 2;
122: register struct icmp *icp;
123: register struct mbuf *m;
124: unsigned icmplen;
125:
126: #ifdef ICMPPRINTFS
127: if (icmpprintfs)
128: printf("icmp_error(%x, %d, %d)\n", oip, type, code);
129: #endif
130: if (type != ICMP_REDIRECT)
131: icmpstat.icps_error++;
132: /*
133: * Don't send error if not the first fragment of message.
134: * Don't error if the old packet protocol was ICMP
135: * error message, only known informational types.
136: */
137: if (oip->ip_off &~ (IP_MF|IP_DF))
138: goto freeit;
139: if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
140: n->m_len >= oiplen + ICMP_MINLEN &&
141: !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
142: icmpstat.icps_oldicmp++;
143: goto freeit;
144: }
145: /* Don't send error in response to a multicast or broadcast packet */
146: if (n->m_flags & (M_BCAST|M_MCAST))
147: goto freeit;
148: /*
149: * First, formulate icmp message
150: */
151: m = m_gethdr(M_DONTWAIT, MT_HEADER);
152: if (m == NULL)
153: goto freeit;
154: icmplen = oiplen + min(8, oip->ip_len);
155: m->m_len = icmplen + ICMP_MINLEN;
156: MH_ALIGN(m, m->m_len);
157: icp = mtod(m, struct icmp *);
158: if ((u_int)type > ICMP_MAXTYPE)
159: panic("icmp_error");
160: icmpstat.icps_outhist[type]++;
161: icp->icmp_type = type;
162: if (type == ICMP_REDIRECT)
163: icp->icmp_gwaddr.s_addr = dest;
164: else {
165: icp->icmp_void = 0;
166: /*
167: * The following assignments assume an overlay with the
168: * zeroed icmp_void field.
169: */
170: if (type == ICMP_PARAMPROB) {
171: icp->icmp_pptr = code;
172: code = 0;
173: } else if (type == ICMP_UNREACH &&
174: code == ICMP_UNREACH_NEEDFRAG && destifp) {
175: icp->icmp_nextmtu = htons(destifp->if_mtu);
176: }
177: }
178:
179: icp->icmp_code = code;
180: bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
181: nip = &icp->icmp_ip;
182: nip->ip_len = htons((u_short)(nip->ip_len + oiplen));
183:
184: /*
185: * Now, copy old ip header (without options)
186: * in front of icmp message.
187: */
188: if (m->m_data - sizeof(struct ip) < m->m_pktdat)
189: panic("icmp len");
190: m->m_data -= sizeof(struct ip);
191: m->m_len += sizeof(struct ip);
192: m->m_pkthdr.len = m->m_len;
193: m->m_pkthdr.rcvif = n->m_pkthdr.rcvif;
194: nip = mtod(m, struct ip *);
195: bcopy((caddr_t)oip, (caddr_t)nip, sizeof(struct ip));
196: nip->ip_len = m->m_len;
197: nip->ip_hl = sizeof(struct ip) >> 2;
198: nip->ip_p = IPPROTO_ICMP;
199: nip->ip_tos = 0;
200: icmp_reflect(m);
201:
202: freeit:
203: m_freem(n);
204: }
205:
206: static struct sockaddr_in icmpsrc = { sizeof (struct sockaddr_in), AF_INET };
207: static struct sockaddr_in icmpdst = { sizeof (struct sockaddr_in), AF_INET };
208: static struct sockaddr_in icmpgw = { sizeof (struct sockaddr_in), AF_INET };
209: struct sockaddr_in icmpmask = { 8, 0 };
210:
211: /*
212: * Process a received ICMP message.
213: */
214: void
215: icmp_input(m, hlen)
216: register struct mbuf *m;
217: int hlen;
218: {
219: register struct icmp *icp;
220: register struct ip *ip = mtod(m, struct ip *);
221: unsigned int icmplen = (unsigned short)ip->ip_len;
222: register int i;
223: struct in_ifaddr *ia;
224: void (*ctlfunc) __P((int, struct sockaddr *, struct ip *));
225: int code;
226: extern u_char ip_protox[];
227:
228: /*
229: * Locate icmp structure in mbuf, and check
230: * that not corrupted and of at least minimum length.
231: */
232: #ifdef ICMPPRINTFS
233: if (icmpprintfs)
234: printf("icmp_input from %x to %x, len %d\n",
235: ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr),
236: icmplen);
237: #endif
238: if (icmplen < ICMP_MINLEN) {
239: icmpstat.icps_tooshort++;
240: goto freeit;
241: }
242: i = hlen + min(icmplen, ICMP_ADVLENMIN);
243: if (m->m_len < i && (m = m_pullup(m, i)) == 0) {
244: icmpstat.icps_tooshort++;
245: return;
246: }
247: ip = mtod(m, struct ip *);
248: m->m_len -= hlen;
249: m->m_data += hlen;
250: icp = mtod(m, struct icmp *);
251: if (in_cksum(m, icmplen)) {
252: icmpstat.icps_checksum++;
253: goto freeit;
254: }
255: m->m_len += hlen;
256: m->m_data -= hlen;
257:
258: #ifdef ICMPPRINTFS
259: /*
260: * Message type specific processing.
261: */
262: if (icmpprintfs)
263: printf("icmp_input, type %d code %d\n", icp->icmp_type,
264: icp->icmp_code);
265: #endif
266: if (icp->icmp_type > ICMP_MAXTYPE)
267: goto raw;
268: icmpstat.icps_inhist[icp->icmp_type]++;
269: code = icp->icmp_code;
270: switch (icp->icmp_type) {
271:
272: case ICMP_UNREACH:
273: switch (code) {
274: case ICMP_UNREACH_NET:
275: case ICMP_UNREACH_HOST:
276: case ICMP_UNREACH_PROTOCOL:
277: case ICMP_UNREACH_PORT:
278: case ICMP_UNREACH_SRCFAIL:
279: code += PRC_UNREACH_NET;
280: break;
281:
282: case ICMP_UNREACH_NEEDFRAG:
283: code = PRC_MSGSIZE;
284: break;
285:
286: case ICMP_UNREACH_NET_UNKNOWN:
287: case ICMP_UNREACH_NET_PROHIB:
288: case ICMP_UNREACH_TOSNET:
289: code = PRC_UNREACH_NET;
290: break;
291:
292: case ICMP_UNREACH_HOST_UNKNOWN:
293: case ICMP_UNREACH_ISOLATED:
294: case ICMP_UNREACH_HOST_PROHIB:
295: case ICMP_UNREACH_TOSHOST:
296: code = PRC_UNREACH_HOST;
297: break;
298:
299: default:
300: goto badcode;
301: }
302: goto deliver;
303:
304: case ICMP_TIMXCEED:
305: if (code > 1)
306: goto badcode;
307: code += PRC_TIMXCEED_INTRANS;
308: goto deliver;
309:
310: case ICMP_PARAMPROB:
311: if (code > 1)
312: goto badcode;
313: code = PRC_PARAMPROB;
314: goto deliver;
315:
316: case ICMP_SOURCEQUENCH:
317: if (code)
318: goto badcode;
319: code = PRC_QUENCH;
320: deliver:
321: /*
322: * Problem with datagram; advise higher level routines.
323: */
324: if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
325: icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
326: icmpstat.icps_badlen++;
327: goto freeit;
328: }
329: NTOHS(icp->icmp_ip.ip_len);
330: #ifdef ICMPPRINTFS
331: if (icmpprintfs)
332: printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
333: #endif
334: icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
335: if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
336: (*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
337: &icp->icmp_ip);
338: break;
339:
340: badcode:
341: icmpstat.icps_badcode++;
342: break;
343:
344: case ICMP_ECHO:
345: if (!icmpbmcastecho
346: && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
347: break;
348: }
349: icp->icmp_type = ICMP_ECHOREPLY;
350: goto reflect;
351:
352: case ICMP_TSTAMP:
353: if (!icmpbmcastecho
354: && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
355: break;
356: }
357: if (icmplen < ICMP_TSLEN) {
358: icmpstat.icps_badlen++;
359: break;
360: }
361: icp->icmp_type = ICMP_TSTAMPREPLY;
362: icp->icmp_rtime = iptime();
363: icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */
364: goto reflect;
365:
366: case ICMP_MASKREQ:
367: #define satosin(sa) ((struct sockaddr_in *)(sa))
368: if (icmpmaskrepl == 0)
369: break;
370: /*
371: * We are not able to respond with all ones broadcast
372: * unless we receive it over a point-to-point interface.
373: */
374: if (icmplen < ICMP_MASKLEN)
375: break;
376: switch (ip->ip_dst.s_addr) {
377:
378: case INADDR_BROADCAST:
379: case INADDR_ANY:
380: icmpdst.sin_addr = ip->ip_src;
381: break;
382:
383: default:
384: icmpdst.sin_addr = ip->ip_dst;
385: }
386: ia = (struct in_ifaddr *)ifaof_ifpforaddr(
387: (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
388: if (ia == 0)
389: break;
390: icp->icmp_type = ICMP_MASKREPLY;
391: icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
392: if (ip->ip_src.s_addr == 0) {
393: if (ia->ia_ifp->if_flags & IFF_BROADCAST)
394: ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
395: else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
396: ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
397: }
398: reflect:
399: ip->ip_len += hlen; /* since ip_input deducts this */
400: icmpstat.icps_reflect++;
401: icmpstat.icps_outhist[icp->icmp_type]++;
402: icmp_reflect(m);
403: return;
404:
405: case ICMP_REDIRECT:
406: if (code > 3)
407: goto badcode;
408: if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp) ||
409: icp->icmp_ip.ip_hl < (sizeof(struct ip) >> 2)) {
410: icmpstat.icps_badlen++;
411: break;
412: }
413: /*
414: * Short circuit routing redirects to force
415: * immediate change in the kernel's routing
416: * tables. The message is also handed to anyone
417: * listening on a raw socket (e.g. the routing
418: * daemon for use in updating its tables).
419: */
420: icmpgw.sin_addr = ip->ip_src;
421: icmpdst.sin_addr = icp->icmp_gwaddr;
422: #ifdef ICMPPRINTFS
423: if (icmpprintfs)
424: printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst,
425: icp->icmp_gwaddr);
426: #endif
427: icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
428: rtredirect((struct sockaddr *)&icmpsrc,
429: (struct sockaddr *)&icmpdst,
430: (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
431: (struct sockaddr *)&icmpgw, (struct rtentry **)0);
432: pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc);
433: break;
434: #if NeXT
435: case ICMP_MASKREPLY:
436: {
437: struct ifnet *ifp = m->m_pkthdr.rcvif;
438: u_long mask;
439:
440: /*
441: * Conditions for accepting a new netmask have changed for NEXTSTEP 3.2
442: * to meet RFC1122 requirements. Now we accept only one NETMASK_REPLY
443: * packet, accept either directed or broadcast packets, and check for
444: * reasonable netmask values in the packet. We maintain the previous
445: * condition that we reconfigure the
446: * netmask and broadcast address only if the provided subnetmask is
447: * larger than the current one.
448: */
449: if ((ia = ifptoia(ifp)) && (ifp->if_eflags & IFEF_AWAITING_NETMASK)) {
450: /* Check for reasonable mask */
451: /* i.e. highest-order byte = 0xff and not all ones */
452: mask = ntohl(icp->icmp_mask);
453: if ((mask == 0xffffffff) || ( (mask & 0xff000000) != 0xff000000))
454: break;
455:
456: ifp->if_eflags &= ~(IFEF_AWAITING_NETMASK);
457: if (!(ifp->if_flags & IFF_LOOPBACK)
458: && ((ia->ia_subnetmask|mask) != ia->ia_subnetmask)) {
459: int err;
460: ia->ia_subnetmask |= mask;
461: ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
462: if (err = in_ifinit(ifp, ia, (struct sockaddr_in *)
463: &ia->ia_addr, 1)) {
464: printf("icmp_input: in_ifinit failed, error = %d\n",
465: err);
466: }
467: else {
468: printf("%s%d: setting netmask to %x, received from %s\n",
469: ifp->if_name, ifp->if_unit,
470: mask, inet_ntoa(&ip->ip_src.s_addr));
471: wakeup(&ia->ia_subnetmask);
472: }
473: }
474: }
475: }
476: /* Fall through */
477: #endif NeXT
478:
479:
480: /*
481: * No kernel processing for the following;
482: * just fall through to send to raw listener.
483: */
484: case ICMP_ECHOREPLY:
485: case ICMP_ROUTERADVERT:
486: case ICMP_ROUTERSOLICIT:
487: case ICMP_TSTAMPREPLY:
488: case ICMP_IREQREPLY:
489: default:
490: break;
491: }
492:
493: raw:
494: rip_input(m);
495: return;
496:
497: freeit:
498: m_freem(m);
499: }
500:
501: /*
502: * Reflect the ip packet back to the source
503: */
504: void
505: icmp_reflect(m)
506: struct mbuf *m;
507: {
508: register struct ip *ip = mtod(m, struct ip *);
509: register struct in_ifaddr *ia;
510: struct in_addr t;
511: struct mbuf *opts = 0, *ip_srcroute();
512: int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
513:
514: if (!in_canforward(ip->ip_src) &&
515: ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) !=
516: (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))) {
517: m_freem(m); /* Bad return address */
518: goto done; /* Ip_output() will check for broadcast */
519: }
520: t = ip->ip_dst;
521: ip->ip_dst = ip->ip_src;
522: /*
523: * If the incoming packet was addressed directly to us,
524: * use dst as the src for the reply. Otherwise (broadcast
525: * or anonymous), use the address which corresponds
526: * to the incoming interface.
527: */
528: for (ia = in_ifaddr; ia; ia = ia->ia_next) {
529: if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
530: break;
531: if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
532: t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
533: break;
534: }
535: icmpdst.sin_addr = t;
536: if (ia == (struct in_ifaddr *)0)
537: ia = (struct in_ifaddr *)ifaof_ifpforaddr(
538: (struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
539: /*
540: * The following happens if the packet was not addressed to us,
541: * and was received on an interface with no IP address.
542: */
543: if (ia == (struct in_ifaddr *)0)
544: ia = in_ifaddr;
545: t = IA_SIN(ia)->sin_addr;
546: ip->ip_src = t;
547: ip->ip_ttl = MAXTTL;
548:
549: if (optlen > 0) {
550: register u_char *cp;
551: int opt, cnt;
552: u_int len;
553:
554: /*
555: * Retrieve any source routing from the incoming packet;
556: * add on any record-route or timestamp options.
557: */
558: cp = (u_char *) (ip + 1);
559: if ((opts = ip_srcroute()) == 0 &&
560: (opts = m_gethdr(M_DONTWAIT, MT_HEADER))) {
561: opts->m_len = sizeof(struct in_addr);
562: mtod(opts, struct in_addr *)->s_addr = 0;
563: }
564: if (opts) {
565: #ifdef ICMPPRINTFS
566: if (icmpprintfs)
567: printf("icmp_reflect optlen %d rt %d => ",
568: optlen, opts->m_len);
569: #endif
570: for (cnt = optlen; cnt > 0; cnt -= len, cp += len) {
571: opt = cp[IPOPT_OPTVAL];
572: if (opt == IPOPT_EOL)
573: break;
574: if (opt == IPOPT_NOP)
575: len = 1;
576: else {
577: len = cp[IPOPT_OLEN];
578: if (len <= 0 || len > cnt)
579: break;
580: }
581: /*
582: * Should check for overflow, but it "can't happen"
583: */
584: if (opt == IPOPT_RR || opt == IPOPT_TS ||
585: opt == IPOPT_SECURITY) {
586: bcopy((caddr_t)cp,
587: mtod(opts, caddr_t) + opts->m_len, len);
588: opts->m_len += len;
589: }
590: }
591: /* Terminate & pad, if necessary */
592: if (cnt = opts->m_len % 4) {
593: for (; cnt < 4; cnt++) {
594: *(mtod(opts, caddr_t) + opts->m_len) =
595: IPOPT_EOL;
596: opts->m_len++;
597: }
598: }
599: #ifdef ICMPPRINTFS
600: if (icmpprintfs)
601: printf("%d\n", opts->m_len);
602: #endif
603: }
604: /*
605: * Now strip out original options by copying rest of first
606: * mbuf's data back, and adjust the IP length.
607: */
608: ip->ip_len -= optlen;
609: ip->ip_hl = sizeof(struct ip) >> 2;
610: m->m_len -= optlen;
611: if (m->m_flags & M_PKTHDR)
612: m->m_pkthdr.len -= optlen;
613: optlen += sizeof(struct ip);
614: bcopy((caddr_t)ip + optlen, (caddr_t)(ip + 1),
615: (unsigned)(m->m_len - sizeof(struct ip)));
616: }
617: m->m_flags &= ~(M_BCAST|M_MCAST);
618: icmp_send(m, opts);
619: done:
620: if (opts)
621: (void)m_free(opts);
622: }
623:
624: /*
625: * Send an icmp packet back to the ip level,
626: * after supplying a checksum.
627: */
628: void
629: icmp_send(m, opts)
630: register struct mbuf *m;
631: struct mbuf *opts;
632: {
633: register struct ip *ip = mtod(m, struct ip *);
634: register unsigned int hlen;
635: register struct icmp *icp;
636: unsigned int ulen;
637:
638: hlen = (unsigned short)ip->ip_hl << 2;
639: m->m_data += hlen;
640: m->m_len -= hlen;
641: icp = mtod(m, struct icmp *);
642: icp->icmp_cksum = 0;
643: ulen = (unsigned short)ip->ip_len - hlen;
644: icp->icmp_cksum = in_cksum(m, ulen);
645: m->m_data -= hlen;
646: m->m_len += hlen;
647: #ifdef ICMPPRINTFS
648: if (icmpprintfs)
649: printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
650: #endif
651: (void) ip_output(m, opts, NULL, 0, NULL);
652: }
653:
654: n_time
655: iptime()
656: {
657: struct timeval atv;
658: u_long t;
659:
660: microtime(&atv);
661: t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000;
662: return (htonl(t));
663: }
664:
665: int
666: icmp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
667: int *name;
668: u_int namelen;
669: void *oldp;
670: size_t *oldlenp;
671: void *newp;
672: size_t newlen;
673: {
674:
675: /* All sysctl names at this level are terminal. */
676: if (namelen != 1)
677: return (ENOTDIR);
678:
679: switch (name[0]) {
680: case ICMPCTL_MASKREPL:
681: return (sysctl_int(oldp, oldlenp, newp, newlen, &icmpmaskrepl));
682: default:
683: return (ENOPROTOOPT);
684: }
685: /* NOTREACHED */
686: }
687:
688: #if NeXT
689: /*
690: * Routine: icmp_sendMaskPacket
691: * Function:
692: *
693: * Former routine icmp_maskrequest() has been renamed to icmp_sendMaskPacket()
694: * and modified to send either an ICMP_MASKREQ packet (as before) or a broadcast
695: * ICMP_MASKREPLY packet, as required by RFC1122 when an interface comes up.
696: *
697: * The only valid values for parameter icmp_msg_type are ICMP_MASKREQ and ICMP_MASKREPLY.
698: */
699: icmp_sendMaskPacket(ifp, icmp_msg_type, retry_delay)
700: struct ifnet *ifp;
701: u_char icmp_msg_type;
702: int retry_delay; /* Seconds to delay before transmitting */
703: {
704: struct mbuf *m = NULL;
705: struct sockaddr_in *sin;
706: struct sockaddr_in lsin;
707: struct ip *ip;
708: struct icmp *icp;
709: struct in_ifaddr *ifa;
710: register int error;
711: extern int wakeup();
712: caddr_t m_offset;
713:
714: if ((ifp->if_flags & IFF_UP) != IFF_UP) {
715: return(0);
716: }
717:
718: /* Don't do this on our loopback interface */
719: if (ifp->if_flags & IFF_LOOPBACK) {
720: return(0);
721: }
722:
723: if ((ifa = ifptoia(ifp)) == NULL) {
724: error = ENETUNREACH;
725: goto errout;
726: }
727:
728: /* Build a packet */
729: MGETHDR(m, M_WAIT, MT_DATA);
730: if (m == NULL) {
731: error = ENOBUFS;
732: goto errout;
733: }
734: m->m_pkthdr.rcvif = ifp;
735: m->m_pkthdr.len = 12 + sizeof(struct ip);/* Size of packet we're sending */
736: m->m_len = m->m_pkthdr.len;
737: m->m_flags |= M_BCAST;
738: bzero(mtod(m, caddr_t), m->m_len);
739: m->m_len -= sizeof(struct ip);
740: m->m_data += sizeof(struct ip);
741: icp = mtod(m, struct icmp *);
742: if (icmp_msg_type == ICMP_MASKREPLY) {
743: icp->icmp_type = ICMP_MASKREPLY;
744: if ((icp->icmp_mask = htonl(ifa->ia_subnetmask)) == 0) {
745: error = EINVAL;
746: goto errout;
747: }
748: }
749: else {
750: icp->icmp_type = ICMP_MASKREQ;
751: }
752: icp->icmp_code = 0;
753: icp->icmp_cksum = 0;
754: icp->icmp_void = 0;
755: icp->icmp_cksum = in_cksum(m, 12);
756:
757: m->m_data -= sizeof(struct ip);
758: m->m_len += sizeof(struct ip);
759: ip = mtod(m, struct ip *);
760:
761: ip->ip_v = IPVERSION;
762: ip->ip_hl = sizeof(struct ip) >> 2;
763: ip->ip_id = htons(ip_id++);
764: ip->ip_ttl = MAXTTL;
765: ip->ip_p = IPPROTO_ICMP;
766:
767: sin = (struct sockaddr_in *)(&ifa->ia_addr);
768: ip->ip_src.s_addr = sin->sin_addr.s_addr;
769: ip->ip_dst.s_addr = INADDR_BROADCAST;
770: ip->ip_len = htons(sizeof (struct ip) + 12);
771: ip->ip_sum=0;
772: ip->ip_sum = in_cksum(m, sizeof(struct ip));
773:
774: lsin.sin_family = AF_INET;
775: lsin.sin_port = 0;
776: lsin.sin_addr.s_addr = INADDR_BROADCAST;
777:
778: /* Send the packet */
779: if (retry_delay > 0) {
780: timeout(wakeup, (caddr_t)&ifa->ia_subnetmask, retry_delay * hz);
781: sleep((caddr_t)&ifa->ia_subnetmask, PZERO);
782: }
783: error = (*ifp->if_output)(ifp, m, (struct sockaddr *)&lsin, (struct rtentry *)0);
784: m = NULL;
785:
786: if (icmp_msg_type == ICMP_MASKREQ) {
787: /* Now wait at least one second for any responses */
788: timeout(wakeup, (caddr_t)&ifa->ia_subnetmask, 1 * hz);
789: sleep((caddr_t)&ifa->ia_subnetmask, PZERO);
790: }
791: errout:
792: if (m) {
793: m_freem(m);
794: }
795: return(error);
796: }
797: #endif NeXT
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.