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