1 /* ip_icmp.c 4.24 82/11/03 */ 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); 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, i, (*ctlfunc)(); 108 extern u_char ip_protox[]; 109 110 /* 111 * Locate icmp structure in mbuf, and check 112 * that not corrupted and of at least minimum length. 113 */ 114 if (icmpprintfs) 115 printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen); 116 if (icmplen < ICMP_MINLEN) 117 goto free; 118 m->m_len -= hlen; 119 m->m_off += hlen; 120 /* need routine to make sure header is in this mbuf here */ 121 icp = mtod(m, struct icmp *); 122 i = icp->icmp_cksum; 123 icp->icmp_cksum = 0; 124 if (i != in_cksum(m, icmplen)) { 125 printf("icmp: cksum %x\n", i); 126 goto free; 127 } 128 129 /* 130 * Message type specific processing. 131 */ 132 if (icmpprintfs) 133 printf("icmp_input, type %d code %d\n", icp->icmp_type, 134 icp->icmp_code); 135 switch (i = icp->icmp_type) { 136 137 case ICMP_UNREACH: 138 case ICMP_TIMXCEED: 139 case ICMP_PARAMPROB: 140 case ICMP_REDIRECT: 141 case ICMP_SOURCEQUENCH: 142 /* 143 * Problem with previous datagram; advise 144 * higher level routines. 145 */ 146 icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len); 147 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) 148 goto free; 149 if (icmpprintfs) 150 printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); 151 if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput) 152 (*ctlfunc)(icmpmap[i] + icp->icmp_code, (caddr_t)icp); 153 goto free; 154 155 case ICMP_ECHO: 156 icp->icmp_type = ICMP_ECHOREPLY; 157 goto reflect; 158 159 case ICMP_TSTAMP: 160 if (icmplen < ICMP_TSLEN) 161 goto free; 162 icp->icmp_type = ICMP_TSTAMPREPLY; 163 icp->icmp_rtime = iptime(); 164 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 165 goto reflect; 166 167 case ICMP_IREQ: 168 /* fill in source address zero fields! */ 169 goto reflect; 170 171 case ICMP_ECHOREPLY: 172 case ICMP_TSTAMPREPLY: 173 case ICMP_IREQREPLY: 174 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) 175 goto free; 176 icmpsrc.sin_addr = ip->ip_src; 177 icmpdst.sin_addr = ip->ip_dst; 178 raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc, 179 (struct sockaddr *)&icmpdst); 180 goto free; 181 182 default: 183 goto free; 184 } 185 reflect: 186 icmp_reflect(ip); 187 free: 188 m_freem(dtom(ip)); 189 } 190 191 /* 192 * Reflect the ip packet back to the source 193 * TODO: rearrange ip source routing options. 194 */ 195 icmp_reflect(ip) 196 struct ip *ip; 197 { 198 struct in_addr t; 199 200 t = ip->ip_dst; 201 ip->ip_dst = ip->ip_src; 202 ip->ip_src = t; 203 icmp_send(ip); 204 } 205 206 int generateicmpmsgs = 1; 207 208 /* 209 * Send an icmp packet back to the ip level, 210 * after supplying a checksum. 211 */ 212 icmp_send(ip) 213 struct ip *ip; 214 { 215 register int hlen = ip->ip_hl << 2; 216 register struct icmp *icp; 217 register struct mbuf *m = dtom(ip); 218 219 if (!generateicmpmsgs) 220 return; 221 icp = mtod(m, struct icmp *); 222 icp->icmp_cksum = 0; 223 icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 224 m->m_off -= hlen; 225 m->m_len += hlen; 226 if (icmpprintfs) 227 printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src); 228 (void) ip_output(m, (struct mbuf *)0, (struct route *)0, 0); 229 } 230 231 n_time 232 iptime() 233 { 234 int s = spl6(); 235 u_long t; 236 237 t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000; 238 splx(s); 239 return (htonl(t)); 240 } 241