1 /* ip_icmp.c 4.9 81/11/29 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../h/mbuf.h" 6 #include "../h/protosw.h" 7 #include "../h/clock.h" 8 #include "../net/in.h" 9 #include "../net/in_systm.h" 10 #include "../net/ip.h" 11 #include "../net/ip_icmp.h" 12 13 /* 14 * ICMP routines: error generation, receive packet processing, and 15 * routines to turnaround packets back to the originator, and 16 * host table maintenance routines. 17 */ 18 19 /* 20 * Generate an error packet of type error in response to bad packet ip. 21 */ 22 icmp_error(oip, type, code) 23 struct ip *oip; 24 int type; 25 { 26 unsigned oiplen = oip->ip_hl << 2; 27 struct icmp *icp = (struct icmp *)((int)oip + oiplen); 28 struct mbuf *m; 29 struct ip *nip; 30 COUNT(ICMP_ERROR); 31 32 /* 33 * Make sure that the old IP packet had 8 bytes of data to return; 34 * if not, don't bother. Also don't EVER error if the old 35 * packet protocol was ICMP. 36 */ 37 if (oip->ip_len - oiplen < 8 || oip->ip_p == IPPROTO_ICMP) 38 goto free; 39 40 /* 41 * Get a new mbuf, and fill in a ICMP header at the bottom 42 * of the mbuf, followed by the old IP header and 8 bytes 43 * of its data. 44 */ 45 m = m_get(0); 46 if (m == 0) 47 goto free; 48 m->m_off = MMAXOFF - (oiplen + 8); 49 icp->icmp_type = type; 50 if (type == ICMP_PARAMPROB) { 51 icp->icmp_code = 0; 52 icp->icmp_pptr = code; 53 } else 54 icp->icmp_code = code; 55 bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, oiplen + 8); 56 57 /* 58 * Now prepend an IP header and reflect this packet back to 59 * the source. 60 */ 61 m->m_off -= sizeof (struct ip); 62 m->m_len += sizeof (struct ip); 63 nip = (struct ip *)mtod(m, struct ip *); 64 *nip = *oip; 65 icmp_reflect(nip); 66 67 /* 68 * Discard mbufs of original datagram 69 */ 70 free: 71 m_freem(dtom(oip)); 72 } 73 74 /* 75 * Process a received ICMP message. 76 */ 77 icmp_input(m) 78 struct mbuf *m; 79 { 80 register struct icmp *icp; 81 register struct ip *ip = mtod(m, struct ip *); 82 int hlen = ip->ip_hl << 2; 83 int icmplen = ip->ip_len - hlen; 84 int i; 85 COUNT(ICMP_INPUT); 86 87 /* 88 * Locate icmp structure in mbuf, and check 89 * that not corrupted and of at least minimum length. 90 */ 91 m->m_len -= hlen; 92 m->m_off += hlen; 93 /* need routine to make sure header is in this mbuf here */ 94 icp = (struct icmp *)mtod(m, struct icmp *); 95 i = icp->icmp_cksum; 96 icp->icmp_cksum = 0; 97 if (i != in_cksum(m, icmplen) || icmplen < ICMP_MINLEN) 98 goto free; 99 100 /* 101 * Message type specific processing. 102 */ 103 switch (icp->icmp_type) { 104 105 case ICMP_UNREACH: 106 case ICMP_TIMXCEED: 107 case ICMP_PARAMPROB: 108 case ICMP_SOURCEQUENCH: 109 case ICMP_REDIRECT: 110 /* 111 * Problem with previous datagram; advise 112 * higher level routines. 113 */ 114 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) 115 goto free; 116 icmp_ctlinput(ip); 117 goto free; 118 119 case ICMP_ECHO: 120 icp->icmp_type = ICMP_ECHOREPLY; 121 goto reflect; 122 123 case ICMP_TSTAMP: 124 if (icmplen < ICMP_TSLEN) 125 goto free; 126 icp->icmp_type = ICMP_TSTAMPREPLY; 127 icp->icmp_rtime = iptime(); 128 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 129 goto reflect; 130 131 case ICMP_IREQ: 132 /* fill in source address zero fields! */ 133 goto reflect; 134 135 case ICMP_ECHOREPLY: 136 case ICMP_TSTAMPREPLY: 137 case ICMP_IREQREPLY: 138 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) 139 goto free; 140 icmp_gotreply(icp); 141 goto free; 142 143 default: 144 goto free; 145 } 146 reflect: 147 icmp_reflect(ip); 148 free: 149 m_freem(dtom(ip)); 150 } 151 152 /* 153 * Reflect the ip packet back to the source 154 */ 155 icmp_reflect(ip) 156 struct ip *ip; 157 { 158 struct in_addr t; 159 COUNT(ICMP_REFLECT); 160 161 t = ip->ip_src; ip->ip_dst = ip->ip_src; ip->ip_src = t; 162 /* 163 * This is a little naive... do we have to munge the options 164 * to reverse source routing? 165 */ 166 icmp_send(ip); 167 } 168 169 /* 170 * Send an icmp packet back to the ip level, after 171 * supplying a checksum. 172 */ 173 icmp_send(ip) 174 struct ip *ip; 175 { 176 struct icmp *icp = 0; /* XXX */ 177 COUNT(ICMP_SEND); 178 179 icp->icmp_cksum = 0; 180 icp->icmp_cksum = in_cksum(dtom(ip), 0); /* XXX */ 181 ip->ip_ttl = MAXTTL; 182 (void) ip_output(dtom(ip), (struct mbuf *)0); 183 } 184 185 /* 186 * Advise a higher level protocol of a problem reported by 187 * a gateway or another host. 188 */ 189 icmp_ctlinput(ip) 190 struct ip *ip; 191 { 192 extern u_char ip_protox[]; /* XXX */ 193 COUNT(ICMP_CTLINPUT); 194 195 (*protosw[ip_protox[ip->ip_p]].pr_ctlinput)(ip); 196 } 197 198 /* 199 * Got a reply, e.g. to an echo message or a timestamp 200 * message; nothing is done with these yet. 201 */ 202 /*ARGSUSED*/ 203 icmp_gotreply(icp) 204 struct icmp *icp; 205 { 206 207 COUNT(ICMP_GOTREPLY); 208 } 209 210 icmp_drain() 211 { 212 213 COUNT(ICMP_DRAIN); 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