xref: /original-bsd/sys/netinet/ip_icmp.c (revision 1e7fda44)
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  */
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 
67 free:
68 	/*
69 	 * Discard mbufs of original datagram
70 	 */
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 	extern u_char ip_protox[];
86 COUNT(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 	}
147 reflect:
148 	icmp_reflect(ip);
149 free:
150 	m_freem(dtom(ip));
151 }
152 
153 /*
154  * Reflect the ip packet back to the source
155  */
156 icmp_reflect(ip)
157 	struct ip *ip;
158 {
159 	struct in_addr t;
160 COUNT(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  */
174 icmp_send(ip)
175 	struct ip *ip;
176 {
177 COUNT(ICMP_SEND);
178 
179 	m_freem(dtom(ip));
180 }
181 
182 icmp_ctlinput(m)
183 	struct mbuf *m;
184 {
185 COUNT(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*/
195 icmp_gotreply(icp)
196 	struct icmp *icp;
197 {
198 
199 COUNT(ICMP_GOTREPLY);
200 }
201 
202 icmp_drain()
203 {
204 
205 COUNT(ICMP_DRAIN);
206 }
207 
208 n_time
209 iptime()
210 {
211 	int s = spl6();
212 	u_long t;
213 
214 COUNT(IPTIME);
215 	t = (time % SECDAY) * 1000 + lbolt * hz;
216 	splx(s);
217 	return (htonl(t));
218 }
219