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