icmp and ctlinput working -- missing protocol specific ctlinput's
[unix-history] / usr / src / sys / netinet / ip_icmp.c
... / ...
CommitLineData
1/* ip_icmp.c 4.14 82/04/24 */
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
20/*
21 * Generate an error packet of type error
22 * in response to bad packet ip.
23 */
24icmp_error(oip, type, code)
25 struct ip *oip;
26 int type, code;
27{
28 register unsigned oiplen = oip->ip_hl << 2;
29 register struct icmp *icp;
30 struct mbuf *m;
31 struct ip *nip;
32COUNT(ICMP_ERROR);
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 /*
43 * First, formulate icmp message
44 */
45 m = m_get(M_DONTWAIT);
46 if (m == 0)
47 goto free;
48 m->m_len = oiplen + 8 + ICMP_MINLEN;
49 m->m_off = MMAXOFF - m->m_len;
50 icp = mtod(m, struct icmp *);
51 icp->icmp_type = type;
52 icp->icmp_void = 0;
53 if (type == ICMP_PARAMPROB) {
54 icp->icmp_pptr = code;
55 code = 0;
56 }
57 icp->icmp_code = code;
58 bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8);
59
60 /*
61 * Now, copy old ip header in front of icmp
62 * message. This allows us to reuse any source
63 * routing info present.
64 */
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;
72 icmp_reflect(nip);
73
74free:
75 m_freem(dtom(oip));
76}
77
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
91/*
92 * Process a received ICMP message.
93 */
94icmp_input(m)
95 struct mbuf *m;
96{
97 register struct icmp *icp;
98 register struct ip *ip = mtod(m, struct ip *);
99 int icmplen = ip->ip_len, hlen = ip->ip_hl << 2, i;
100 extern u_char ip_protox[];
101COUNT(ICMP_INPUT);
102
103 /*
104 * Locate icmp structure in mbuf, and check
105 * that not corrupted and of at least minimum length.
106 */
107 if (icmplen < ICMP_MINLEN)
108 goto free;
109 m->m_len -= hlen;
110 m->m_off += hlen;
111 /* need routine to make sure header is in this mbuf here */
112 icp = mtod(m, struct icmp *);
113 i = icp->icmp_cksum;
114 icp->icmp_cksum = 0;
115 if (i != in_cksum(m, icmplen)) {
116 printf("icmp: cksum %x\n", i);
117 goto free;
118 }
119
120 /*
121 * Message type specific processing.
122 */
123 switch (i = icp->icmp_type) {
124
125 case ICMP_UNREACH:
126 case ICMP_TIMXCEED:
127 case ICMP_PARAMPROB:
128 case ICMP_REDIRECT:
129 case ICMP_SOURCEQUENCH:
130 /*
131 * Problem with previous datagram; advise
132 * higher level routines.
133 */
134 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
135 goto free;
136 (*protosw[ip_protox[ip->ip_p]].pr_ctlinput)
137 (icmpmap[i] + icp->icmp_code, (caddr_t)icp);
138 goto free;
139
140 case ICMP_ECHO:
141 icp->icmp_type = ICMP_ECHOREPLY;
142 goto reflect;
143
144 case ICMP_TSTAMP:
145 if (icmplen < ICMP_TSLEN)
146 goto free;
147 icp->icmp_type = ICMP_TSTAMPREPLY;
148 icp->icmp_rtime = iptime();
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:
159 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
160 goto free;
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);
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
178 * TODO: rearrange ip source routing options.
179 */
180icmp_reflect(ip)
181 struct ip *ip;
182{
183 struct in_addr t;
184COUNT(ICMP_REFLECT);
185
186 t = ip->ip_dst;
187 ip->ip_dst = ip->ip_src;
188 ip->ip_src = t;
189 icmp_send(ip);
190}
191
192int generateicmpmsgs = 0;
193
194/*
195 * Send an icmp packet back to the ip level,
196 * after supplying a checksum.
197 */
198icmp_send(ip)
199 struct ip *ip;
200{
201 register int hlen = ip->ip_hl << 2;
202 register struct icmp *icp;
203 register struct mbuf *m = dtom(ip);
204
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);
214}
215
216n_time
217iptime()
218{
219 int s = spl6();
220 u_long t;
221
222COUNT(IPTIME);
223 t = (time % SECDAY) * 1000 + lbolt * hz;
224 splx(s);
225 return (htonl(t));
226}