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