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