properly free mbuf space
[unix-history] / usr / src / sys / netinet / ip_icmp.c
... / ...
CommitLineData
1/* ip_icmp.c 4.13 82/04/07 */
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/mbuf.h"
6#include "../h/protosw.h"
7#include "../h/clock.h"
8#include "../net/in.h"
9#include "../net/in_systm.h"
10#include "../net/ip.h"
11#include "../net/ip_icmp.h"
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{
26 unsigned oiplen = oip->ip_hl << 2;
27 struct icmp *icp = (struct icmp *)((int)oip + oiplen);
28 struct mbuf *m;
29 struct ip *nip;
30COUNT(ICMP_ERROR);
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(M_DONTWAIT);
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;
55 bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8);
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);
63 nip = (struct ip *)mtod(m, struct ip *);
64 *nip = *oip;
65 icmp_reflect(nip);
66
67free:
68 /*
69 * Discard mbufs of original datagram
70 */
71 m_freem(dtom(oip));
72}
73
74/*
75 * Process a received ICMP message.
76 */
77icmp_input(m)
78 struct mbuf *m;
79{
80 register struct icmp *icp;
81 register struct ip *ip = mtod(m, struct ip *);
82 int hlen = ip->ip_hl << 2;
83 int icmplen = ip->ip_len - hlen;
84 int i;
85 extern u_char ip_protox[];
86COUNT(ICMP_INPUT);
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 */
95 icp = (struct icmp *)mtod(m, struct icmp *);
96 i = icp->icmp_cksum;
97 icp->icmp_cksum = 0;
98 if (i != in_cksum(m, icmplen) || icmplen < ICMP_MINLEN)
99 goto free;
100
101 /*
102 * Message type specific processing.
103 */
104 switch (icp->icmp_type) {
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 */
115 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
116 goto free;
117 (*protosw[ip_protox[ip->ip_p]].pr_ctlinput)(m);
118 goto free;
119
120 case ICMP_ECHO:
121 icp->icmp_type = ICMP_ECHOREPLY;
122 goto reflect;
123
124 case ICMP_TSTAMP:
125 if (icmplen < ICMP_TSLEN)
126 goto free;
127 icp->icmp_type = ICMP_TSTAMPREPLY;
128 icp->icmp_rtime = iptime();
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:
139 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
140 goto free;
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{
159 struct in_addr t;
160COUNT(ICMP_REFLECT);
161
162 t = ip->ip_src; ip->ip_dst = ip->ip_src; ip->ip_src = t;
163 /*
164 * This is a little naive... do we have to munge the options
165 * to reverse source routing?
166 */
167 icmp_send(ip);
168}
169
170/*
171 * Send an icmp packet back to the ip level, after
172 * supplying a checksum.
173 */
174icmp_send(ip)
175 struct ip *ip;
176{
177COUNT(ICMP_SEND);
178
179 m_freem(dtom(ip));
180}
181
182icmp_ctlinput(m)
183 struct mbuf *m;
184{
185COUNT(ICMP_CTLINPUT);
186
187 m_freem(m);
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
199COUNT(ICMP_GOTREPLY);
200}
201
202icmp_drain()
203{
204
205COUNT(ICMP_DRAIN);
206}
207
208n_time
209iptime()
210{
211 int s = spl6();
212 u_long t;
213
214COUNT(IPTIME);
215 t = (time % SECDAY) * 1000 + lbolt * hz;
216 splx(s);
217 return (htonl(t));
218}