1 /* ip_icmp.c 4.22 82/10/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 <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 #if vax || pdp11 || ns16032 67 nip->ip_len = htons((u_short)nip->ip_len); 68 #endif 69 70 /* 71 * Now, copy old ip header in front of icmp 72 * message. This allows us to reuse any source 73 * routing info present. 74 */ 75 m->m_off -= oiplen; 76 nip = mtod(m, struct ip *); 77 bcopy((caddr_t)oip, (caddr_t)nip, oiplen); 78 nip->ip_len = m->m_len + oiplen; 79 nip->ip_p = IPPROTO_ICMP; 80 /* icmp_send adds ip header to m_off and m_len, so we deduct here */ 81 m->m_off += oiplen; 82 icmp_reflect(nip); 83 84 free: 85 m_freem(dtom(oip)); 86 } 87 88 static char icmpmap[] = { 89 -1, -1, -1, 90 PRC_UNREACH_NET, PRC_QUENCH, PRC_REDIRECT_NET, 91 -1, -1, -1, 92 -1, -1, PRC_TIMXCEED_INTRANS, 93 PRC_PARAMPROB, -1, -1, 94 -1, -1 95 }; 96 97 static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP }; 98 static struct sockaddr_in icmpsrc = { AF_INET }; 99 static struct sockaddr_in icmpdst = { AF_INET }; 100 101 /* 102 * Process a received ICMP message. 103 */ 104 icmp_input(m) 105 struct mbuf *m; 106 { 107 register struct icmp *icp; 108 register struct ip *ip = mtod(m, struct ip *); 109 int icmplen = ip->ip_len, hlen = ip->ip_hl << 2, i, (*ctlfunc)(); 110 extern u_char ip_protox[]; 111 112 /* 113 * Locate icmp structure in mbuf, and check 114 * that not corrupted and of at least minimum length. 115 */ 116 if (icmpprintfs) 117 printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen); 118 if (icmplen < ICMP_MINLEN) 119 goto free; 120 m->m_len -= hlen; 121 m->m_off += hlen; 122 /* need routine to make sure header is in this mbuf here */ 123 icp = mtod(m, struct icmp *); 124 i = icp->icmp_cksum; 125 icp->icmp_cksum = 0; 126 if (i != in_cksum(m, icmplen)) { 127 printf("icmp: cksum %x\n", i); 128 goto free; 129 } 130 131 /* 132 * Message type specific processing. 133 */ 134 if (icmpprintfs) 135 printf("icmp_input, type %d code %d\n", icp->icmp_type, 136 icp->icmp_code); 137 switch (i = icp->icmp_type) { 138 139 case ICMP_UNREACH: 140 case ICMP_TIMXCEED: 141 case ICMP_PARAMPROB: 142 case ICMP_REDIRECT: 143 case ICMP_SOURCEQUENCH: 144 /* 145 * Problem with previous datagram; advise 146 * higher level routines. 147 */ 148 #if vax || pdp11 || ns16032 149 icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len); 150 #endif 151 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) 152 goto free; 153 if (icmpprintfs) 154 printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); 155 if (ctlfunc = protosw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput) 156 (*ctlfunc)(icmpmap[i] + icp->icmp_code, (caddr_t)icp); 157 goto free; 158 159 case ICMP_ECHO: 160 icp->icmp_type = ICMP_ECHOREPLY; 161 goto reflect; 162 163 case ICMP_TSTAMP: 164 if (icmplen < ICMP_TSLEN) 165 goto free; 166 icp->icmp_type = ICMP_TSTAMPREPLY; 167 icp->icmp_rtime = iptime(); 168 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 169 goto reflect; 170 171 case ICMP_IREQ: 172 /* fill in source address zero fields! */ 173 goto reflect; 174 175 case ICMP_ECHOREPLY: 176 case ICMP_TSTAMPREPLY: 177 case ICMP_IREQREPLY: 178 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) 179 goto free; 180 icmpsrc.sin_addr = ip->ip_src; 181 icmpdst.sin_addr = ip->ip_dst; 182 raw_input(dtom(icp), &icmproto, (struct sockaddr *)&icmpsrc, 183 (struct sockaddr *)&icmpdst); 184 goto free; 185 186 default: 187 goto free; 188 } 189 reflect: 190 icmp_reflect(ip); 191 free: 192 m_freem(dtom(ip)); 193 } 194 195 /* 196 * Reflect the ip packet back to the source 197 * TODO: rearrange ip source routing options. 198 */ 199 icmp_reflect(ip) 200 struct ip *ip; 201 { 202 struct in_addr t; 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 if (!generateicmpmsgs) 224 return; 225 icp = mtod(m, struct icmp *); 226 icp->icmp_cksum = 0; 227 icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); 228 m->m_off -= hlen; 229 m->m_len += hlen; 230 if (icmpprintfs) 231 printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src); 232 (void) ip_output(m, (struct mbuf *)0, (struct route *)0, 0); 233 } 234 235 n_time 236 iptime() 237 { 238 int s = spl6(); 239 u_long t; 240 241 t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000; 242 splx(s); 243 return (htonl(t)); 244 } 245