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