more cleanup
[unix-history] / usr / src / sys / netinet / ip_icmp.c
CommitLineData
f1b2fa5b 1/* ip_icmp.c 4.9 81/11/29 */
81a36a8d
BJ
2
3#include "../h/param.h"
2b4b57cd 4#include "../h/systm.h"
81a36a8d 5#include "../h/mbuf.h"
cdad2eb1
BJ
6#include "../h/protosw.h"
7#include "../h/clock.h"
8a13b737
BJ
8#include "../net/in.h"
9#include "../net/in_systm.h"
d52566dd
BJ
10#include "../net/ip.h"
11#include "../net/ip_icmp.h"
81a36a8d
BJ
12
13/*
14 * ICMP routines: error generation, receive packet processing, and
15 * routines to turnaround packets back to the originator, and
16 * host table maintenance routines.
17 */
18
19/*
20 * Generate an error packet of type error in response to bad packet ip.
21 */
22icmp_error(oip, type, code)
23 struct ip *oip;
24 int type;
25{
cdad2eb1 26 unsigned oiplen = oip->ip_hl << 2;
d52566dd 27 struct icmp *icp = (struct icmp *)((int)oip + oiplen);
81a36a8d
BJ
28 struct mbuf *m;
29 struct ip *nip;
8a13b737 30COUNT(ICMP_ERROR);
81a36a8d
BJ
31
32 /*
33 * Make sure that the old IP packet had 8 bytes of data to return;
34 * if not, don't bother. Also don't EVER error if the old
35 * packet protocol was ICMP.
36 */
37 if (oip->ip_len - oiplen < 8 || oip->ip_p == IPPROTO_ICMP)
38 goto free;
39
40 /*
41 * Get a new mbuf, and fill in a ICMP header at the bottom
42 * of the mbuf, followed by the old IP header and 8 bytes
43 * of its data.
44 */
45 m = m_get(0);
46 if (m == 0)
47 goto free;
48 m->m_off = MMAXOFF - (oiplen + 8);
49 icp->icmp_type = type;
50 if (type == ICMP_PARAMPROB) {
51 icp->icmp_code = 0;
52 icp->icmp_pptr = code;
53 } else
54 icp->icmp_code = code;
d52566dd 55 bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8);
81a36a8d
BJ
56
57 /*
58 * Now prepend an IP header and reflect this packet back to
59 * the source.
60 */
61 m->m_off -= sizeof (struct ip);
62 m->m_len += sizeof (struct ip);
d52566dd
BJ
63 nip = (struct ip *)mtod(m, struct ip *);
64 *nip = *oip;
65 icmp_reflect(nip);
81a36a8d
BJ
66
67 /*
68 * Discard mbufs of original datagram
69 */
70free:
71 m_freem(dtom(oip));
72}
73
74/*
d52566dd 75 * Process a received ICMP message.
81a36a8d
BJ
76 */
77icmp_input(m)
78 struct mbuf *m;
79{
81a36a8d 80 register struct icmp *icp;
d52566dd
BJ
81 register struct ip *ip = mtod(m, struct ip *);
82 int hlen = ip->ip_hl << 2;
81a36a8d 83 int icmplen = ip->ip_len - hlen;
d52566dd 84 int i;
8a13b737 85COUNT(ICMP_INPUT);
81a36a8d
BJ
86
87 /*
88 * Locate icmp structure in mbuf, and check
89 * that not corrupted and of at least minimum length.
90 */
91 m->m_len -= hlen;
92 m->m_off += hlen;
93 /* need routine to make sure header is in this mbuf here */
d52566dd 94 icp = (struct icmp *)mtod(m, struct icmp *);
81a36a8d
BJ
95 i = icp->icmp_cksum;
96 icp->icmp_cksum = 0;
8a13b737 97 if (i != in_cksum(m, icmplen) || icmplen < ICMP_MINLEN)
d52566dd 98 goto free;
81a36a8d
BJ
99
100 /*
101 * Message type specific processing.
102 */
d52566dd 103 switch (icp->icmp_type) {
81a36a8d
BJ
104
105 case ICMP_UNREACH:
106 case ICMP_TIMXCEED:
107 case ICMP_PARAMPROB:
108 case ICMP_SOURCEQUENCH:
109 case ICMP_REDIRECT:
110 /*
111 * Problem with previous datagram; advise
112 * higher level routines.
113 */
d52566dd
BJ
114 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
115 goto free;
cdad2eb1 116 icmp_ctlinput(ip);
81a36a8d
BJ
117 goto free;
118
119 case ICMP_ECHO:
120 icp->icmp_type = ICMP_ECHOREPLY;
121 goto reflect;
122
123 case ICMP_TSTAMP:
d52566dd
BJ
124 if (icmplen < ICMP_TSLEN)
125 goto free;
81a36a8d 126 icp->icmp_type = ICMP_TSTAMPREPLY;
2b4b57cd 127 icp->icmp_rtime = iptime();
81a36a8d
BJ
128 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */
129 goto reflect;
130
131 case ICMP_IREQ:
132 /* fill in source address zero fields! */
133 goto reflect;
134
135 case ICMP_ECHOREPLY:
136 case ICMP_TSTAMPREPLY:
137 case ICMP_IREQREPLY:
d52566dd
BJ
138 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
139 goto free;
81a36a8d
BJ
140 icmp_gotreply(icp);
141 goto free;
142
143 default:
144 goto free;
145 }
146reflect:
147 icmp_reflect(ip);
148free:
149 m_freem(dtom(ip));
150}
151
152/*
153 * Reflect the ip packet back to the source
154 */
155icmp_reflect(ip)
156 struct ip *ip;
157{
2b4b57cd 158 struct in_addr t;
8a13b737 159COUNT(ICMP_REFLECT);
81a36a8d 160
d52566dd 161 t = ip->ip_src; ip->ip_dst = ip->ip_src; ip->ip_src = t;
81a36a8d
BJ
162 /*
163 * This is a little naive... do we have to munge the options
164 * to reverse source routing?
165 */
81a36a8d
BJ
166 icmp_send(ip);
167}
168
169/*
170 * Send an icmp packet back to the ip level, after
171 * supplying a checksum.
172 */
cdad2eb1 173icmp_send(ip)
81a36a8d 174 struct ip *ip;
81a36a8d 175{
cdad2eb1 176 struct icmp *icp = 0; /* XXX */
8a13b737 177COUNT(ICMP_SEND);
81a36a8d 178
d52566dd 179 icp->icmp_cksum = 0;
8a13b737 180 icp->icmp_cksum = in_cksum(dtom(ip), 0); /* XXX */
4d5fc554 181 ip->ip_ttl = MAXTTL;
f1b2fa5b 182 (void) ip_output(dtom(ip), (struct mbuf *)0);
81a36a8d
BJ
183}
184
185/*
186 * Advise a higher level protocol of a problem reported by
187 * a gateway or another host.
188 */
cdad2eb1 189icmp_ctlinput(ip)
81a36a8d 190 struct ip *ip;
81a36a8d 191{
cdad2eb1 192 extern u_char ip_protox[]; /* XXX */
8a13b737 193COUNT(ICMP_CTLINPUT);
81a36a8d 194
cdad2eb1 195 (*protosw[ip_protox[ip->ip_p]].pr_ctlinput)(ip);
81a36a8d
BJ
196}
197
198/*
199 * Got a reply, e.g. to an echo message or a timestamp
200 * message; nothing is done with these yet.
201 */
202/*ARGSUSED*/
203icmp_gotreply(icp)
204 struct icmp *icp;
205{
206
8a13b737 207COUNT(ICMP_GOTREPLY);
81a36a8d 208}
d52566dd
BJ
209
210icmp_drain()
211{
212
8a13b737 213COUNT(ICMP_DRAIN);
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}