1 #include "../h/param.h" 2 #include "../h/systm.h" 3 #include "../h/mbuf.h" 4 #include "../h/socket.h" 5 #include "../h/socketvar.h" 6 #include "../h/protosw.h" 7 #include "../h/syslog.h" 8 9 #include "../net/if.h" 10 #include "../net/route.h" 11 12 #include "../bbnnet/in.h" 13 #include "../bbnnet/net.h" 14 #include "../bbnnet/in_pcb.h" 15 #include "../bbnnet/in_var.h" 16 #include "../bbnnet/ip.h" 17 #include "../bbnnet/icmp.h" 18 #include "../bbnnet/nopcb.h" 19 20 extern struct ifnet *inetifp; 21 22 /* 23 * We are generating an ICMP error message in response to this packet sent 24 * to us. Too bad the device driver doesn't pair a pointer to its ifnet with 25 * the incoming packet. That would save us a search, and we could use that 26 * for our source address in the ICMP error message. 27 * 28 * Pick a source address for that ICMP error message we send. We can't 29 * always use ip_dst of the original for the ip_src of the ICMP error 30 * message since the packet may have been broadcast. 31 * 32 * We try to establish a proper interface to respond by in case we're 33 * multi-homed. Try to respond by interface received on rather than 34 * interface that represents most direct route back. 35 */ 36 struct in_addr icmp_addr (ip) 37 struct ip *ip; 38 { 39 struct in_ifaddr *ia; 40 41 #ifdef bsd42 42 /* don't want broadcasts to match */ 43 if (! (ia = in_iawithaddr(ip->ip_dst, FALSE))) 44 { 45 /* hmm, try for the net... */ 46 if ((ia = in_iawithnet(ip->ip_dst)) == NULL) 47 { 48 struct in_addr l; 49 50 /* 51 * The message will be sent by ip_send() who will 52 * route the message and discover that a local address 53 * should be set on the basis of the route used. 54 */ 55 l.s_addr = INADDR_ANY; 56 return (l); 57 } 58 } 59 #endif 60 ia = in_iafromif(inetifp); 61 return (IA_INADDR(ia)); 62 } 63 64 /* 65 * notes to above mostly apply 66 * 67 * icmp_addr() sort of assumes the packet was addressed to us. But when we 68 * act as a getway, S sends to A1, and we use A2 to get to D. We want to 69 * reply with the A1 address, not the A2 address. 70 */ 71 struct in_addr redir_addr (ip) 72 struct ip *ip; 73 { 74 register struct in_ifaddr *ia; 75 76 #ifdef bsd42 77 /* note we use ip_src, not ip_dst here */ 78 if ((ia = in_iawithnet(ip->ip_src)) == NULL) 79 { 80 struct in_addr l; 81 82 l.s_addr = INADDR_ANY; 83 return (l); 84 } 85 #endif 86 ia = in_iafromif(inetifp); 87 return (IA_INADDR(ia)); 88 } 89 90 /* 91 * There are a few icmp output routines since the header has some variable 92 * types in it ... 93 */ 94 send_redirect (redirip, use, code, icmplen) 95 struct ip *redirip; 96 struct in_addr use; 97 unsigned icmplen; 98 { 99 register struct mbuf *m; 100 int error; 101 102 if (m = m_get(M_DONTWAIT, MT_HEADER)) 103 { 104 m->m_len = ICMPSIZE + icmplen; 105 m->m_off = MMAXOFF - m->m_len; 106 { 107 register struct icmp *ic; 108 109 ic = mtod(m, struct icmp *); 110 ic->ic_type = ICMP_REDIR; 111 ic->ic_code = code; 112 ic->ic_sum = 0; 113 ic->ic_gaddr = use; 114 if (icmplen > 0) 115 bcopy ((caddr_t)redirip, ic->ic_data, icmplen); 116 117 /* used to use an inline cksum here */ 118 ic->ic_sum = in_cksum (m, m->m_len); 119 } 120 121 m->m_off -= sizeof(struct ip); 122 m->m_len += sizeof(struct ip); 123 { 124 register struct ip *ip; 125 126 ip = mtod(m, struct ip *); 127 ip->ip_p = IPPROTO_ICMP; 128 ip->ip_tos = 0; 129 ip->ip_dst = redirip->ip_src; 130 ip->ip_src = redir_addr(redirip); 131 } 132 NOPCB_IPSEND (m, (int)icmplen, FALSE, error); 133 134 #ifdef lint 135 error = error ; 136 #endif 137 } 138 } 139 140 /* 141 * Send an ICMP error message. Note that data must not exceed single mbuf. 142 */ 143 ic_errmsg (src, dst, type, code, off, dlen, dp) 144 struct in_addr src; 145 struct in_addr dst; 146 unsigned dlen; 147 caddr_t dp; /* assumed to be contiguous */ 148 { 149 register struct mbuf *m; 150 register unsigned len; 151 int error; 152 153 if ((m = m_get(M_DONTWAIT, MT_HEADER)) == NULL) 154 return /*ENOBUFS*/; 155 156 /* 157 * Build ICMP header 158 */ 159 len = ICMPSIZE + dlen; 160 m->m_off = MMAXOFF - len; 161 if (m->m_off < (MMINOFF + sizeof(struct ip))) 162 { 163 log (KERN_RECOV, "ic_errmsg len %d", len); 164 m_free (m); 165 return; 166 } 167 m->m_len = len; 168 169 /* ICMP header */ 170 { 171 register struct icmp *ic; 172 173 ic = mtod(m, struct icmp *); 174 ic->ic_type = type; 175 ic->ic_code = code; 176 ic->ic_off = off; 177 if (dlen > 0) 178 bcopy(dp, ic->ic_data, dlen); 179 ic->ic_sum = 0; 180 ic->ic_sum = in_cksum(m, len); 181 } 182 183 /* IP header */ 184 { 185 register struct ip *ip; 186 187 m->m_off -= sizeof(struct ip); 188 m->m_len += sizeof(struct ip); 189 ip = mtod(m, struct ip *); 190 ip->ip_p = IPPROTO_ICMP; 191 ip->ip_tos = 0; 192 ip->ip_src = src; 193 ip->ip_dst = dst; 194 } 195 196 NOPCB_IPSEND (m, (int)len, FALSE, error); 197 198 #ifdef lint 199 error = error; 200 #endif 201 } 202 203 #ifdef BBNPING 204 ping(gwaddr) 205 struct in_addr gwaddr; 206 { 207 register struct mbuf *m; 208 209 if ((m = m_get(M_DONTWAIT, MT_HEADER)) == NULL) 210 return; 211 m->m_off = MMAXOFF - ICMPSIZE; 212 m->m_len = ICMPSIZE; 213 { 214 register struct icmp *ic; 215 216 ic = mtod (m, struct icmp *); 217 ic->ic_type = ICMP_ECHO; 218 ic->ic_code = 0; 219 ic->ic_id = MY_ECHO_ID; 220 ic->ic_sum = 0; 221 ic->ic_sum = in_cksum(m, ICMPSIZE); 222 } 223 224 m->m_off -= sizeof(struct ip); 225 m->m_len += sizeof(struct ip); 226 { 227 register struct ip *ip; 228 229 ip = mtod(m, struct ip *); 230 ip->ip_p = IPPROTO_ICMP; 231 ip->ip_tos = 0; 232 ip->ip_dst = gwaddr; 233 ip->ip_src = icmp_addr (ip); 234 } 235 236 { 237 register int error; 238 239 NOPCB_IPSEND (m, ICMPSIZE, FALSE, error); 240 #ifdef lint 241 error = error; 242 #endif 243 } 244 } 245 #endif 246