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