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