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