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