core ()ization
[unix-history] / usr / src / sys / netinet / ip_icmp.c
CommitLineData
fe034d95 1/* ip_icmp.c 4.11 81/12/22 */
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);
b454c3ea 66 return;
81a36a8d
BJ
67
68 /*
69 * Discard mbufs of original datagram
70 */
71free:
72 m_freem(dtom(oip));
73}
74
75/*
d52566dd 76 * Process a received ICMP message.
81a36a8d
BJ
77 */
78icmp_input(m)
79 struct mbuf *m;
80{
81a36a8d 81 register struct icmp *icp;
d52566dd
BJ
82 register struct ip *ip = mtod(m, struct ip *);
83 int hlen = ip->ip_hl << 2;
81a36a8d 84 int icmplen = ip->ip_len - hlen;
d52566dd 85 int i;
b454c3ea 86 extern u_char ip_protox[];
8a13b737 87COUNT(ICMP_INPUT);
81a36a8d
BJ
88
89 /*
90 * Locate icmp structure in mbuf, and check
91 * that not corrupted and of at least minimum length.
92 */
93 m->m_len -= hlen;
94 m->m_off += hlen;
95 /* need routine to make sure header is in this mbuf here */
d52566dd 96 icp = (struct icmp *)mtod(m, struct icmp *);
81a36a8d
BJ
97 i = icp->icmp_cksum;
98 icp->icmp_cksum = 0;
8a13b737 99 if (i != in_cksum(m, icmplen) || icmplen < ICMP_MINLEN)
d52566dd 100 goto free;
81a36a8d
BJ
101
102 /*
103 * Message type specific processing.
104 */
d52566dd 105 switch (icp->icmp_type) {
81a36a8d
BJ
106
107 case ICMP_UNREACH:
108 case ICMP_TIMXCEED:
109 case ICMP_PARAMPROB:
110 case ICMP_SOURCEQUENCH:
111 case ICMP_REDIRECT:
112 /*
113 * Problem with previous datagram; advise
114 * higher level routines.
115 */
d52566dd
BJ
116 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
117 goto free;
b454c3ea 118 (*protosw[ip_protox[ip->ip_p]].pr_ctlinput)(m);
81a36a8d
BJ
119 goto free;
120
121 case ICMP_ECHO:
122 icp->icmp_type = ICMP_ECHOREPLY;
123 goto reflect;
124
125 case ICMP_TSTAMP:
d52566dd
BJ
126 if (icmplen < ICMP_TSLEN)
127 goto free;
81a36a8d 128 icp->icmp_type = ICMP_TSTAMPREPLY;
2b4b57cd 129 icp->icmp_rtime = iptime();
81a36a8d
BJ
130 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */
131 goto reflect;
132
133 case ICMP_IREQ:
134 /* fill in source address zero fields! */
135 goto reflect;
136
137 case ICMP_ECHOREPLY:
138 case ICMP_TSTAMPREPLY:
139 case ICMP_IREQREPLY:
d52566dd
BJ
140 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
141 goto free;
81a36a8d
BJ
142 icmp_gotreply(icp);
143 goto free;
144
145 default:
146 goto free;
147 }
148reflect:
149 icmp_reflect(ip);
150free:
151 m_freem(dtom(ip));
152}
153
154/*
155 * Reflect the ip packet back to the source
156 */
157icmp_reflect(ip)
158 struct ip *ip;
159{
2b4b57cd 160 struct in_addr t;
8a13b737 161COUNT(ICMP_REFLECT);
81a36a8d 162
d52566dd 163 t = ip->ip_src; ip->ip_dst = ip->ip_src; ip->ip_src = t;
81a36a8d
BJ
164 /*
165 * This is a little naive... do we have to munge the options
166 * to reverse source routing?
167 */
81a36a8d
BJ
168 icmp_send(ip);
169}
170
171/*
172 * Send an icmp packet back to the ip level, after
173 * supplying a checksum.
174 */
cdad2eb1 175icmp_send(ip)
81a36a8d 176 struct ip *ip;
81a36a8d 177{
8a13b737 178COUNT(ICMP_SEND);
81a36a8d 179
fe034d95 180 m_freem(dtom(ip));
81a36a8d
BJ
181}
182
b454c3ea
BJ
183icmp_ctlinput(m)
184 struct mbuf *m;
81a36a8d 185{
8a13b737 186COUNT(ICMP_CTLINPUT);
81a36a8d 187
b454c3ea 188 m_freem(m);
81a36a8d
BJ
189}
190
191/*
192 * Got a reply, e.g. to an echo message or a timestamp
193 * message; nothing is done with these yet.
194 */
195/*ARGSUSED*/
196icmp_gotreply(icp)
197 struct icmp *icp;
198{
199
8a13b737 200COUNT(ICMP_GOTREPLY);
81a36a8d 201}
d52566dd
BJ
202
203icmp_drain()
204{
205
8a13b737 206COUNT(ICMP_DRAIN);
d52566dd
BJ
207}
208
cdad2eb1 209n_time
2b4b57cd 210iptime()
d52566dd 211{
cdad2eb1 212 int s = spl6();
2752c877 213 u_long t;
d52566dd 214
8a13b737 215COUNT(IPTIME);
cdad2eb1
BJ
216 t = (time % SECDAY) * 1000 + lbolt * hz;
217 splx(s);
218 return (htonl(t));
d52566dd 219}