Commit | Line | Data |
---|---|---|
72e4f44e | 1 | /* ip_icmp.c 4.14 82/04/24 */ |
81a36a8d BJ |
2 | |
3 | #include "../h/param.h" | |
2b4b57cd | 4 | #include "../h/systm.h" |
81a36a8d | 5 | #include "../h/mbuf.h" |
cdad2eb1 | 6 | #include "../h/protosw.h" |
72e4f44e | 7 | #include "../h/socket.h" |
cdad2eb1 | 8 | #include "../h/clock.h" |
8a13b737 BJ |
9 | #include "../net/in.h" |
10 | #include "../net/in_systm.h" | |
d52566dd BJ |
11 | #include "../net/ip.h" |
12 | #include "../net/ip_icmp.h" | |
81a36a8d BJ |
13 | |
14 | /* | |
15 | * ICMP routines: error generation, receive packet processing, and | |
16 | * routines to turnaround packets back to the originator, and | |
17 | * host table maintenance routines. | |
18 | */ | |
19 | ||
20 | /* | |
72e4f44e SL |
21 | * Generate an error packet of type error |
22 | * in response to bad packet ip. | |
81a36a8d BJ |
23 | */ |
24 | icmp_error(oip, type, code) | |
25 | struct ip *oip; | |
72e4f44e | 26 | int type, code; |
81a36a8d | 27 | { |
72e4f44e SL |
28 | register unsigned oiplen = oip->ip_hl << 2; |
29 | register struct icmp *icp; | |
81a36a8d BJ |
30 | struct mbuf *m; |
31 | struct ip *nip; | |
8a13b737 | 32 | COUNT(ICMP_ERROR); |
81a36a8d BJ |
33 | |
34 | /* | |
35 | * Make sure that the old IP packet had 8 bytes of data to return; | |
36 | * if not, don't bother. Also don't EVER error if the old | |
37 | * packet protocol was ICMP. | |
38 | */ | |
39 | if (oip->ip_len - oiplen < 8 || oip->ip_p == IPPROTO_ICMP) | |
40 | goto free; | |
41 | ||
42 | /* | |
72e4f44e | 43 | * First, formulate icmp message |
81a36a8d | 44 | */ |
ef9b4258 | 45 | m = m_get(M_DONTWAIT); |
81a36a8d BJ |
46 | if (m == 0) |
47 | goto free; | |
72e4f44e SL |
48 | m->m_len = oiplen + 8 + ICMP_MINLEN; |
49 | m->m_off = MMAXOFF - m->m_len; | |
50 | icp = mtod(m, struct icmp *); | |
81a36a8d | 51 | icp->icmp_type = type; |
72e4f44e | 52 | icp->icmp_void = 0; |
81a36a8d | 53 | if (type == ICMP_PARAMPROB) { |
81a36a8d | 54 | icp->icmp_pptr = code; |
72e4f44e SL |
55 | code = 0; |
56 | } | |
57 | icp->icmp_code = code; | |
d52566dd | 58 | bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8); |
81a36a8d BJ |
59 | |
60 | /* | |
72e4f44e SL |
61 | * Now, copy old ip header in front of icmp |
62 | * message. This allows us to reuse any source | |
63 | * routing info present. | |
81a36a8d | 64 | */ |
72e4f44e SL |
65 | m->m_off -= oiplen; |
66 | nip = mtod(m, struct ip *); | |
67 | bcopy((caddr_t)oip, (caddr_t)nip, oiplen); | |
68 | nip->ip_len = m->m_len + oiplen; | |
69 | nip->ip_p = IPPROTO_ICMP; | |
70 | /* icmp_send adds ip header to m_off and m_len, so we deduct here */ | |
71 | m->m_off += oiplen; | |
d52566dd | 72 | icmp_reflect(nip); |
81a36a8d | 73 | |
def04636 | 74 | free: |
81a36a8d BJ |
75 | m_freem(dtom(oip)); |
76 | } | |
77 | ||
72e4f44e SL |
78 | static char icmpmap[] = { |
79 | -1, -1, -1, | |
80 | PRC_UNREACH_NET, PRC_QUENCH, PRC_REDIRECT_NET, | |
81 | -1, -1, -1, | |
82 | -1, -1, PRC_TIMXCEED_INTRANS, | |
83 | PRC_PARAMPROB, -1, -1, | |
84 | -1, -1 | |
85 | }; | |
86 | ||
87 | static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP }; | |
88 | static struct sockaddr_in icmpsrc = { AF_INET }; | |
89 | static struct sockaddr_in icmpdst = { AF_INET }; | |
90 | ||
81a36a8d | 91 | /* |
d52566dd | 92 | * Process a received ICMP message. |
81a36a8d BJ |
93 | */ |
94 | icmp_input(m) | |
95 | struct mbuf *m; | |
96 | { | |
81a36a8d | 97 | register struct icmp *icp; |
d52566dd | 98 | register struct ip *ip = mtod(m, struct ip *); |
72e4f44e | 99 | int icmplen = ip->ip_len, hlen = ip->ip_hl << 2, i; |
b454c3ea | 100 | extern u_char ip_protox[]; |
8a13b737 | 101 | COUNT(ICMP_INPUT); |
81a36a8d BJ |
102 | |
103 | /* | |
104 | * Locate icmp structure in mbuf, and check | |
105 | * that not corrupted and of at least minimum length. | |
106 | */ | |
72e4f44e SL |
107 | if (icmplen < ICMP_MINLEN) |
108 | goto free; | |
81a36a8d BJ |
109 | m->m_len -= hlen; |
110 | m->m_off += hlen; | |
111 | /* need routine to make sure header is in this mbuf here */ | |
72e4f44e | 112 | icp = mtod(m, struct icmp *); |
81a36a8d BJ |
113 | i = icp->icmp_cksum; |
114 | icp->icmp_cksum = 0; | |
72e4f44e SL |
115 | if (i != in_cksum(m, icmplen)) { |
116 | printf("icmp: cksum %x\n", i); | |
d52566dd | 117 | goto free; |
72e4f44e | 118 | } |
81a36a8d BJ |
119 | |
120 | /* | |
121 | * Message type specific processing. | |
122 | */ | |
72e4f44e | 123 | switch (i = icp->icmp_type) { |
81a36a8d BJ |
124 | |
125 | case ICMP_UNREACH: | |
126 | case ICMP_TIMXCEED: | |
127 | case ICMP_PARAMPROB: | |
81a36a8d | 128 | case ICMP_REDIRECT: |
72e4f44e | 129 | case ICMP_SOURCEQUENCH: |
81a36a8d BJ |
130 | /* |
131 | * Problem with previous datagram; advise | |
132 | * higher level routines. | |
133 | */ | |
d52566dd BJ |
134 | if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) |
135 | goto free; | |
72e4f44e SL |
136 | (*protosw[ip_protox[ip->ip_p]].pr_ctlinput) |
137 | (icmpmap[i] + icp->icmp_code, (caddr_t)icp); | |
81a36a8d BJ |
138 | goto free; |
139 | ||
140 | case ICMP_ECHO: | |
141 | icp->icmp_type = ICMP_ECHOREPLY; | |
142 | goto reflect; | |
143 | ||
144 | case ICMP_TSTAMP: | |
d52566dd BJ |
145 | if (icmplen < ICMP_TSLEN) |
146 | goto free; | |
81a36a8d | 147 | icp->icmp_type = ICMP_TSTAMPREPLY; |
2b4b57cd | 148 | icp->icmp_rtime = iptime(); |
81a36a8d BJ |
149 | icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ |
150 | goto reflect; | |
151 | ||
152 | case ICMP_IREQ: | |
153 | /* fill in source address zero fields! */ | |
154 | goto reflect; | |
155 | ||
156 | case ICMP_ECHOREPLY: | |
157 | case ICMP_TSTAMPREPLY: | |
158 | case ICMP_IREQREPLY: | |
d52566dd BJ |
159 | if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) |
160 | goto free; | |
72e4f44e SL |
161 | icmpsrc.sin_addr = ip->ip_src; |
162 | icmpdst.sin_addr = ip->ip_dst; | |
163 | raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc, | |
164 | (struct sockaddr *)&icmpdst); | |
81a36a8d BJ |
165 | goto free; |
166 | ||
167 | default: | |
168 | goto free; | |
169 | } | |
170 | reflect: | |
171 | icmp_reflect(ip); | |
172 | free: | |
173 | m_freem(dtom(ip)); | |
174 | } | |
175 | ||
176 | /* | |
177 | * Reflect the ip packet back to the source | |
72e4f44e | 178 | * TODO: rearrange ip source routing options. |
81a36a8d BJ |
179 | */ |
180 | icmp_reflect(ip) | |
181 | struct ip *ip; | |
182 | { | |
2b4b57cd | 183 | struct in_addr t; |
8a13b737 | 184 | COUNT(ICMP_REFLECT); |
81a36a8d | 185 | |
72e4f44e SL |
186 | t = ip->ip_dst; |
187 | ip->ip_dst = ip->ip_src; | |
188 | ip->ip_src = t; | |
81a36a8d BJ |
189 | icmp_send(ip); |
190 | } | |
191 | ||
72e4f44e SL |
192 | int generateicmpmsgs = 0; |
193 | ||
81a36a8d | 194 | /* |
72e4f44e SL |
195 | * Send an icmp packet back to the ip level, |
196 | * after supplying a checksum. | |
81a36a8d | 197 | */ |
cdad2eb1 | 198 | icmp_send(ip) |
81a36a8d | 199 | struct ip *ip; |
81a36a8d | 200 | { |
72e4f44e SL |
201 | register int hlen = ip->ip_hl << 2; |
202 | register struct icmp *icp; | |
203 | register struct mbuf *m = dtom(ip); | |
d52566dd | 204 | |
72e4f44e SL |
205 | COUNT(ICMP_SEND); |
206 | if (!generateicmpmsgs) | |
207 | return; | |
208 | icp = mtod(m, struct icmp *); | |
209 | icp->icmp_cksum = 0; | |
210 | icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); | |
211 | m->m_off -= hlen; | |
212 | m->m_len += hlen; | |
213 | (void) ip_output(m, 0, 0, 0); | |
d52566dd BJ |
214 | } |
215 | ||
cdad2eb1 | 216 | n_time |
2b4b57cd | 217 | iptime() |
d52566dd | 218 | { |
cdad2eb1 | 219 | int s = spl6(); |
2752c877 | 220 | u_long t; |
d52566dd | 221 | |
8a13b737 | 222 | COUNT(IPTIME); |
cdad2eb1 BJ |
223 | t = (time % SECDAY) * 1000 + lbolt * hz; |
224 | splx(s); | |
225 | return (htonl(t)); | |
d52566dd | 226 | } |