1 /* ip_icmp.c 6.7 84/08/29 */ 2 3 #include "param.h" 4 #include "systm.h" 5 #include "mbuf.h" 6 #include "protosw.h" 7 #include "socket.h" 8 #include "time.h" 9 #include "kernel.h" 10 11 #include "../net/route.h" 12 13 #include "in.h" 14 #include "in_systm.h" 15 #include "ip.h" 16 #include "ip_icmp.h" 17 #include "icmp_var.h" 18 19 #ifdef ICMPPRINTFS 20 /* 21 * ICMP routines: error generation, receive packet processing, and 22 * routines to turnaround packets back to the originator, and 23 * host table maintenance routines. 24 */ 25 int icmpprintfs = 0; 26 #endif 27 28 /* 29 * Generate an error packet of type error 30 * in response to bad packet ip. 31 */ 32 icmp_error(oip, type, code) 33 struct ip *oip; 34 int type, code; 35 { 36 register unsigned oiplen = oip->ip_hl << 2; 37 register struct icmp *icp; 38 struct mbuf *m; 39 struct ip *nip; 40 41 #ifdef ICMPPRINTFS 42 if (icmpprintfs) 43 printf("icmp_error(%x, %d, %d)\n", oip, type, code); 44 #endif 45 icmpstat.icps_error++; 46 /* 47 * Make sure that the old IP packet had 8 bytes of data to return; 48 * if not, don't bother. Also don't EVER error if the old 49 * packet protocol was ICMP. 50 */ 51 if (oip->ip_len < 8) { 52 icmpstat.icps_oldshort++; 53 goto free; 54 } 55 if (oip->ip_p == IPPROTO_ICMP) { 56 icmpstat.icps_oldicmp++; 57 goto free; 58 } 59 60 /* 61 * First, formulate icmp message 62 */ 63 m = m_get(M_DONTWAIT, MT_HEADER); 64 if (m == NULL) 65 goto free; 66 m->m_len = oiplen + 8 + ICMP_MINLEN; 67 m->m_off = MMAXOFF - m->m_len; 68 icp = mtod(m, struct icmp *); 69 if ((u_int)type > ICMP_IREQREPLY) 70 panic("icmp_error"); 71 icmpstat.icps_outhist[type]++; 72 icp->icmp_type = type; 73 icp->icmp_void = 0; 74 if (type == ICMP_PARAMPROB) { 75 icp->icmp_pptr = code; 76 code = 0; 77 } 78 icp->icmp_code = code; 79 bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8); 80 nip = &icp->icmp_ip; 81 nip->ip_len += oiplen; 82 nip->ip_len = htons((u_short)nip->ip_len); 83 84 /* 85 * Now, copy old ip header in front of icmp 86 * message. This allows us to reuse any source 87 * routing info present. 88 */ 89 m->m_off -= oiplen; 90 nip = mtod(m, struct ip *); 91 bcopy((caddr_t)oip, (caddr_t)nip, oiplen); 92 nip->ip_len = m->m_len + oiplen; 93 nip->ip_p = IPPROTO_ICMP; 94 /* icmp_send adds ip header to m_off and m_len, so we deduct here */ 95 m->m_off += oiplen; 96 icmp_reflect(nip); 97 98 free: 99 m_freem(dtom(oip)); 100 } 101 102 static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP }; 103 static struct sockaddr_in icmpsrc = { AF_INET }; 104 static struct sockaddr_in icmpdst = { AF_INET }; 105 106 /* 107 * Process a received ICMP message. 108 */ 109 icmp_input(m) 110 struct mbuf *m; 111 { 112 register struct icmp *icp; 113 register struct ip *ip = mtod(m, struct ip *); 114 int icmplen = ip->ip_len, hlen = ip->ip_hl << 2; 115 register int i; 116 int (*ctlfunc)(), code; 117 extern u_char ip_protox[]; 118 extern struct in_addr if_makeaddr(); 119 120 /* 121 * Locate icmp structure in mbuf, and check 122 * that not corrupted and of at least minimum length. 123 */ 124 #ifdef ICMPPRINTFS 125 if (icmpprintfs) 126 printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen); 127 #endif 128 if (icmplen < ICMP_MINLEN) { 129 icmpstat.icps_tooshort++; 130 goto free; 131 } 132 /* THIS LENGTH CHECK STILL MISSES ANY IP OPTIONS IN ICMP_IP */ 133 i = MIN(icmplen, ICMP_ADVLENMIN + hlen); 134 if ((m->m_off > MMAXOFF || m->m_len < i) && 135 (m = m_pullup(m, i)) == 0) { 136 icmpstat.icps_tooshort++; 137 return; 138 } 139 ip = mtod(m, struct ip *); 140 m->m_len -= hlen; 141 m->m_off += hlen; 142 icp = mtod(m, struct icmp *); 143 if (in_cksum(m, icmplen)) { 144 icmpstat.icps_checksum++; 145 goto free; 146 } 147 148 #ifdef ICMPPRINTFS 149 /* 150 * Message type specific processing. 151 */ 152 if (icmpprintfs) 153 printf("icmp_input, type %d code %d\n", icp->icmp_type, 154 icp->icmp_code); 155 #endif 156 if (icp->icmp_type > ICMP_IREQREPLY) 157 goto free; 158 icmpstat.icps_inhist[icp->icmp_type]++; 159 code = icp->icmp_code; 160 switch (icp->icmp_type) { 161 162 case ICMP_UNREACH: 163 if (code > 5) 164 goto badcode; 165 code += PRC_UNREACH_NET; 166 goto deliver; 167 168 case ICMP_TIMXCEED: 169 if (code > 1) 170 goto badcode; 171 code += PRC_TIMXCEED_INTRANS; 172 goto deliver; 173 174 case ICMP_PARAMPROB: 175 if (code) 176 goto badcode; 177 code = PRC_PARAMPROB; 178 goto deliver; 179 180 case ICMP_SOURCEQUENCH: 181 if (code) 182 goto badcode; 183 code = PRC_QUENCH; 184 deliver: 185 /* 186 * Problem with datagram; advise higher level routines. 187 */ 188 icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len); 189 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) { 190 icmpstat.icps_badlen++; 191 goto free; 192 } 193 #ifdef ICMPPRINTFS 194 if (icmpprintfs) 195 printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); 196 #endif 197 if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput) 198 (*ctlfunc)(code, (caddr_t)icp); 199 goto free; 200 201 badcode: 202 icmpstat.icps_badcode++; 203 goto free; 204 205 case ICMP_ECHO: 206 icp->icmp_type = ICMP_ECHOREPLY; 207 goto reflect; 208 209 case ICMP_TSTAMP: 210 if (icmplen < ICMP_TSLEN) { 211 icmpstat.icps_badlen++; 212 goto free; 213 } 214 icp->icmp_type = ICMP_TSTAMPREPLY; 215 icp->icmp_rtime = iptime(); 216 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 217 goto reflect; 218 219 case ICMP_IREQ: 220 #ifdef notdef 221 /* fill in source address zero fields! */ 222 goto reflect; 223 #else 224 goto free; /* not yet implemented: ignore */ 225 #endif 226 227 case ICMP_REDIRECT: 228 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) { 229 icmpstat.icps_badlen++; 230 goto free; 231 } 232 /* 233 * Short circuit routing redirects to force 234 * immediate change in the kernel's routing 235 * tables. The message is also handed to anyone 236 * listening on a raw socket (e.g. the routing 237 * daemon for use in updating its tables). 238 */ 239 icmpdst.sin_addr = icp->icmp_gwaddr; 240 if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) { 241 icmpsrc.sin_addr = 242 if_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY); 243 rtredirect((struct sockaddr *)&icmpsrc, 244 (struct sockaddr *)&icmpdst, RTF_GATEWAY); 245 } else { 246 icmpsrc.sin_addr = icp->icmp_ip.ip_dst; 247 rtredirect((struct sockaddr *)&icmpsrc, 248 (struct sockaddr *)&icmpdst, RTF_GATEWAY | RTF_HOST); 249 } 250 /* FALL THROUGH */ 251 252 case ICMP_ECHOREPLY: 253 case ICMP_TSTAMPREPLY: 254 case ICMP_IREQREPLY: 255 icmpsrc.sin_addr = ip->ip_src; 256 icmpdst.sin_addr = ip->ip_dst; 257 raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc, 258 (struct sockaddr *)&icmpdst); 259 return; 260 261 default: 262 goto free; 263 } 264 reflect: 265 ip->ip_len += hlen; /* since ip_input deducts this */ 266 icmpstat.icps_reflect++; 267 icmp_reflect(ip); 268 return; 269 free: 270 m_freem(dtom(ip)); 271 } 272 273 /* 274 * Reflect the ip packet back to the source 275 * TODO: rearrange ip source routing options. 276 */ 277 icmp_reflect(ip) 278 struct ip *ip; 279 { 280 struct in_addr t; 281 282 t = ip->ip_dst; 283 ip->ip_dst = ip->ip_src; 284 ip->ip_src = t; 285 icmp_send(ip); 286 } 287 288 /* 289 * Send an icmp packet back to the ip level, 290 * after supplying a checksum. 291 */ 292 icmp_send(ip) 293 struct ip *ip; 294 { 295 register int hlen; 296 register struct icmp *icp; 297 register struct mbuf *m; 298 299 m = dtom(ip); 300 hlen = ip->ip_hl << 2; 301 icp = mtod(m, struct icmp *); 302 icp->icmp_cksum = 0; 303 icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 304 m->m_off -= hlen; 305 m->m_len += hlen; 306 #ifdef ICMPPRINTFS 307 if (icmpprintfs) 308 printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src); 309 #endif 310 (void) ip_output(m, (struct mbuf *)0, (struct route *)0, 0); 311 } 312 313 n_time 314 iptime() 315 { 316 int s = spl6(); 317 u_long t; 318 319 t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000; 320 splx(s); 321 return (htonl(t)); 322 } 323