xref: /csrg-svn/sys/netinet/ip_icmp.c (revision 8694)
1 /*	ip_icmp.c	4.22	82/10/20	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/mbuf.h"
6 #include "../h/protosw.h"
7 #include "../h/socket.h"
8 #include <time.h>
9 #include "../h/kernel.h"
10 
11 #include "../net/route.h"
12 #include "../netinet/in.h"
13 #include "../netinet/in_systm.h"
14 #include "../netinet/ip.h"
15 #include "../netinet/ip_icmp.h"
16 
17 /*
18  * ICMP routines: error generation, receive packet processing, and
19  * routines to turnaround packets back to the originator, and
20  * host table maintenance routines.
21  */
22 int	icmpprintfs = 0;
23 
24 /*
25  * Generate an error packet of type error
26  * in response to bad packet ip.
27  */
28 icmp_error(oip, type, code)
29 	struct ip *oip;
30 	int type, code;
31 {
32 	register unsigned oiplen = oip->ip_hl << 2;
33 	register struct icmp *icp;
34 	struct mbuf *m;
35 	struct ip *nip;
36 
37 	if (icmpprintfs)
38 		printf("icmp_error(%x, %d, %d)\n", oip, type, code);
39 	/*
40 	 * Make sure that the old IP packet had 8 bytes of data to return;
41 	 * if not, don't bother.  Also don't EVER error if the old
42 	 * packet protocol was ICMP.
43 	 */
44 	if (oip->ip_len < 8 || oip->ip_p == IPPROTO_ICMP)
45 		goto free;
46 
47 	/*
48 	 * First, formulate icmp message
49 	 */
50 	m = m_get(M_DONTWAIT);
51 	if (m == 0)
52 		goto free;
53 	m->m_len = oiplen + 8 + ICMP_MINLEN;
54 	m->m_off = MMAXOFF - m->m_len;
55 	icp = mtod(m, struct icmp *);
56 	icp->icmp_type = type;
57 	icp->icmp_void = 0;
58 	if (type == ICMP_PARAMPROB) {
59 		icp->icmp_pptr = code;
60 		code = 0;
61 	}
62 	icp->icmp_code = code;
63 	bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8);
64 	nip = &icp->icmp_ip;
65 	nip->ip_len += oiplen;
66 #if vax || pdp11 || ns16032
67 	nip->ip_len = htons((u_short)nip->ip_len);
68 #endif
69 
70 	/*
71 	 * Now, copy old ip header in front of icmp
72 	 * message.  This allows us to reuse any source
73 	 * routing info present.
74 	 */
75 	m->m_off -= oiplen;
76 	nip = mtod(m, struct ip *);
77 	bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
78 	nip->ip_len = m->m_len + oiplen;
79 	nip->ip_p = IPPROTO_ICMP;
80 	/* icmp_send adds ip header to m_off and m_len, so we deduct here */
81 	m->m_off += oiplen;
82 	icmp_reflect(nip);
83 
84 free:
85 	m_freem(dtom(oip));
86 }
87 
88 static char icmpmap[] = {
89 	-1,		 -1,		-1,
90 	PRC_UNREACH_NET, PRC_QUENCH, 	PRC_REDIRECT_NET,
91 	-1,		 -1,		-1,
92 	-1,		 -1,		PRC_TIMXCEED_INTRANS,
93 	PRC_PARAMPROB,	 -1,		-1,
94 	-1,		 -1
95 };
96 
97 static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
98 static struct sockaddr_in icmpsrc = { AF_INET };
99 static struct sockaddr_in icmpdst = { AF_INET };
100 
101 /*
102  * Process a received ICMP message.
103  */
104 icmp_input(m)
105 	struct mbuf *m;
106 {
107 	register struct icmp *icp;
108 	register struct ip *ip = mtod(m, struct ip *);
109 	int icmplen = ip->ip_len, hlen = ip->ip_hl << 2, i, (*ctlfunc)();
110 	extern u_char ip_protox[];
111 
112 	/*
113 	 * Locate icmp structure in mbuf, and check
114 	 * that not corrupted and of at least minimum length.
115 	 */
116 	if (icmpprintfs)
117 		printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
118 	if (icmplen < ICMP_MINLEN)
119 		goto free;
120 	m->m_len -= hlen;
121 	m->m_off += hlen;
122 	/* need routine to make sure header is in this mbuf here */
123 	icp = mtod(m, struct icmp *);
124 	i = icp->icmp_cksum;
125 	icp->icmp_cksum = 0;
126 	if (i != in_cksum(m, icmplen)) {
127 		printf("icmp: cksum %x\n", i);
128 		goto free;
129 	}
130 
131 	/*
132 	 * Message type specific processing.
133 	 */
134 	if (icmpprintfs)
135 		printf("icmp_input, type %d code %d\n", icp->icmp_type,
136 			icp->icmp_code);
137 	switch (i = icp->icmp_type) {
138 
139 	case ICMP_UNREACH:
140 	case ICMP_TIMXCEED:
141 	case ICMP_PARAMPROB:
142 	case ICMP_REDIRECT:
143 	case ICMP_SOURCEQUENCH:
144 		/*
145 		 * Problem with previous datagram; advise
146 		 * higher level routines.
147 		 */
148 #if vax || pdp11 || ns16032
149 		icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len);
150 #endif
151 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
152 			goto free;
153 		if (icmpprintfs)
154 			printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
155 		if (ctlfunc = protosw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
156 			(*ctlfunc)(icmpmap[i] + icp->icmp_code, (caddr_t)icp);
157 		goto free;
158 
159 	case ICMP_ECHO:
160 		icp->icmp_type = ICMP_ECHOREPLY;
161 		goto reflect;
162 
163 	case ICMP_TSTAMP:
164 		if (icmplen < ICMP_TSLEN)
165 			goto free;
166 		icp->icmp_type = ICMP_TSTAMPREPLY;
167 		icp->icmp_rtime = iptime();
168 		icp->icmp_ttime = icp->icmp_rtime;	/* bogus, do later! */
169 		goto reflect;
170 
171 	case ICMP_IREQ:
172 		/* fill in source address zero fields! */
173 		goto reflect;
174 
175 	case ICMP_ECHOREPLY:
176 	case ICMP_TSTAMPREPLY:
177 	case ICMP_IREQREPLY:
178 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
179 			goto free;
180 		icmpsrc.sin_addr = ip->ip_src;
181 		icmpdst.sin_addr = ip->ip_dst;
182 		raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc,
183 		  (struct sockaddr *)&icmpdst);
184 		goto free;
185 
186 	default:
187 		goto free;
188 	}
189 reflect:
190 	icmp_reflect(ip);
191 free:
192 	m_freem(dtom(ip));
193 }
194 
195 /*
196  * Reflect the ip packet back to the source
197  * TODO: rearrange ip source routing options.
198  */
199 icmp_reflect(ip)
200 	struct ip *ip;
201 {
202 	struct in_addr t;
203 
204 	t = ip->ip_dst;
205 	ip->ip_dst = ip->ip_src;
206 	ip->ip_src = t;
207 	icmp_send(ip);
208 }
209 
210 int	generateicmpmsgs = 1;
211 
212 /*
213  * Send an icmp packet back to the ip level,
214  * after supplying a checksum.
215  */
216 icmp_send(ip)
217 	struct ip *ip;
218 {
219 	register int hlen = ip->ip_hl << 2;
220 	register struct icmp *icp;
221 	register struct mbuf *m = dtom(ip);
222 
223 	if (!generateicmpmsgs)
224 		return;
225 	icp = mtod(m, struct icmp *);
226 	icp->icmp_cksum = 0;
227 	icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
228 	m->m_off -= hlen;
229 	m->m_len += hlen;
230 	if (icmpprintfs)
231 		printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
232 	(void) ip_output(m, (struct mbuf *)0, (struct route *)0, 0);
233 }
234 
235 n_time
236 iptime()
237 {
238 	int s = spl6();
239 	u_long t;
240 
241 	t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000;
242 	splx(s);
243 	return (htonl(t));
244 }
245