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