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