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