xref: /csrg-svn/sys/netinet/ip_icmp.c (revision 5584)
1 /*	ip_icmp.c	4.12	82/01/19	*/
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  */
22 icmp_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;
30 COUNT(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 	return;
67 
68 	/*
69 	 * Discard mbufs of original datagram
70 	 */
71 free:
72 	m_freem(dtom(oip));
73 }
74 
75 /*
76  * Process a received ICMP message.
77  */
78 icmp_input(m)
79 	struct mbuf *m;
80 {
81 	register struct icmp *icp;
82 	register struct ip *ip = mtod(m, struct ip *);
83 	int hlen = ip->ip_hl << 2;
84 	int icmplen = ip->ip_len - hlen;
85 	int i;
86 	extern u_char ip_protox[];
87 COUNT(ICMP_INPUT);
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 */
96 	icp = (struct icmp *)mtod(m, struct icmp *);
97 	i = icp->icmp_cksum;
98 	icp->icmp_cksum = 0;
99 	if (i != in_cksum(m, icmplen) || icmplen < ICMP_MINLEN)
100 		goto free;
101 
102 	/*
103 	 * Message type specific processing.
104 	 */
105 	switch (icp->icmp_type) {
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 		 */
116 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
117 			goto free;
118 		(*protosw[ip_protox[ip->ip_p]].pr_ctlinput)(m);
119 		goto free;
120 
121 	case ICMP_ECHO:
122 		icp->icmp_type = ICMP_ECHOREPLY;
123 		goto reflect;
124 
125 	case ICMP_TSTAMP:
126 		if (icmplen < ICMP_TSLEN)
127 			goto free;
128 		icp->icmp_type = ICMP_TSTAMPREPLY;
129 		icp->icmp_rtime = iptime();
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:
140 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
141 			goto free;
142 		icmp_gotreply(icp);
143 		goto free;
144 
145 	default:
146 		goto free;
147 	}
148 reflect:
149 	icmp_reflect(ip);
150 free:
151 	m_freem(dtom(ip));
152 }
153 
154 /*
155  * Reflect the ip packet back to the source
156  */
157 icmp_reflect(ip)
158 	struct ip *ip;
159 {
160 	struct in_addr t;
161 COUNT(ICMP_REFLECT);
162 
163 	t = ip->ip_src; ip->ip_dst = ip->ip_src; ip->ip_src = t;
164 	/*
165 	 * This is a little naive... do we have to munge the options
166 	 * to reverse source routing?
167 	 */
168 	icmp_send(ip);
169 }
170 
171 /*
172  * Send an icmp packet back to the ip level, after
173  * supplying a checksum.
174  */
175 icmp_send(ip)
176 	struct ip *ip;
177 {
178 COUNT(ICMP_SEND);
179 
180 	m_freem(dtom(ip));
181 }
182 
183 icmp_ctlinput(m)
184 	struct mbuf *m;
185 {
186 COUNT(ICMP_CTLINPUT);
187 
188 	m_freem(m);
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*/
196 icmp_gotreply(icp)
197 	struct icmp *icp;
198 {
199 
200 COUNT(ICMP_GOTREPLY);
201 }
202 
203 icmp_drain()
204 {
205 
206 COUNT(ICMP_DRAIN);
207 }
208 
209 n_time
210 iptime()
211 {
212 	int s = spl6();
213 	u_long t;
214 
215 COUNT(IPTIME);
216 	t = (time % SECDAY) * 1000 + lbolt * hz;
217 	splx(s);
218 	return (htonl(t));
219 }
220