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