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 
66 
67 struct in_addr ping_addr (ip)
68 struct ip	*ip;
69 {
70     struct in_ifaddr *ia;
71 
72     /* don't want broadcasts to match */
73     if (! (ia = in_iawithaddr(ip->ip_dst, FALSE)))
74     {
75 	/* hmm, try for the net... */
76 	if ((ia = in_iawithnet(ip->ip_dst)) == NULL)
77 	{
78 	    struct in_addr l;
79 
80 	    /*
81 	     * The message will be sent by ip_send() who will
82 	     * route the message and discover that a local address
83 	     * should be set on the basis of the route used.
84 	     */
85 	    l.s_addr = INADDR_ANY;
86 	    return (l);
87 	}
88     }
89     return (IA_INADDR(ia));
90 }
91 
92 /*
93  * notes to above mostly apply
94  *
95  * icmp_addr() sort of assumes the packet was addressed to us.  But when we
96  * act as a getway, S sends to A1, and we use A2 to get to D.  We want to
97  * reply with the A1 address, not the A2 address.
98  */
99 struct in_addr redir_addr (ip)
100 struct ip	*ip;
101 {
102     register struct in_ifaddr *ia;
103 
104 #ifdef bsd42
105     /* note we use ip_src, not ip_dst here */
106     if ((ia = in_iawithnet(ip->ip_src)) == NULL)
107     {
108 	struct in_addr l;
109 
110 	l.s_addr = INADDR_ANY;
111 	return (l);
112     }
113 #endif
114     ia = in_iafromif(inetifp);
115     return (IA_INADDR(ia));
116 }
117 
118 /*
119  * There are a few icmp output routines since the header has some variable
120  * types in it ...
121  */
122 send_redirect (redirip, use, code, icmplen)
123 struct ip	*redirip;
124 struct in_addr	 use;
125 unsigned icmplen;
126 {
127     register struct mbuf	*m;
128     int error;
129 
130     if (m = m_get(M_DONTWAIT, MT_HEADER))
131     {
132 	m->m_len = ICMPSIZE + icmplen;
133 	m->m_off = MMAXOFF - m->m_len;
134 	{
135 	register struct icmp	*ic;
136 
137 	ic = mtod(m, struct icmp *);
138 	ic->ic_type = ICMP_REDIR;
139 	ic->ic_code = code;
140 	ic->ic_sum = 0;
141 	ic->ic_gaddr = use;
142 	if (icmplen > 0)
143 	    bcopy ((caddr_t)redirip, ic->ic_data, icmplen);
144 
145 	/* used to use an inline cksum here  */
146 	ic->ic_sum = in_cksum (m, m->m_len);
147 	}
148 
149 	m->m_off -= sizeof(struct ip);
150 	m->m_len += sizeof(struct ip);
151 	{
152 	register struct ip	*ip;
153 
154 	ip = mtod(m, struct ip *);
155 	ip->ip_p = IPPROTO_ICMP;
156 	ip->ip_tos = 0;
157 	ip->ip_dst = redirip->ip_src;
158 	ip->ip_src = redir_addr(redirip);
159 	}
160 	NOPCB_IPSEND (m, (int)icmplen, FALSE, error);
161 
162 #ifdef lint
163 	error = error ;
164 #endif
165     }
166 }
167 
168 /*
169  * Send an ICMP error message.  Note that data must not exceed single mbuf.
170  */
171 ic_errmsg (src, dst, type, code, off, dlen, dp)
172 struct in_addr	 src;
173 struct in_addr  dst;
174 unsigned dlen;
175 caddr_t dp;	/* assumed to be contiguous */
176 {
177     register struct mbuf	*m;
178     register unsigned	 len;
179     int error;
180 
181     if ((m = m_get(M_DONTWAIT, MT_HEADER)) == NULL)
182 	return /*ENOBUFS*/;
183 
184     /*
185      * Build ICMP header
186      */
187     len = ICMPSIZE + dlen;
188     m->m_off = MMAXOFF - len;
189     if (m->m_off < (MMINOFF + sizeof(struct ip)))
190     {
191 	log (LOG_INFO, "ic_errmsg len %d", len);
192 	m_free (m);
193 	return;
194     }
195     m->m_len = len;
196 
197     /* ICMP header */
198     {
199 	register struct icmp	*ic;
200 
201 	ic = mtod(m, struct icmp *);
202 	ic->ic_type	= type;
203 	ic->ic_code	= code;
204 	ic->ic_off	= off;
205 	if (dlen > 0)
206 	    bcopy(dp, ic->ic_data, dlen);
207 	ic->ic_sum	= 0;
208 	ic->ic_sum	= in_cksum(m, len);
209     }
210 
211     /* IP header */
212     {
213 	register struct ip	*ip;
214 
215 	m->m_off -= sizeof(struct ip);
216 	m->m_len += sizeof(struct ip);
217 	ip = mtod(m, struct ip *);
218 	ip->ip_p	= IPPROTO_ICMP;
219 	ip->ip_tos	= 0;
220 	ip->ip_src	= src;
221 	ip->ip_dst	= dst;
222     }
223 
224     NOPCB_IPSEND (m, (int)len, FALSE, error);
225 
226 #ifdef lint
227     error = error;
228 #endif
229 }
230 
231 #ifdef BBNPING
232 ping(gwaddr)
233 struct in_addr gwaddr;
234 {
235     register struct mbuf *m;
236 
237     if ((m = m_get(M_DONTWAIT, MT_HEADER)) == NULL)
238 	return;
239     m->m_off = MMAXOFF - ICMPSIZE;
240     m->m_len = ICMPSIZE;
241     {
242 	register struct icmp *ic;
243 
244 	ic = mtod (m, struct icmp *);
245 	ic->ic_type	= ICMP_ECHO;
246 	ic->ic_code	= 0;
247 	ic->ic_id	= MY_ECHO_ID;
248 	ic->ic_sum	= 0;
249 	ic->ic_sum	= in_cksum(m, ICMPSIZE);
250     }
251 
252     m->m_off -= sizeof(struct ip);
253     m->m_len += sizeof(struct ip);
254     {
255 	register struct ip *ip;
256 
257 	ip = mtod(m, struct ip *);
258 	ip->ip_p	= IPPROTO_ICMP;
259 	ip->ip_tos	= 0;
260 	ip->ip_dst	= gwaddr;
261 	ip->ip_src	= ping_addr (ip);
262     }
263 
264     {
265 	register int error;
266 
267 	NOPCB_IPSEND (m, ICMPSIZE, FALSE, error);
268 #ifdef lint
269 	error = error;
270 #endif
271     }
272 }
273 #endif
274