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