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