1 /* ip_icmp.c 4.16 82/05/02 */ 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/clock.h" 9 #include "../net/in.h" 10 #include "../net/in_systm.h" 11 #include "../net/ip.h" 12 #include "../net/ip_icmp.h" 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 int icmpprintfs = 0; 20 21 /* 22 * Generate an error packet of type error 23 * in response to bad packet ip. 24 */ 25 icmp_error(oip, type, code) 26 struct ip *oip; 27 int type, code; 28 { 29 register unsigned oiplen = oip->ip_hl << 2; 30 register struct icmp *icp; 31 struct mbuf *m; 32 struct ip *nip; 33 COUNT(ICMP_ERROR); 34 35 if (icmpprintfs) 36 printf("icmp_error(%x, %d, %d)\n", oip, type, code); 37 /* 38 * Make sure that the old IP packet had 8 bytes of data to return; 39 * if not, don't bother. Also don't EVER error if the old 40 * packet protocol was ICMP. 41 */ 42 if (oip->ip_len < 8 || oip->ip_p == IPPROTO_ICMP) 43 goto free; 44 45 /* 46 * First, formulate icmp message 47 */ 48 m = m_get(M_DONTWAIT); 49 if (m == 0) 50 goto free; 51 m->m_len = oiplen + 8 + ICMP_MINLEN; 52 m->m_off = MMAXOFF - m->m_len; 53 icp = mtod(m, struct icmp *); 54 icp->icmp_type = type; 55 icp->icmp_void = 0; 56 if (type == ICMP_PARAMPROB) { 57 icp->icmp_pptr = code; 58 code = 0; 59 } 60 icp->icmp_code = code; 61 bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8); 62 nip = &icp->icmp_ip; 63 nip->ip_len += oiplen; 64 #if vax || pdp11 65 nip->ip_len = htons((u_short)nip->ip_len); 66 #endif 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 COUNT(ICMP_INPUT); 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 #if vax || pdp11 148 icp->icmp_ip.ip_len = ntohs(icp->icmp_ip.ip_len); 149 #endif 150 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) 151 goto free; 152 if (icmpprintfs) 153 printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); 154 if (ctlfunc = protosw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput) 155 (*ctlfunc)(icmpmap[i] + icp->icmp_code, (caddr_t)icp); 156 goto free; 157 158 case ICMP_ECHO: 159 icp->icmp_type = ICMP_ECHOREPLY; 160 goto reflect; 161 162 case ICMP_TSTAMP: 163 if (icmplen < ICMP_TSLEN) 164 goto free; 165 icp->icmp_type = ICMP_TSTAMPREPLY; 166 icp->icmp_rtime = iptime(); 167 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 168 goto reflect; 169 170 case ICMP_IREQ: 171 /* fill in source address zero fields! */ 172 goto reflect; 173 174 case ICMP_ECHOREPLY: 175 case ICMP_TSTAMPREPLY: 176 case ICMP_IREQREPLY: 177 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) 178 goto free; 179 icmpsrc.sin_addr = ip->ip_src; 180 icmpdst.sin_addr = ip->ip_dst; 181 raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc, 182 (struct sockaddr *)&icmpdst); 183 goto free; 184 185 default: 186 goto free; 187 } 188 reflect: 189 icmp_reflect(ip); 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 COUNT(ICMP_REFLECT); 203 204 t = ip->ip_dst; 205 ip->ip_dst = ip->ip_src; 206 ip->ip_src = t; 207 icmp_send(ip); 208 } 209 210 int generateicmpmsgs = 1; 211 212 /* 213 * Send an icmp packet back to the ip level, 214 * after supplying a checksum. 215 */ 216 icmp_send(ip) 217 struct ip *ip; 218 { 219 register int hlen = ip->ip_hl << 2; 220 register struct icmp *icp; 221 register struct mbuf *m = dtom(ip); 222 223 COUNT(ICMP_SEND); 224 if (!generateicmpmsgs) 225 return; 226 icp = mtod(m, struct icmp *); 227 icp->icmp_cksum = 0; 228 icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 229 m->m_off -= hlen; 230 m->m_len += hlen; 231 if (icmpprintfs) 232 printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src); 233 (void) ip_output(m, 0, 0, 0); 234 } 235 236 n_time 237 iptime() 238 { 239 int s = spl6(); 240 u_long t; 241 242 COUNT(IPTIME); 243 t = (time % SECDAY) * 1000 + lbolt * hz; 244 splx(s); 245 return (htonl(t)); 246 } 247