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