1 /* ip_icmp.c 4.12 82/01/19 */ 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(M_DONTWAIT); 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 return; 67 68 /* 69 * Discard mbufs of original datagram 70 */ 71 free: 72 m_freem(dtom(oip)); 73 } 74 75 /* 76 * Process a received ICMP message. 77 */ 78 icmp_input(m) 79 struct mbuf *m; 80 { 81 register struct icmp *icp; 82 register struct ip *ip = mtod(m, struct ip *); 83 int hlen = ip->ip_hl << 2; 84 int icmplen = ip->ip_len - hlen; 85 int i; 86 extern u_char ip_protox[]; 87 COUNT(ICMP_INPUT); 88 89 /* 90 * Locate icmp structure in mbuf, and check 91 * that not corrupted and of at least minimum length. 92 */ 93 m->m_len -= hlen; 94 m->m_off += hlen; 95 /* need routine to make sure header is in this mbuf here */ 96 icp = (struct icmp *)mtod(m, struct icmp *); 97 i = icp->icmp_cksum; 98 icp->icmp_cksum = 0; 99 if (i != in_cksum(m, icmplen) || icmplen < ICMP_MINLEN) 100 goto free; 101 102 /* 103 * Message type specific processing. 104 */ 105 switch (icp->icmp_type) { 106 107 case ICMP_UNREACH: 108 case ICMP_TIMXCEED: 109 case ICMP_PARAMPROB: 110 case ICMP_SOURCEQUENCH: 111 case ICMP_REDIRECT: 112 /* 113 * Problem with previous datagram; advise 114 * higher level routines. 115 */ 116 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) 117 goto free; 118 (*protosw[ip_protox[ip->ip_p]].pr_ctlinput)(m); 119 goto free; 120 121 case ICMP_ECHO: 122 icp->icmp_type = ICMP_ECHOREPLY; 123 goto reflect; 124 125 case ICMP_TSTAMP: 126 if (icmplen < ICMP_TSLEN) 127 goto free; 128 icp->icmp_type = ICMP_TSTAMPREPLY; 129 icp->icmp_rtime = iptime(); 130 icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ 131 goto reflect; 132 133 case ICMP_IREQ: 134 /* fill in source address zero fields! */ 135 goto reflect; 136 137 case ICMP_ECHOREPLY: 138 case ICMP_TSTAMPREPLY: 139 case ICMP_IREQREPLY: 140 if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) 141 goto free; 142 icmp_gotreply(icp); 143 goto free; 144 145 default: 146 goto free; 147 } 148 reflect: 149 icmp_reflect(ip); 150 free: 151 m_freem(dtom(ip)); 152 } 153 154 /* 155 * Reflect the ip packet back to the source 156 */ 157 icmp_reflect(ip) 158 struct ip *ip; 159 { 160 struct in_addr t; 161 COUNT(ICMP_REFLECT); 162 163 t = ip->ip_src; ip->ip_dst = ip->ip_src; ip->ip_src = t; 164 /* 165 * This is a little naive... do we have to munge the options 166 * to reverse source routing? 167 */ 168 icmp_send(ip); 169 } 170 171 /* 172 * Send an icmp packet back to the ip level, after 173 * supplying a checksum. 174 */ 175 icmp_send(ip) 176 struct ip *ip; 177 { 178 COUNT(ICMP_SEND); 179 180 m_freem(dtom(ip)); 181 } 182 183 icmp_ctlinput(m) 184 struct mbuf *m; 185 { 186 COUNT(ICMP_CTLINPUT); 187 188 m_freem(m); 189 } 190 191 /* 192 * Got a reply, e.g. to an echo message or a timestamp 193 * message; nothing is done with these yet. 194 */ 195 /*ARGSUSED*/ 196 icmp_gotreply(icp) 197 struct icmp *icp; 198 { 199 200 COUNT(ICMP_GOTREPLY); 201 } 202 203 icmp_drain() 204 { 205 206 COUNT(ICMP_DRAIN); 207 } 208 209 n_time 210 iptime() 211 { 212 int s = spl6(); 213 u_long t; 214 215 COUNT(IPTIME); 216 t = (time % SECDAY) * 1000 + lbolt * hz; 217 splx(s); 218 return (htonl(t)); 219 } 220