get resid right even if >32767
[unix-history] / usr / src / sys / netinet / ip_icmp.c
CommitLineData
b11be056 1/* ip_icmp.c 6.1 83/07/29 */
81a36a8d
BJ
2
3#include "../h/param.h"
2b4b57cd 4#include "../h/systm.h"
81a36a8d 5#include "../h/mbuf.h"
cdad2eb1 6#include "../h/protosw.h"
72e4f44e 7#include "../h/socket.h"
f4d55810 8#include "../h/time.h"
6e7edb25
BJ
9#include "../h/kernel.h"
10
11#include "../net/route.h"
f4d55810 12
fcfe450e
BJ
13#include "../netinet/in.h"
14#include "../netinet/in_systm.h"
15#include "../netinet/ip.h"
16#include "../netinet/ip_icmp.h"
7b66c1fd 17#include "../netinet/icmp_var.h"
81a36a8d
BJ
18
19/*
20 * ICMP routines: error generation, receive packet processing, and
21 * routines to turnaround packets back to the originator, and
22 * host table maintenance routines.
23 */
67387c9c 24int icmpprintfs = 0;
81a36a8d
BJ
25
26/*
72e4f44e
SL
27 * Generate an error packet of type error
28 * in response to bad packet ip.
81a36a8d
BJ
29 */
30icmp_error(oip, type, code)
31 struct ip *oip;
755d8841 32 int type, code;
81a36a8d 33{
72e4f44e
SL
34 register unsigned oiplen = oip->ip_hl << 2;
35 register struct icmp *icp;
81a36a8d
BJ
36 struct mbuf *m;
37 struct ip *nip;
38
39674d5f
SL
39 if (icmpprintfs)
40 printf("icmp_error(%x, %d, %d)\n", oip, type, code);
7b66c1fd 41 icmpstat.icps_error++;
81a36a8d
BJ
42 /*
43 * Make sure that the old IP packet had 8 bytes of data to return;
44 * if not, don't bother. Also don't EVER error if the old
45 * packet protocol was ICMP.
46 */
7b66c1fd
SL
47 if (oip->ip_len < 8) {
48 icmpstat.icps_oldshort++;
81a36a8d 49 goto free;
7b66c1fd
SL
50 }
51 if (oip->ip_p == IPPROTO_ICMP) {
52 icmpstat.icps_oldicmp++;
53 goto free;
54 }
81a36a8d
BJ
55
56 /*
72e4f44e 57 * First, formulate icmp message
81a36a8d 58 */
cce93e4b 59 m = m_get(M_DONTWAIT, MT_HEADER);
7b66c1fd 60 if (m == NULL)
81a36a8d 61 goto free;
72e4f44e
SL
62 m->m_len = oiplen + 8 + ICMP_MINLEN;
63 m->m_off = MMAXOFF - m->m_len;
64 icp = mtod(m, struct icmp *);
755d8841 65 if ((u_int)type > ICMP_IREQREPLY)
7b66c1fd
SL
66 panic("icmp_error");
67 icmpstat.icps_outhist[type]++;
81a36a8d 68 icp->icmp_type = type;
72e4f44e 69 icp->icmp_void = 0;
81a36a8d 70 if (type == ICMP_PARAMPROB) {
81a36a8d 71 icp->icmp_pptr = code;
72e4f44e
SL
72 code = 0;
73 }
74 icp->icmp_code = code;
d52566dd 75 bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8);
39674d5f
SL
76 nip = &icp->icmp_ip;
77 nip->ip_len += oiplen;
39674d5f 78 nip->ip_len = htons((u_short)nip->ip_len);
81a36a8d
BJ
79
80 /*
72e4f44e
SL
81 * Now, copy old ip header in front of icmp
82 * message. This allows us to reuse any source
83 * routing info present.
81a36a8d 84 */
72e4f44e
SL
85 m->m_off -= oiplen;
86 nip = mtod(m, struct ip *);
87 bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
88 nip->ip_len = m->m_len + oiplen;
89 nip->ip_p = IPPROTO_ICMP;
90 /* icmp_send adds ip header to m_off and m_len, so we deduct here */
91 m->m_off += oiplen;
d52566dd 92 icmp_reflect(nip);
81a36a8d 93
def04636 94free:
81a36a8d
BJ
95 m_freem(dtom(oip));
96}
97
72e4f44e
SL
98static char icmpmap[] = {
99 -1, -1, -1,
100 PRC_UNREACH_NET, PRC_QUENCH, PRC_REDIRECT_NET,
101 -1, -1, -1,
102 -1, -1, PRC_TIMXCEED_INTRANS,
103 PRC_PARAMPROB, -1, -1,
104 -1, -1
105};
106
107static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
108static struct sockaddr_in icmpsrc = { AF_INET };
109static struct sockaddr_in icmpdst = { AF_INET };
110
81a36a8d 111/*
d52566dd 112 * Process a received ICMP message.
81a36a8d
BJ
113 */
114icmp_input(m)
115 struct mbuf *m;
116{
81a36a8d 117 register struct icmp *icp;
d52566dd 118 register struct ip *ip = mtod(m, struct ip *);
af8f6a21 119 int icmplen = ip->ip_len, hlen = ip->ip_hl << 2;
7b66c1fd 120 int (*ctlfunc)(), code, i;
b454c3ea 121 extern u_char ip_protox[];
81a36a8d
BJ
122
123 /*
124 * Locate icmp structure in mbuf, and check
125 * that not corrupted and of at least minimum length.
126 */
39674d5f
SL
127 if (icmpprintfs)
128 printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen);
7b66c1fd
SL
129 if (icmplen < ICMP_MINLEN) {
130 icmpstat.icps_tooshort++;
72e4f44e 131 goto free;
7b66c1fd 132 }
81a36a8d
BJ
133 m->m_len -= hlen;
134 m->m_off += hlen;
135 /* need routine to make sure header is in this mbuf here */
72e4f44e 136 icp = mtod(m, struct icmp *);
81a36a8d
BJ
137 i = icp->icmp_cksum;
138 icp->icmp_cksum = 0;
72e4f44e 139 if (i != in_cksum(m, icmplen)) {
7b66c1fd 140 icmpstat.icps_checksum++;
d52566dd 141 goto free;
72e4f44e 142 }
81a36a8d
BJ
143
144 /*
145 * Message type specific processing.
146 */
39674d5f
SL
147 if (icmpprintfs)
148 printf("icmp_input, type %d code %d\n", icp->icmp_type,
149 icp->icmp_code);
7b66c1fd
SL
150 if (icp->icmp_type > ICMP_IREQREPLY)
151 goto free;
152 icmpstat.icps_inhist[icp->icmp_type]++;
153 switch (icp->icmp_type) {
81a36a8d
BJ
154
155 case ICMP_UNREACH:
156 case ICMP_TIMXCEED:
157 case ICMP_PARAMPROB:
72e4f44e 158 case ICMP_SOURCEQUENCH:
81a36a8d
BJ
159 /*
160 * Problem with previous datagram; advise
161 * higher level routines.
162 */
a1edc12b 163 icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len);
7b66c1fd
SL
164 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
165 icmpstat.icps_badlen++;
d52566dd 166 goto free;
7b66c1fd 167 }
39674d5f
SL
168 if (icmpprintfs)
169 printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
7b66c1fd 170 code = icp->icmp_type == ICMP_PARAMPROB ? 0 : icp->icmp_code;
59965020 171 if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
7b66c1fd 172 (*ctlfunc)(icmpmap[icp->icmp_type]+code, (caddr_t)icp);
81a36a8d
BJ
173 goto free;
174
175 case ICMP_ECHO:
176 icp->icmp_type = ICMP_ECHOREPLY;
177 goto reflect;
178
179 case ICMP_TSTAMP:
7b66c1fd
SL
180 if (icmplen < ICMP_TSLEN) {
181 icmpstat.icps_badlen++;
d52566dd 182 goto free;
7b66c1fd 183 }
81a36a8d 184 icp->icmp_type = ICMP_TSTAMPREPLY;
2b4b57cd 185 icp->icmp_rtime = iptime();
81a36a8d
BJ
186 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */
187 goto reflect;
188
189 case ICMP_IREQ:
190 /* fill in source address zero fields! */
191 goto reflect;
192
a469458a 193 case ICMP_REDIRECT:
81a36a8d
BJ
194 case ICMP_ECHOREPLY:
195 case ICMP_TSTAMPREPLY:
196 case ICMP_IREQREPLY:
7b66c1fd
SL
197 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
198 icmpstat.icps_badlen++;
d52566dd 199 goto free;
7b66c1fd 200 }
a469458a
SL
201 /*
202 * Short circuit routing redirects to force
203 * immediate change in the kernel's routing
204 * tables. The message is also handed to anyone
205 * listening on a raw socket (e.g. the routing
206 * daemon for use in updating it's tables).
207 */
208 if (icp->icmp_type == ICMP_REDIRECT) {
209 icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
210 icmpdst.sin_addr = icp->icmp_gwaddr;
211 rtredirect((struct sockaddr *)&icmpsrc,
212 (struct sockaddr *)&icmpdst);
213 }
72e4f44e
SL
214 icmpsrc.sin_addr = ip->ip_src;
215 icmpdst.sin_addr = ip->ip_dst;
216 raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc,
217 (struct sockaddr *)&icmpdst);
fd15a680 218 return;
81a36a8d
BJ
219
220 default:
221 goto free;
222 }
223reflect:
b012ee63 224 ip->ip_len += hlen; /* since ip_input deducts this */
7b66c1fd 225 icmpstat.icps_reflect++;
81a36a8d 226 icmp_reflect(ip);
af8f6a21 227 return;
81a36a8d
BJ
228free:
229 m_freem(dtom(ip));
230}
231
232/*
233 * Reflect the ip packet back to the source
72e4f44e 234 * TODO: rearrange ip source routing options.
81a36a8d
BJ
235 */
236icmp_reflect(ip)
237 struct ip *ip;
238{
2b4b57cd 239 struct in_addr t;
81a36a8d 240
72e4f44e
SL
241 t = ip->ip_dst;
242 ip->ip_dst = ip->ip_src;
243 ip->ip_src = t;
81a36a8d
BJ
244 icmp_send(ip);
245}
246
247/*
72e4f44e
SL
248 * Send an icmp packet back to the ip level,
249 * after supplying a checksum.
81a36a8d 250 */
cdad2eb1 251icmp_send(ip)
81a36a8d 252 struct ip *ip;
81a36a8d 253{
af8f6a21 254 register int hlen;
72e4f44e 255 register struct icmp *icp;
af8f6a21 256 register struct mbuf *m;
d52566dd 257
af8f6a21
SL
258 m = dtom(ip);
259 hlen = ip->ip_hl << 2;
72e4f44e
SL
260 icp = mtod(m, struct icmp *);
261 icp->icmp_cksum = 0;
262 icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
263 m->m_off -= hlen;
264 m->m_len += hlen;
39674d5f
SL
265 if (icmpprintfs)
266 printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src);
a1edc12b 267 (void) ip_output(m, (struct mbuf *)0, (struct route *)0, 0);
d52566dd
BJ
268}
269
cdad2eb1 270n_time
2b4b57cd 271iptime()
d52566dd 272{
cdad2eb1 273 int s = spl6();
2752c877 274 u_long t;
d52566dd 275
b2ac7f3b 276 t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000;
cdad2eb1
BJ
277 splx(s);
278 return (htonl(t));
d52566dd 279}