xref: /csrg-svn/sys/netinet/ip_icmp.c (revision 4967)
1 /*	ip_icmp.c	4.6	81/11/20	*/
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/inet.h"
9 #include "../net/inet_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 
31 	/*
32 	 * Make sure that the old IP packet had 8 bytes of data to return;
33 	 * if not, don't bother.  Also don't EVER error if the old
34 	 * packet protocol was ICMP.
35 	 */
36 	if (oip->ip_len - oiplen < 8 || oip->ip_p == IPPROTO_ICMP)
37 		goto free;
38 
39 	/*
40 	 * Get a new mbuf, and fill in a ICMP header at the bottom
41 	 * of the mbuf, followed by the old IP header and 8 bytes
42 	 * of its data.
43 	 */
44 	m = m_get(0);
45 	if (m == 0)
46 		goto free;
47 	m->m_off = MMAXOFF - (oiplen + 8);
48 	icp->icmp_type = type;
49 	if (type == ICMP_PARAMPROB) {
50 		icp->icmp_code = 0;
51 		icp->icmp_pptr = code;
52 	} else
53 		icp->icmp_code = code;
54 	bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8);
55 
56 	/*
57 	 * Now prepend an IP header and reflect this packet back to
58 	 * the source.
59 	 */
60 	m->m_off -= sizeof (struct ip);
61 	m->m_len += sizeof (struct ip);
62 	nip = (struct ip *)mtod(m, struct ip *);
63 	*nip = *oip;
64 	icmp_reflect(nip);
65 
66 	/*
67 	 * Discard mbufs of original datagram
68 	 */
69 free:
70 	m_freem(dtom(oip));
71 }
72 
73 /*
74  * Process a received ICMP message.
75  */
76 icmp_input(m)
77 	struct mbuf *m;
78 {
79 	register struct icmp *icp;
80 	register struct ip *ip = mtod(m, struct ip *);
81 	int hlen = ip->ip_hl << 2;
82 	int icmplen = ip->ip_len - hlen;
83 	int i;
84 
85 	/*
86 	 * Locate icmp structure in mbuf, and check
87 	 * that not corrupted and of at least minimum length.
88 	 */
89 	m->m_len -= hlen;
90 	m->m_off += hlen;
91 	/* need routine to make sure header is in this mbuf here */
92 	icp = (struct icmp *)mtod(m, struct icmp *);
93 	i = icp->icmp_cksum;
94 	icp->icmp_cksum = 0;
95 	if (i != inet_cksum(m, icmplen) || icmplen < ICMP_MINLEN)
96 		goto free;
97 
98 	/*
99 	 * Message type specific processing.
100 	 */
101 	switch (icp->icmp_type) {
102 
103 	case ICMP_UNREACH:
104 	case ICMP_TIMXCEED:
105 	case ICMP_PARAMPROB:
106 	case ICMP_SOURCEQUENCH:
107 	case ICMP_REDIRECT:
108 		/*
109 		 * Problem with previous datagram; advise
110 		 * higher level routines.
111 		 */
112 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
113 			goto free;
114 		icmp_ctlinput(ip);
115 		goto free;
116 
117 	case ICMP_ECHO:
118 		icp->icmp_type = ICMP_ECHOREPLY;
119 		goto reflect;
120 
121 	case ICMP_TSTAMP:
122 		if (icmplen < ICMP_TSLEN)
123 			goto free;
124 		icp->icmp_type = ICMP_TSTAMPREPLY;
125 		icp->icmp_rtime = iptime();
126 		icp->icmp_ttime = icp->icmp_rtime;	/* bogus, do later! */
127 		goto reflect;
128 
129 	case ICMP_IREQ:
130 		/* fill in source address zero fields! */
131 		goto reflect;
132 
133 	case ICMP_ECHOREPLY:
134 	case ICMP_TSTAMPREPLY:
135 	case ICMP_IREQREPLY:
136 		if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp))
137 			goto free;
138 		icmp_gotreply(icp);
139 		goto free;
140 
141 	default:
142 		goto free;
143 	}
144 reflect:
145 	icmp_reflect(ip);
146 free:
147 	m_freem(dtom(ip));
148 }
149 
150 /*
151  * Reflect the ip packet back to the source
152  */
153 icmp_reflect(ip)
154 	struct ip *ip;
155 {
156 	struct in_addr t;
157 
158 	t = ip->ip_src; ip->ip_dst = ip->ip_src; ip->ip_src = t;
159 	/*
160 	 * This is a little naive... do we have to munge the options
161 	 * to reverse source routing?
162 	 */
163 	icmp_send(ip);
164 }
165 
166 /*
167  * Send an icmp packet back to the ip level, after
168  * supplying a checksum.
169  */
170 icmp_send(ip)
171 	struct ip *ip;
172 {
173 	struct icmp *icp = 0;					/* XXX */
174 
175 	icp->icmp_cksum = 0;
176 	icp->icmp_cksum = inet_cksum(dtom(ip), 0);		/* XXX */
177 	/* what about ttl? */
178 	ip_output(dtom(ip));
179 }
180 
181 /*
182  * Advise a higher level protocol of a problem reported by
183  * a gateway or another host.
184  */
185 icmp_ctlinput(ip)
186 	struct ip *ip;
187 {
188 	extern u_char ip_protox[];		/* XXX */
189 
190 	(*protosw[ip_protox[ip->ip_p]].pr_ctlinput)(ip);
191 }
192 
193 /*
194  * Got a reply, e.g. to an echo message or a timestamp
195  * message; nothing is done with these yet.
196  */
197 /*ARGSUSED*/
198 icmp_gotreply(icp)
199 	struct icmp *icp;
200 {
201 
202 }
203 
204 icmp_drain()
205 {
206 
207 }
208 
209 n_time
210 iptime()
211 {
212 	int s = spl6();
213 	u_long t;
214 
215 	t = (time % SECDAY) * 1000 + lbolt * hz;
216 	splx(s);
217 	return (htonl(t));
218 }
219