1 |
27 |
unneback |
//==========================================================================
|
2 |
|
|
//
|
3 |
|
|
// sys/netinet/if_ether.c
|
4 |
|
|
//
|
5 |
|
|
//
|
6 |
|
|
//
|
7 |
|
|
//==========================================================================
|
8 |
|
|
//####BSDCOPYRIGHTBEGIN####
|
9 |
|
|
//
|
10 |
|
|
// -------------------------------------------
|
11 |
|
|
//
|
12 |
|
|
// Portions of this software may have been derived from OpenBSD or other sources,
|
13 |
|
|
// and are covered by the appropriate copyright disclaimers included herein.
|
14 |
|
|
//
|
15 |
|
|
// -------------------------------------------
|
16 |
|
|
//
|
17 |
|
|
//####BSDCOPYRIGHTEND####
|
18 |
|
|
//==========================================================================
|
19 |
|
|
//#####DESCRIPTIONBEGIN####
|
20 |
|
|
//
|
21 |
|
|
// Author(s): gthomas
|
22 |
|
|
// Contributors: gthomas
|
23 |
|
|
// Date: 2000-01-10
|
24 |
|
|
// Purpose:
|
25 |
|
|
// Description:
|
26 |
|
|
//
|
27 |
|
|
//
|
28 |
|
|
//####DESCRIPTIONEND####
|
29 |
|
|
//
|
30 |
|
|
//==========================================================================
|
31 |
|
|
|
32 |
|
|
|
33 |
|
|
/* $OpenBSD: if_ether.c,v 1.19 1999/11/10 18:48:47 chris Exp $ */
|
34 |
|
|
/* $NetBSD: if_ether.c,v 1.31 1996/05/11 12:59:58 mycroft Exp $ */
|
35 |
|
|
|
36 |
|
|
/*
|
37 |
|
|
* Copyright (c) 1982, 1986, 1988, 1993
|
38 |
|
|
* The Regents of the University of California. All rights reserved.
|
39 |
|
|
*
|
40 |
|
|
* Redistribution and use in source and binary forms, with or without
|
41 |
|
|
* modification, are permitted provided that the following conditions
|
42 |
|
|
* are met:
|
43 |
|
|
* 1. Redistributions of source code must retain the above copyright
|
44 |
|
|
* notice, this list of conditions and the following disclaimer.
|
45 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
46 |
|
|
* notice, this list of conditions and the following disclaimer in the
|
47 |
|
|
* documentation and/or other materials provided with the distribution.
|
48 |
|
|
* 3. All advertising materials mentioning features or use of this software
|
49 |
|
|
* must display the following acknowledgement:
|
50 |
|
|
* This product includes software developed by the University of
|
51 |
|
|
* California, Berkeley and its contributors.
|
52 |
|
|
* 4. Neither the name of the University nor the names of its contributors
|
53 |
|
|
* may be used to endorse or promote products derived from this software
|
54 |
|
|
* without specific prior written permission.
|
55 |
|
|
*
|
56 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
57 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
58 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
59 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
60 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
61 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
62 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
63 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
64 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
65 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
66 |
|
|
* SUCH DAMAGE.
|
67 |
|
|
*
|
68 |
|
|
* @(#)if_ether.c 8.1 (Berkeley) 6/10/93
|
69 |
|
|
*/
|
70 |
|
|
|
71 |
|
|
/*
|
72 |
|
|
* Ethernet address resolution protocol.
|
73 |
|
|
* TODO:
|
74 |
|
|
* add "inuse/lock" bit (or ref. count) along with valid bit
|
75 |
|
|
*/
|
76 |
|
|
|
77 |
|
|
#include <sys/param.h>
|
78 |
|
|
#ifndef __ECOS
|
79 |
|
|
#include <sys/systm.h>
|
80 |
|
|
#endif
|
81 |
|
|
#include <sys/malloc.h>
|
82 |
|
|
#include <sys/mbuf.h>
|
83 |
|
|
#include <sys/socket.h>
|
84 |
|
|
#include <sys/time.h>
|
85 |
|
|
#include <sys/kernel.h>
|
86 |
|
|
#include <sys/errno.h>
|
87 |
|
|
#include <sys/ioctl.h>
|
88 |
|
|
#ifndef __ECOS
|
89 |
|
|
#include <sys/syslog.h>
|
90 |
|
|
#include <sys/proc.h>
|
91 |
|
|
#endif
|
92 |
|
|
|
93 |
|
|
#ifdef INET
|
94 |
|
|
|
95 |
|
|
#include <net/if.h>
|
96 |
|
|
#include <net/if_dl.h>
|
97 |
|
|
#include <net/route.h>
|
98 |
|
|
|
99 |
|
|
#include <netinet/in.h>
|
100 |
|
|
#include <netinet/in_systm.h>
|
101 |
|
|
#include <netinet/in_var.h>
|
102 |
|
|
#include <netinet/ip.h>
|
103 |
|
|
#include <netinet/if_ether.h>
|
104 |
|
|
|
105 |
|
|
#define SIN(s) ((struct sockaddr_in *)s)
|
106 |
|
|
#define SDL(s) ((struct sockaddr_dl *)s)
|
107 |
|
|
#define SRP(s) ((struct sockaddr_inarp *)s)
|
108 |
|
|
|
109 |
|
|
/*
|
110 |
|
|
* ARP trailer negotiation. Trailer protocol is not IP specific,
|
111 |
|
|
* but ARP request/response use IP addresses.
|
112 |
|
|
*/
|
113 |
|
|
#define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL
|
114 |
|
|
|
115 |
|
|
/* timer values */
|
116 |
|
|
int arpt_prune = (5*60*1); /* walk list every 5 minutes */
|
117 |
|
|
int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */
|
118 |
|
|
int arpt_down = 20; /* once declared down, don't send for 20 secs */
|
119 |
|
|
#define rt_expire rt_rmx.rmx_expire
|
120 |
|
|
|
121 |
|
|
static void arprequest
|
122 |
|
|
__P((struct arpcom *, u_int32_t *, u_int32_t *, u_int8_t *));
|
123 |
|
|
static void arptfree __P((struct llinfo_arp *));
|
124 |
|
|
static void arptimer __P((void *));
|
125 |
|
|
static struct llinfo_arp *arplookup __P((u_int32_t, int, int));
|
126 |
|
|
static void in_arpinput __P((struct mbuf *));
|
127 |
|
|
|
128 |
|
|
extern struct ifnet loif;
|
129 |
|
|
LIST_HEAD(, llinfo_arp) llinfo_arp;
|
130 |
|
|
struct ifqueue arpintrq = {0, 0, 0, 50};
|
131 |
|
|
int arp_inuse, arp_allocated, arp_intimer;
|
132 |
|
|
int arp_maxtries = 5;
|
133 |
|
|
int useloopback = 1; /* use loopback interface for local traffic */
|
134 |
|
|
int arpinit_done = 0;
|
135 |
|
|
|
136 |
|
|
/* revarp state */
|
137 |
|
|
static struct in_addr myip, srv_ip;
|
138 |
|
|
static int myip_initialized = 0;
|
139 |
|
|
static int revarp_in_progress = 0;
|
140 |
|
|
struct ifnet *myip_ifp = NULL;
|
141 |
|
|
|
142 |
|
|
static void arptimer __P((void *));
|
143 |
|
|
static void arprequest __P((struct arpcom *, u_int32_t *, u_int32_t *,
|
144 |
|
|
u_int8_t *));
|
145 |
|
|
static void in_arpinput __P((struct mbuf *));
|
146 |
|
|
static void arptfree __P((struct llinfo_arp *));
|
147 |
|
|
static struct llinfo_arp *arplookup __P((u_int32_t, int, int ));
|
148 |
|
|
#ifdef DDB
|
149 |
|
|
#include <vm/vm.h>
|
150 |
|
|
|
151 |
|
|
static void db_print_sa __P((struct sockaddr *));
|
152 |
|
|
static void db_print_ifa __P((struct ifaddr *));
|
153 |
|
|
static void db_print_llinfo __P((caddr_t));
|
154 |
|
|
static int db_show_radix_node __P((struct radix_node *, void *));
|
155 |
|
|
#endif
|
156 |
|
|
|
157 |
|
|
/*
|
158 |
|
|
* Timeout routine. Age arp_tab entries periodically.
|
159 |
|
|
*/
|
160 |
|
|
/* ARGSUSED */
|
161 |
|
|
static void
|
162 |
|
|
arptimer(arg)
|
163 |
|
|
void *arg;
|
164 |
|
|
{
|
165 |
|
|
int s;
|
166 |
|
|
register struct llinfo_arp *la, *nla;
|
167 |
|
|
|
168 |
|
|
s = splsoftnet();
|
169 |
|
|
timeout(arptimer, NULL, arpt_prune * hz);
|
170 |
|
|
for (la = llinfo_arp.lh_first; la != 0; la = nla) {
|
171 |
|
|
register struct rtentry *rt = la->la_rt;
|
172 |
|
|
|
173 |
|
|
nla = la->la_list.le_next;
|
174 |
|
|
if (rt->rt_expire && rt->rt_expire <= time.tv_sec)
|
175 |
|
|
arptfree(la); /* timer has expired; clear */
|
176 |
|
|
}
|
177 |
|
|
splx(s);
|
178 |
|
|
}
|
179 |
|
|
|
180 |
|
|
/*
|
181 |
|
|
* Parallel to llc_rtrequest.
|
182 |
|
|
*/
|
183 |
|
|
void
|
184 |
|
|
arp_rtrequest(req, rt, sa)
|
185 |
|
|
int req;
|
186 |
|
|
register struct rtentry *rt;
|
187 |
|
|
struct sockaddr *sa;
|
188 |
|
|
{
|
189 |
|
|
register struct sockaddr *gate = rt->rt_gateway;
|
190 |
|
|
register struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
|
191 |
|
|
static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
|
192 |
|
|
|
193 |
|
|
if (!arpinit_done) {
|
194 |
|
|
arpinit_done = 1;
|
195 |
|
|
/*
|
196 |
|
|
* We generate expiration times from time.tv_sec
|
197 |
|
|
* so avoid accidently creating permanent routes.
|
198 |
|
|
*/
|
199 |
|
|
if (time.tv_sec == 0) {
|
200 |
|
|
time.tv_sec++;
|
201 |
|
|
}
|
202 |
|
|
timeout(arptimer, (caddr_t)0, hz);
|
203 |
|
|
}
|
204 |
|
|
if (rt->rt_flags & RTF_GATEWAY)
|
205 |
|
|
return;
|
206 |
|
|
switch (req) {
|
207 |
|
|
|
208 |
|
|
case RTM_ADD:
|
209 |
|
|
/*
|
210 |
|
|
* XXX: If this is a manually added route to interface
|
211 |
|
|
* such as older version of routed or gated might provide,
|
212 |
|
|
* restore cloning bit.
|
213 |
|
|
*/
|
214 |
|
|
if ((rt->rt_flags & RTF_HOST) == 0 &&
|
215 |
|
|
SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
|
216 |
|
|
rt->rt_flags |= RTF_CLONING;
|
217 |
|
|
if (rt->rt_flags & RTF_CLONING) {
|
218 |
|
|
/*
|
219 |
|
|
* Case 1: This route should come from a route to iface.
|
220 |
|
|
*/
|
221 |
|
|
rt_setgate(rt, rt_key(rt),
|
222 |
|
|
(struct sockaddr *)&null_sdl);
|
223 |
|
|
gate = rt->rt_gateway;
|
224 |
|
|
SDL(gate)->sdl_type = rt->rt_ifp->if_type;
|
225 |
|
|
SDL(gate)->sdl_index = rt->rt_ifp->if_index;
|
226 |
|
|
/*
|
227 |
|
|
* Give this route an expiration time, even though
|
228 |
|
|
* it's a "permanent" route, so that routes cloned
|
229 |
|
|
* from it do not need their expiration time set.
|
230 |
|
|
*/
|
231 |
|
|
rt->rt_expire = time.tv_sec;
|
232 |
|
|
break;
|
233 |
|
|
}
|
234 |
|
|
/* Announce a new entry if requested. */
|
235 |
|
|
if (rt->rt_flags & RTF_ANNOUNCE)
|
236 |
|
|
arprequest((struct arpcom *)rt->rt_ifp,
|
237 |
|
|
&SIN(rt_key(rt))->sin_addr.s_addr,
|
238 |
|
|
&SIN(rt_key(rt))->sin_addr.s_addr,
|
239 |
|
|
(u_char *)LLADDR(SDL(gate)));
|
240 |
|
|
/*FALLTHROUGH*/
|
241 |
|
|
case RTM_RESOLVE:
|
242 |
|
|
if (gate->sa_family != AF_LINK ||
|
243 |
|
|
gate->sa_len < sizeof(null_sdl)) {
|
244 |
|
|
#ifdef __ECOS
|
245 |
|
|
#else
|
246 |
|
|
log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n");
|
247 |
|
|
#endif
|
248 |
|
|
break;
|
249 |
|
|
}
|
250 |
|
|
SDL(gate)->sdl_type = rt->rt_ifp->if_type;
|
251 |
|
|
SDL(gate)->sdl_index = rt->rt_ifp->if_index;
|
252 |
|
|
if (la != 0)
|
253 |
|
|
break; /* This happens on a route change */
|
254 |
|
|
/*
|
255 |
|
|
* Case 2: This route may come from cloning, or a manual route
|
256 |
|
|
* add with a LL address.
|
257 |
|
|
*/
|
258 |
|
|
R_Malloc(la, struct llinfo_arp *, sizeof(*la));
|
259 |
|
|
rt->rt_llinfo = (caddr_t)la;
|
260 |
|
|
if (la == 0) {
|
261 |
|
|
#ifdef __ECOS
|
262 |
|
|
#else
|
263 |
|
|
log(LOG_DEBUG, "arp_rtrequest: malloc failed\n");
|
264 |
|
|
#endif
|
265 |
|
|
break;
|
266 |
|
|
}
|
267 |
|
|
arp_inuse++, arp_allocated++;
|
268 |
|
|
Bzero(la, sizeof(*la));
|
269 |
|
|
la->la_rt = rt;
|
270 |
|
|
rt->rt_flags |= RTF_LLINFO;
|
271 |
|
|
LIST_INSERT_HEAD(&llinfo_arp, la, la_list);
|
272 |
|
|
if (SIN(rt_key(rt))->sin_addr.s_addr ==
|
273 |
|
|
(IA_SIN(rt->rt_ifa))->sin_addr.s_addr) {
|
274 |
|
|
/*
|
275 |
|
|
* This test used to be
|
276 |
|
|
* if (loif.if_flags & IFF_UP)
|
277 |
|
|
* It allowed local traffic to be forced through
|
278 |
|
|
* the hardware by configuring the loopback down.
|
279 |
|
|
* However, it causes problems during network
|
280 |
|
|
* configuration for boards that can't receive
|
281 |
|
|
* packets they send. It is now necessary to clear
|
282 |
|
|
* "useloopback" and remove the route to force
|
283 |
|
|
* traffic out to the hardware.
|
284 |
|
|
*/
|
285 |
|
|
rt->rt_expire = 0;
|
286 |
|
|
Bcopy(((struct arpcom *)rt->rt_ifp)->ac_enaddr,
|
287 |
|
|
LLADDR(SDL(gate)),
|
288 |
|
|
SDL(gate)->sdl_alen = ETHER_ADDR_LEN);
|
289 |
|
|
if (useloopback)
|
290 |
|
|
rt->rt_ifp = &loif;
|
291 |
|
|
}
|
292 |
|
|
break;
|
293 |
|
|
|
294 |
|
|
case RTM_DELETE:
|
295 |
|
|
if (la == 0)
|
296 |
|
|
break;
|
297 |
|
|
arp_inuse--;
|
298 |
|
|
LIST_REMOVE(la, la_list);
|
299 |
|
|
rt->rt_llinfo = 0;
|
300 |
|
|
rt->rt_flags &= ~RTF_LLINFO;
|
301 |
|
|
if (la->la_hold)
|
302 |
|
|
m_freem(la->la_hold);
|
303 |
|
|
Free((caddr_t)la);
|
304 |
|
|
}
|
305 |
|
|
}
|
306 |
|
|
|
307 |
|
|
/*
|
308 |
|
|
* Broadcast an ARP request. Caller specifies:
|
309 |
|
|
* - arp header source ip address
|
310 |
|
|
* - arp header target ip address
|
311 |
|
|
* - arp header source ethernet address
|
312 |
|
|
*/
|
313 |
|
|
static void
|
314 |
|
|
arprequest(ac, sip, tip, enaddr)
|
315 |
|
|
register struct arpcom *ac;
|
316 |
|
|
register u_int32_t *sip, *tip;
|
317 |
|
|
register u_int8_t *enaddr;
|
318 |
|
|
{
|
319 |
|
|
register struct mbuf *m;
|
320 |
|
|
register struct ether_header *eh;
|
321 |
|
|
register struct ether_arp *ea;
|
322 |
|
|
struct sockaddr sa;
|
323 |
|
|
|
324 |
|
|
if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
|
325 |
|
|
return;
|
326 |
|
|
m->m_len = sizeof(*ea);
|
327 |
|
|
m->m_pkthdr.len = sizeof(*ea);
|
328 |
|
|
MH_ALIGN(m, sizeof(*ea));
|
329 |
|
|
ea = mtod(m, struct ether_arp *);
|
330 |
|
|
eh = (struct ether_header *)sa.sa_data;
|
331 |
|
|
bzero((caddr_t)ea, sizeof (*ea));
|
332 |
|
|
bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
|
333 |
|
|
sizeof(eh->ether_dhost));
|
334 |
|
|
eh->ether_type = htons(ETHERTYPE_ARP); /* if_output will not swap */
|
335 |
|
|
ea->arp_hrd = htons(ARPHRD_ETHER);
|
336 |
|
|
ea->arp_pro = htons(ETHERTYPE_IP);
|
337 |
|
|
ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */
|
338 |
|
|
ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */
|
339 |
|
|
ea->arp_op = htons(ARPOP_REQUEST);
|
340 |
|
|
bcopy((caddr_t)enaddr, (caddr_t)eh->ether_shost,
|
341 |
|
|
sizeof(eh->ether_shost));
|
342 |
|
|
bcopy((caddr_t)enaddr, (caddr_t)ea->arp_sha, sizeof(ea->arp_sha));
|
343 |
|
|
bcopy((caddr_t)sip, (caddr_t)ea->arp_spa, sizeof(ea->arp_spa));
|
344 |
|
|
bcopy((caddr_t)tip, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa));
|
345 |
|
|
sa.sa_family = AF_UNSPEC;
|
346 |
|
|
sa.sa_len = sizeof(sa);
|
347 |
|
|
(*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
|
348 |
|
|
}
|
349 |
|
|
|
350 |
|
|
/*
|
351 |
|
|
* Resolve an IP address into an ethernet address. If success,
|
352 |
|
|
* desten is filled in. If there is no entry in arptab,
|
353 |
|
|
* set one up and broadcast a request for the IP address.
|
354 |
|
|
* Hold onto this mbuf and resend it once the address
|
355 |
|
|
* is finally resolved. A return value of 1 indicates
|
356 |
|
|
* that desten has been filled in and the packet should be sent
|
357 |
|
|
* normally; a 0 return indicates that the packet has been
|
358 |
|
|
* taken over here, either now or for later transmission.
|
359 |
|
|
*/
|
360 |
|
|
int
|
361 |
|
|
arpresolve(ac, rt, m, dst, desten)
|
362 |
|
|
register struct arpcom *ac;
|
363 |
|
|
register struct rtentry *rt;
|
364 |
|
|
struct mbuf *m;
|
365 |
|
|
register struct sockaddr *dst;
|
366 |
|
|
register u_char *desten;
|
367 |
|
|
{
|
368 |
|
|
register struct llinfo_arp *la;
|
369 |
|
|
struct sockaddr_dl *sdl;
|
370 |
|
|
|
371 |
|
|
if (m->m_flags & M_BCAST) { /* broadcast */
|
372 |
|
|
bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
|
373 |
|
|
sizeof(etherbroadcastaddr));
|
374 |
|
|
return (1);
|
375 |
|
|
}
|
376 |
|
|
if (m->m_flags & M_MCAST) { /* multicast */
|
377 |
|
|
ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten);
|
378 |
|
|
return (1);
|
379 |
|
|
}
|
380 |
|
|
if (rt)
|
381 |
|
|
la = (struct llinfo_arp *)rt->rt_llinfo;
|
382 |
|
|
else {
|
383 |
|
|
if ((la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0)) != NULL)
|
384 |
|
|
rt = la->la_rt;
|
385 |
|
|
}
|
386 |
|
|
if (la == 0 || rt == 0) {
|
387 |
|
|
#ifdef __ECOS
|
388 |
|
|
#else
|
389 |
|
|
log(LOG_DEBUG, "arpresolve: can't allocate llinfo\n");
|
390 |
|
|
#endif
|
391 |
|
|
m_freem(m);
|
392 |
|
|
return (0);
|
393 |
|
|
}
|
394 |
|
|
sdl = SDL(rt->rt_gateway);
|
395 |
|
|
/*
|
396 |
|
|
* Check the address family and length is valid, the address
|
397 |
|
|
* is resolved; otherwise, try to resolve.
|
398 |
|
|
*/
|
399 |
|
|
if ((rt->rt_expire == 0 || rt->rt_expire > time.tv_sec) &&
|
400 |
|
|
sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
|
401 |
|
|
bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
|
402 |
|
|
return 1;
|
403 |
|
|
}
|
404 |
|
|
if (((struct ifnet *)ac)->if_flags & IFF_NOARP)
|
405 |
|
|
return 0;
|
406 |
|
|
|
407 |
|
|
/*
|
408 |
|
|
* There is an arptab entry, but no ethernet address
|
409 |
|
|
* response yet. Replace the held mbuf with this
|
410 |
|
|
* latest one.
|
411 |
|
|
*/
|
412 |
|
|
if (la->la_hold)
|
413 |
|
|
m_freem(la->la_hold);
|
414 |
|
|
la->la_hold = m;
|
415 |
|
|
/*
|
416 |
|
|
* Re-send the ARP request when appropriate.
|
417 |
|
|
*/
|
418 |
|
|
#ifdef DIAGNOSTIC
|
419 |
|
|
if (rt->rt_expire == 0) {
|
420 |
|
|
/* This should never happen. (Should it? -gwr) */
|
421 |
|
|
printf("arpresolve: unresolved and rt_expire == 0\n");
|
422 |
|
|
/* Set expiration time to now (expired). */
|
423 |
|
|
rt->rt_expire = time.tv_sec;
|
424 |
|
|
}
|
425 |
|
|
#endif
|
426 |
|
|
if (rt->rt_expire) {
|
427 |
|
|
rt->rt_flags &= ~RTF_REJECT;
|
428 |
|
|
if (la->la_asked == 0 || rt->rt_expire != time.tv_sec) {
|
429 |
|
|
rt->rt_expire = time.tv_sec;
|
430 |
|
|
if (la->la_asked++ < arp_maxtries)
|
431 |
|
|
arprequest(ac,
|
432 |
|
|
&(SIN(rt->rt_ifa->ifa_addr)->sin_addr.s_addr),
|
433 |
|
|
&(SIN(dst)->sin_addr.s_addr),
|
434 |
|
|
ac->ac_enaddr);
|
435 |
|
|
else {
|
436 |
|
|
rt->rt_flags |= RTF_REJECT;
|
437 |
|
|
rt->rt_expire += arpt_down;
|
438 |
|
|
la->la_asked = 0;
|
439 |
|
|
}
|
440 |
|
|
}
|
441 |
|
|
}
|
442 |
|
|
return (0);
|
443 |
|
|
}
|
444 |
|
|
|
445 |
|
|
/*
|
446 |
|
|
* Common length and type checks are done here,
|
447 |
|
|
* then the protocol-specific routine is called.
|
448 |
|
|
*/
|
449 |
|
|
void
|
450 |
|
|
arpintr()
|
451 |
|
|
{
|
452 |
|
|
register struct mbuf *m;
|
453 |
|
|
register struct arphdr *ar;
|
454 |
|
|
int s;
|
455 |
|
|
|
456 |
|
|
while (arpintrq.ifq_head) {
|
457 |
|
|
s = splimp();
|
458 |
|
|
IF_DEQUEUE(&arpintrq, m);
|
459 |
|
|
splx(s);
|
460 |
|
|
if (m == 0 || (m->m_flags & M_PKTHDR) == 0)
|
461 |
|
|
panic("arpintr");
|
462 |
|
|
if (m->m_len >= sizeof(struct arphdr) &&
|
463 |
|
|
(ar = mtod(m, struct arphdr *)) &&
|
464 |
|
|
ntohs(ar->ar_hrd) == ARPHRD_ETHER &&
|
465 |
|
|
m->m_len >=
|
466 |
|
|
sizeof(struct arphdr) + 2 * (ar->ar_hln + ar->ar_pln))
|
467 |
|
|
switch (ntohs(ar->ar_pro)) {
|
468 |
|
|
|
469 |
|
|
case ETHERTYPE_IP:
|
470 |
|
|
case ETHERTYPE_IPTRAILERS:
|
471 |
|
|
in_arpinput(m);
|
472 |
|
|
continue;
|
473 |
|
|
}
|
474 |
|
|
m_freem(m);
|
475 |
|
|
}
|
476 |
|
|
}
|
477 |
|
|
|
478 |
|
|
/*
|
479 |
|
|
* ARP for Internet protocols on Ethernet.
|
480 |
|
|
* Algorithm is that given in RFC 826.
|
481 |
|
|
* In addition, a sanity check is performed on the sender
|
482 |
|
|
* protocol address, to catch impersonators.
|
483 |
|
|
* We no longer handle negotiations for use of trailer protocol:
|
484 |
|
|
* Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent
|
485 |
|
|
* along with IP replies if we wanted trailers sent to us,
|
486 |
|
|
* and also sent them in response to IP replies.
|
487 |
|
|
* This allowed either end to announce the desire to receive
|
488 |
|
|
* trailer packets.
|
489 |
|
|
* We no longer reply to requests for ETHERTYPE_TRAIL protocol either,
|
490 |
|
|
* but formerly didn't normally send requests.
|
491 |
|
|
*/
|
492 |
|
|
static void
|
493 |
|
|
in_arpinput(m)
|
494 |
|
|
struct mbuf *m;
|
495 |
|
|
{
|
496 |
|
|
register struct ether_arp *ea;
|
497 |
|
|
register struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif;
|
498 |
|
|
struct ether_header *eh;
|
499 |
|
|
register struct llinfo_arp *la = 0;
|
500 |
|
|
register struct rtentry *rt;
|
501 |
|
|
struct in_ifaddr *ia, *maybe_ia = 0;
|
502 |
|
|
struct sockaddr_dl *sdl;
|
503 |
|
|
struct sockaddr sa;
|
504 |
|
|
struct in_addr isaddr, itaddr, myaddr;
|
505 |
|
|
int op;
|
506 |
|
|
|
507 |
|
|
ea = mtod(m, struct ether_arp *);
|
508 |
|
|
op = ntohs(ea->arp_op);
|
509 |
|
|
bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr));
|
510 |
|
|
bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr));
|
511 |
|
|
for (ia = in_ifaddr.tqh_first; ia != 0; ia = ia->ia_list.tqe_next)
|
512 |
|
|
if (ia->ia_ifp == &ac->ac_if ||
|
513 |
|
|
(ia->ia_ifp->if_bridge &&
|
514 |
|
|
ia->ia_ifp->if_bridge == ac->ac_if.if_bridge)) {
|
515 |
|
|
maybe_ia = ia;
|
516 |
|
|
if (itaddr.s_addr == ia->ia_addr.sin_addr.s_addr ||
|
517 |
|
|
isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)
|
518 |
|
|
break;
|
519 |
|
|
}
|
520 |
|
|
if (maybe_ia == 0)
|
521 |
|
|
goto out;
|
522 |
|
|
myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
|
523 |
|
|
if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
|
524 |
|
|
sizeof (ea->arp_sha)))
|
525 |
|
|
goto out; /* it's from me, ignore it. */
|
526 |
|
|
if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
|
527 |
|
|
sizeof (ea->arp_sha))) {
|
528 |
|
|
#ifdef __ECOS
|
529 |
|
|
#else
|
530 |
|
|
log(LOG_ERR,
|
531 |
|
|
"arp: ether address is broadcast for IP address %s!\n",
|
532 |
|
|
inet_ntoa(isaddr));
|
533 |
|
|
#endif
|
534 |
|
|
goto out;
|
535 |
|
|
}
|
536 |
|
|
if (isaddr.s_addr == myaddr.s_addr) {
|
537 |
|
|
#ifdef __ECOS
|
538 |
|
|
#else
|
539 |
|
|
log(LOG_ERR,
|
540 |
|
|
"duplicate IP address %s sent from ethernet address %s\n",
|
541 |
|
|
inet_ntoa(isaddr), ether_sprintf(ea->arp_sha));
|
542 |
|
|
#endif
|
543 |
|
|
itaddr = myaddr;
|
544 |
|
|
goto reply;
|
545 |
|
|
}
|
546 |
|
|
la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0);
|
547 |
|
|
if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) {
|
548 |
|
|
if (sdl->sdl_alen &&
|
549 |
|
|
bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) {
|
550 |
|
|
if (rt->rt_flags & RTF_PERMANENT_ARP) {
|
551 |
|
|
#ifdef __ECOS
|
552 |
|
|
#else
|
553 |
|
|
log(LOG_WARNING,
|
554 |
|
|
"arp: attempt to overwrite permanent "
|
555 |
|
|
"entry for %s by %s on %s\n",
|
556 |
|
|
inet_ntoa(isaddr),
|
557 |
|
|
ether_sprintf(ea->arp_sha),
|
558 |
|
|
(&ac->ac_if)->if_xname);
|
559 |
|
|
#endif
|
560 |
|
|
goto out;
|
561 |
|
|
} else if (rt->rt_ifp != &ac->ac_if) {
|
562 |
|
|
#ifdef __ECOS
|
563 |
|
|
#else
|
564 |
|
|
log(LOG_WARNING,
|
565 |
|
|
"arp: attempt to overwrite entry for %s "
|
566 |
|
|
"on %s by %s on %s\n",
|
567 |
|
|
inet_ntoa(isaddr), rt->rt_ifp->if_xname,
|
568 |
|
|
ether_sprintf(ea->arp_sha),
|
569 |
|
|
(&ac->ac_if)->if_xname);
|
570 |
|
|
#endif
|
571 |
|
|
goto out;
|
572 |
|
|
} else {
|
573 |
|
|
#ifdef __ECOS
|
574 |
|
|
#else
|
575 |
|
|
log(LOG_INFO,
|
576 |
|
|
"arp info overwritten for %s by %s on %s\n",
|
577 |
|
|
inet_ntoa(isaddr),
|
578 |
|
|
ether_sprintf(ea->arp_sha),
|
579 |
|
|
(&ac->ac_if)->if_xname);
|
580 |
|
|
#endif
|
581 |
|
|
rt->rt_expire = 1; /* no longer static */
|
582 |
|
|
}
|
583 |
|
|
}
|
584 |
|
|
bcopy((caddr_t)ea->arp_sha, LLADDR(sdl),
|
585 |
|
|
sdl->sdl_alen = sizeof(ea->arp_sha));
|
586 |
|
|
if (rt->rt_expire)
|
587 |
|
|
rt->rt_expire = time.tv_sec + arpt_keep;
|
588 |
|
|
rt->rt_flags &= ~RTF_REJECT;
|
589 |
|
|
la->la_asked = 0;
|
590 |
|
|
if (la->la_hold) {
|
591 |
|
|
(*ac->ac_if.if_output)(&ac->ac_if, la->la_hold,
|
592 |
|
|
rt_key(rt), rt);
|
593 |
|
|
la->la_hold = 0;
|
594 |
|
|
}
|
595 |
|
|
}
|
596 |
|
|
reply:
|
597 |
|
|
if (op != ARPOP_REQUEST) {
|
598 |
|
|
out:
|
599 |
|
|
m_freem(m);
|
600 |
|
|
return;
|
601 |
|
|
}
|
602 |
|
|
if (itaddr.s_addr == myaddr.s_addr) {
|
603 |
|
|
/* I am the target */
|
604 |
|
|
bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
|
605 |
|
|
sizeof(ea->arp_sha));
|
606 |
|
|
bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
|
607 |
|
|
sizeof(ea->arp_sha));
|
608 |
|
|
} else {
|
609 |
|
|
la = arplookup(itaddr.s_addr, 0, SIN_PROXY);
|
610 |
|
|
if (la == 0)
|
611 |
|
|
goto out;
|
612 |
|
|
rt = la->la_rt;
|
613 |
|
|
bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
|
614 |
|
|
sizeof(ea->arp_sha));
|
615 |
|
|
sdl = SDL(rt->rt_gateway);
|
616 |
|
|
bcopy(LLADDR(sdl), (caddr_t)ea->arp_sha, sizeof(ea->arp_sha));
|
617 |
|
|
}
|
618 |
|
|
|
619 |
|
|
bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa, sizeof(ea->arp_spa));
|
620 |
|
|
bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa, sizeof(ea->arp_spa));
|
621 |
|
|
ea->arp_op = htons(ARPOP_REPLY);
|
622 |
|
|
ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */
|
623 |
|
|
eh = (struct ether_header *)sa.sa_data;
|
624 |
|
|
bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
|
625 |
|
|
sizeof(eh->ether_dhost));
|
626 |
|
|
bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
|
627 |
|
|
sizeof(eh->ether_shost));
|
628 |
|
|
eh->ether_type = htons(ETHERTYPE_ARP);
|
629 |
|
|
sa.sa_family = AF_UNSPEC;
|
630 |
|
|
sa.sa_len = sizeof(sa);
|
631 |
|
|
(*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
|
632 |
|
|
return;
|
633 |
|
|
}
|
634 |
|
|
|
635 |
|
|
/*
|
636 |
|
|
* Free an arp entry.
|
637 |
|
|
*/
|
638 |
|
|
static void
|
639 |
|
|
arptfree(la)
|
640 |
|
|
register struct llinfo_arp *la;
|
641 |
|
|
{
|
642 |
|
|
register struct rtentry *rt = la->la_rt;
|
643 |
|
|
register struct sockaddr_dl *sdl;
|
644 |
|
|
|
645 |
|
|
if (rt == 0)
|
646 |
|
|
panic("arptfree");
|
647 |
|
|
if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) &&
|
648 |
|
|
sdl->sdl_family == AF_LINK) {
|
649 |
|
|
sdl->sdl_alen = 0;
|
650 |
|
|
la->la_asked = 0;
|
651 |
|
|
rt->rt_flags &= ~RTF_REJECT;
|
652 |
|
|
return;
|
653 |
|
|
}
|
654 |
|
|
rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt),
|
655 |
|
|
0, (struct rtentry **)0);
|
656 |
|
|
}
|
657 |
|
|
|
658 |
|
|
/*
|
659 |
|
|
* Lookup or enter a new address in arptab.
|
660 |
|
|
*/
|
661 |
|
|
static struct llinfo_arp *
|
662 |
|
|
arplookup(addr, create, proxy)
|
663 |
|
|
u_int32_t addr;
|
664 |
|
|
int create, proxy;
|
665 |
|
|
{
|
666 |
|
|
register struct rtentry *rt;
|
667 |
|
|
static struct sockaddr_inarp sin;
|
668 |
|
|
|
669 |
|
|
sin.sin_len = sizeof(sin);
|
670 |
|
|
sin.sin_family = AF_INET;
|
671 |
|
|
sin.sin_addr.s_addr = addr;
|
672 |
|
|
sin.sin_other = proxy ? SIN_PROXY : 0;
|
673 |
|
|
rt = rtalloc1(sintosa(&sin), create);
|
674 |
|
|
if (rt == 0)
|
675 |
|
|
return (0);
|
676 |
|
|
rt->rt_refcnt--;
|
677 |
|
|
if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 ||
|
678 |
|
|
rt->rt_gateway->sa_family != AF_LINK) {
|
679 |
|
|
if (create)
|
680 |
|
|
#ifdef __ECOS
|
681 |
|
|
#else
|
682 |
|
|
log(LOG_DEBUG,
|
683 |
|
|
"arplookup: unable to enter address for %s\n",
|
684 |
|
|
inet_ntoa(sin.sin_addr));
|
685 |
|
|
#endif
|
686 |
|
|
return (0);
|
687 |
|
|
}
|
688 |
|
|
return ((struct llinfo_arp *)rt->rt_llinfo);
|
689 |
|
|
}
|
690 |
|
|
|
691 |
|
|
int
|
692 |
|
|
arpioctl(cmd, data)
|
693 |
|
|
u_long cmd;
|
694 |
|
|
caddr_t data;
|
695 |
|
|
{
|
696 |
|
|
|
697 |
|
|
return (EOPNOTSUPP);
|
698 |
|
|
}
|
699 |
|
|
|
700 |
|
|
void
|
701 |
|
|
arp_ifinit(ac, ifa)
|
702 |
|
|
struct arpcom *ac;
|
703 |
|
|
struct ifaddr *ifa;
|
704 |
|
|
{
|
705 |
|
|
|
706 |
|
|
/* Warn the user if another station has this IP address. */
|
707 |
|
|
arprequest(ac,
|
708 |
|
|
&(IA_SIN(ifa)->sin_addr.s_addr),
|
709 |
|
|
&(IA_SIN(ifa)->sin_addr.s_addr),
|
710 |
|
|
ac->ac_enaddr);
|
711 |
|
|
ifa->ifa_rtrequest = arp_rtrequest;
|
712 |
|
|
ifa->ifa_flags |= RTF_CLONING;
|
713 |
|
|
}
|
714 |
|
|
|
715 |
|
|
/*
|
716 |
|
|
* Called from Ethernet interrupt handlers
|
717 |
|
|
* when ether packet type ETHERTYPE_REVARP
|
718 |
|
|
* is received. Common length and type checks are done here,
|
719 |
|
|
* then the protocol-specific routine is called.
|
720 |
|
|
*/
|
721 |
|
|
void
|
722 |
|
|
revarpinput(m)
|
723 |
|
|
struct mbuf *m;
|
724 |
|
|
{
|
725 |
|
|
struct arphdr *ar;
|
726 |
|
|
|
727 |
|
|
if (m->m_len < sizeof(struct arphdr))
|
728 |
|
|
goto out;
|
729 |
|
|
ar = mtod(m, struct arphdr *);
|
730 |
|
|
if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
|
731 |
|
|
goto out;
|
732 |
|
|
if (m->m_len < sizeof(struct arphdr) + 2 * (ar->ar_hln + ar->ar_pln))
|
733 |
|
|
goto out;
|
734 |
|
|
switch (ntohs(ar->ar_pro)) {
|
735 |
|
|
|
736 |
|
|
case ETHERTYPE_IP:
|
737 |
|
|
case ETHERTYPE_IPTRAILERS:
|
738 |
|
|
in_revarpinput(m);
|
739 |
|
|
return;
|
740 |
|
|
|
741 |
|
|
default:
|
742 |
|
|
break;
|
743 |
|
|
}
|
744 |
|
|
out:
|
745 |
|
|
m_freem(m);
|
746 |
|
|
}
|
747 |
|
|
|
748 |
|
|
/*
|
749 |
|
|
* RARP for Internet protocols on Ethernet.
|
750 |
|
|
* Algorithm is that given in RFC 903.
|
751 |
|
|
* We are only using for bootstrap purposes to get an ip address for one of
|
752 |
|
|
* our interfaces. Thus we support no user-interface.
|
753 |
|
|
*
|
754 |
|
|
* Since the contents of the RARP reply are specific to the interface that
|
755 |
|
|
* sent the request, this code must ensure that they are properly associated.
|
756 |
|
|
*
|
757 |
|
|
* Note: also supports ARP via RARP packets, per the RFC.
|
758 |
|
|
*/
|
759 |
|
|
void
|
760 |
|
|
in_revarpinput(m)
|
761 |
|
|
struct mbuf *m;
|
762 |
|
|
{
|
763 |
|
|
struct ifnet *ifp;
|
764 |
|
|
struct ether_arp *ar;
|
765 |
|
|
int op;
|
766 |
|
|
|
767 |
|
|
ar = mtod(m, struct ether_arp *);
|
768 |
|
|
op = ntohs(ar->arp_op);
|
769 |
|
|
switch (op) {
|
770 |
|
|
case ARPOP_REQUEST:
|
771 |
|
|
case ARPOP_REPLY: /* per RFC */
|
772 |
|
|
in_arpinput(m);
|
773 |
|
|
return;
|
774 |
|
|
case ARPOP_REVREPLY:
|
775 |
|
|
break;
|
776 |
|
|
case ARPOP_REVREQUEST: /* handled by rarpd(8) */
|
777 |
|
|
default:
|
778 |
|
|
goto out;
|
779 |
|
|
}
|
780 |
|
|
if (!revarp_in_progress)
|
781 |
|
|
goto out;
|
782 |
|
|
ifp = m->m_pkthdr.rcvif;
|
783 |
|
|
if (ifp != myip_ifp) /* !same interface */
|
784 |
|
|
goto out;
|
785 |
|
|
if (myip_initialized)
|
786 |
|
|
goto wake;
|
787 |
|
|
if (bcmp(ar->arp_tha, ((struct arpcom *)ifp)->ac_enaddr,
|
788 |
|
|
sizeof(ar->arp_tha)))
|
789 |
|
|
goto out;
|
790 |
|
|
bcopy((caddr_t)ar->arp_spa, (caddr_t)&srv_ip, sizeof(srv_ip));
|
791 |
|
|
bcopy((caddr_t)ar->arp_tpa, (caddr_t)&myip, sizeof(myip));
|
792 |
|
|
myip_initialized = 1;
|
793 |
|
|
wake: /* Do wakeup every time in case it was missed. */
|
794 |
|
|
wakeup((caddr_t)&myip);
|
795 |
|
|
|
796 |
|
|
out:
|
797 |
|
|
m_freem(m);
|
798 |
|
|
}
|
799 |
|
|
|
800 |
|
|
/*
|
801 |
|
|
* Send a RARP request for the ip address of the specified interface.
|
802 |
|
|
* The request should be RFC 903-compliant.
|
803 |
|
|
*/
|
804 |
|
|
void
|
805 |
|
|
revarprequest(ifp)
|
806 |
|
|
struct ifnet *ifp;
|
807 |
|
|
{
|
808 |
|
|
struct sockaddr sa;
|
809 |
|
|
struct mbuf *m;
|
810 |
|
|
struct ether_header *eh;
|
811 |
|
|
struct ether_arp *ea;
|
812 |
|
|
struct arpcom *ac = (struct arpcom *)ifp;
|
813 |
|
|
|
814 |
|
|
if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
|
815 |
|
|
return;
|
816 |
|
|
m->m_len = sizeof(*ea);
|
817 |
|
|
m->m_pkthdr.len = sizeof(*ea);
|
818 |
|
|
MH_ALIGN(m, sizeof(*ea));
|
819 |
|
|
ea = mtod(m, struct ether_arp *);
|
820 |
|
|
eh = (struct ether_header *)sa.sa_data;
|
821 |
|
|
bzero((caddr_t)ea, sizeof(*ea));
|
822 |
|
|
bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
|
823 |
|
|
sizeof(eh->ether_dhost));
|
824 |
|
|
eh->ether_type = htons(ETHERTYPE_REVARP);
|
825 |
|
|
ea->arp_hrd = htons(ARPHRD_ETHER);
|
826 |
|
|
ea->arp_pro = htons(ETHERTYPE_IP);
|
827 |
|
|
ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */
|
828 |
|
|
ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */
|
829 |
|
|
ea->arp_op = htons(ARPOP_REVREQUEST);
|
830 |
|
|
bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
|
831 |
|
|
sizeof(ea->arp_tha));
|
832 |
|
|
bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
|
833 |
|
|
sizeof(ea->arp_sha));
|
834 |
|
|
bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_tha,
|
835 |
|
|
sizeof(ea->arp_tha));
|
836 |
|
|
sa.sa_family = AF_UNSPEC;
|
837 |
|
|
sa.sa_len = sizeof(sa);
|
838 |
|
|
ifp->if_output(ifp, m, &sa, (struct rtentry *)0);
|
839 |
|
|
}
|
840 |
|
|
|
841 |
|
|
/*
|
842 |
|
|
* RARP for the ip address of the specified interface, but also
|
843 |
|
|
* save the ip address of the server that sent the answer.
|
844 |
|
|
* Timeout if no response is received.
|
845 |
|
|
*/
|
846 |
|
|
int
|
847 |
|
|
revarpwhoarewe(ifp, serv_in, clnt_in)
|
848 |
|
|
struct ifnet *ifp;
|
849 |
|
|
struct in_addr *serv_in;
|
850 |
|
|
struct in_addr *clnt_in;
|
851 |
|
|
{
|
852 |
|
|
int result, count = 20;
|
853 |
|
|
|
854 |
|
|
if (myip_initialized)
|
855 |
|
|
return EIO;
|
856 |
|
|
|
857 |
|
|
myip_ifp = ifp;
|
858 |
|
|
revarp_in_progress = 1;
|
859 |
|
|
while (count--) {
|
860 |
|
|
revarprequest(ifp);
|
861 |
|
|
result = tsleep((caddr_t)&myip, PSOCK, "revarp", hz/2);
|
862 |
|
|
if (result != EWOULDBLOCK)
|
863 |
|
|
break;
|
864 |
|
|
}
|
865 |
|
|
revarp_in_progress = 0;
|
866 |
|
|
if (!myip_initialized)
|
867 |
|
|
return ENETUNREACH;
|
868 |
|
|
|
869 |
|
|
bcopy((caddr_t)&srv_ip, serv_in, sizeof(*serv_in));
|
870 |
|
|
bcopy((caddr_t)&myip, clnt_in, sizeof(*clnt_in));
|
871 |
|
|
return 0;
|
872 |
|
|
}
|
873 |
|
|
|
874 |
|
|
/* For compatibility: only saves interface address. */
|
875 |
|
|
int
|
876 |
|
|
revarpwhoami(in, ifp)
|
877 |
|
|
struct in_addr *in;
|
878 |
|
|
struct ifnet *ifp;
|
879 |
|
|
{
|
880 |
|
|
struct in_addr server;
|
881 |
|
|
return (revarpwhoarewe(ifp, &server, in));
|
882 |
|
|
}
|
883 |
|
|
|
884 |
|
|
|
885 |
|
|
#ifdef DDB
|
886 |
|
|
|
887 |
|
|
#include <machine/db_machdep.h>
|
888 |
|
|
#include <ddb/db_interface.h>
|
889 |
|
|
#include <ddb/db_output.h>
|
890 |
|
|
|
891 |
|
|
static void
|
892 |
|
|
db_print_sa(sa)
|
893 |
|
|
struct sockaddr *sa;
|
894 |
|
|
{
|
895 |
|
|
int len;
|
896 |
|
|
u_char *p;
|
897 |
|
|
|
898 |
|
|
if (sa == 0) {
|
899 |
|
|
db_printf("[NULL]");
|
900 |
|
|
return;
|
901 |
|
|
}
|
902 |
|
|
|
903 |
|
|
p = (u_char*)sa;
|
904 |
|
|
len = sa->sa_len;
|
905 |
|
|
db_printf("[");
|
906 |
|
|
while (len > 0) {
|
907 |
|
|
db_printf("%d", *p);
|
908 |
|
|
p++;
|
909 |
|
|
len--;
|
910 |
|
|
if (len)
|
911 |
|
|
db_printf(",");
|
912 |
|
|
}
|
913 |
|
|
db_printf("]\n");
|
914 |
|
|
}
|
915 |
|
|
|
916 |
|
|
static void
|
917 |
|
|
db_print_ifa(ifa)
|
918 |
|
|
struct ifaddr *ifa;
|
919 |
|
|
{
|
920 |
|
|
if (ifa == 0)
|
921 |
|
|
return;
|
922 |
|
|
db_printf(" ifa_addr=");
|
923 |
|
|
db_print_sa(ifa->ifa_addr);
|
924 |
|
|
db_printf(" ifa_dsta=");
|
925 |
|
|
db_print_sa(ifa->ifa_dstaddr);
|
926 |
|
|
db_printf(" ifa_mask=");
|
927 |
|
|
db_print_sa(ifa->ifa_netmask);
|
928 |
|
|
db_printf(" flags=0x%x, refcnt=%d, metric=%d\n",
|
929 |
|
|
ifa->ifa_flags, ifa->ifa_refcnt, ifa->ifa_metric);
|
930 |
|
|
}
|
931 |
|
|
|
932 |
|
|
static void
|
933 |
|
|
db_print_llinfo(li)
|
934 |
|
|
caddr_t li;
|
935 |
|
|
{
|
936 |
|
|
struct llinfo_arp *la;
|
937 |
|
|
|
938 |
|
|
if (li == 0)
|
939 |
|
|
return;
|
940 |
|
|
la = (struct llinfo_arp *)li;
|
941 |
|
|
db_printf(" la_rt=%p la_hold=%p, la_asked=0x%lx\n",
|
942 |
|
|
la->la_rt, la->la_hold, la->la_asked);
|
943 |
|
|
}
|
944 |
|
|
|
945 |
|
|
/*
|
946 |
|
|
* Function to pass to rn_walktree().
|
947 |
|
|
* Return non-zero error to abort walk.
|
948 |
|
|
*/
|
949 |
|
|
static int
|
950 |
|
|
db_show_radix_node(rn, w)
|
951 |
|
|
struct radix_node *rn;
|
952 |
|
|
void *w;
|
953 |
|
|
{
|
954 |
|
|
struct rtentry *rt = (struct rtentry *)rn;
|
955 |
|
|
|
956 |
|
|
db_printf("rtentry=%p", rt);
|
957 |
|
|
|
958 |
|
|
db_printf(" flags=0x%x refcnt=%d use=%ld expire=%ld\n",
|
959 |
|
|
rt->rt_flags, rt->rt_refcnt, rt->rt_use, rt->rt_expire);
|
960 |
|
|
|
961 |
|
|
db_printf(" key="); db_print_sa(rt_key(rt));
|
962 |
|
|
db_printf(" mask="); db_print_sa(rt_mask(rt));
|
963 |
|
|
db_printf(" gw="); db_print_sa(rt->rt_gateway);
|
964 |
|
|
|
965 |
|
|
db_printf(" ifp=%p ", rt->rt_ifp);
|
966 |
|
|
if (rt->rt_ifp)
|
967 |
|
|
db_printf("(%s)", rt->rt_ifp->if_xname);
|
968 |
|
|
else
|
969 |
|
|
db_printf("(NULL)");
|
970 |
|
|
|
971 |
|
|
db_printf(" ifa=%p\n", rt->rt_ifa);
|
972 |
|
|
db_print_ifa(rt->rt_ifa);
|
973 |
|
|
|
974 |
|
|
db_printf(" genmask="); db_print_sa(rt->rt_genmask);
|
975 |
|
|
|
976 |
|
|
db_printf(" gwroute=%p llinfo=%p\n", rt->rt_gwroute, rt->rt_llinfo);
|
977 |
|
|
db_print_llinfo(rt->rt_llinfo);
|
978 |
|
|
return (0);
|
979 |
|
|
}
|
980 |
|
|
|
981 |
|
|
/*
|
982 |
|
|
* Function to print all the route trees.
|
983 |
|
|
* Use this from ddb: "call db_show_arptab"
|
984 |
|
|
*/
|
985 |
|
|
int
|
986 |
|
|
db_show_arptab()
|
987 |
|
|
{
|
988 |
|
|
struct radix_node_head *rnh;
|
989 |
|
|
rnh = rt_tables[AF_INET];
|
990 |
|
|
db_printf("Route tree for AF_INET\n");
|
991 |
|
|
if (rnh == NULL) {
|
992 |
|
|
db_printf(" (not initialized)\n");
|
993 |
|
|
return (0);
|
994 |
|
|
}
|
995 |
|
|
rn_walktree(rnh, db_show_radix_node, NULL);
|
996 |
|
|
return (0);
|
997 |
|
|
}
|
998 |
|
|
#endif
|
999 |
|
|
#endif /* INET */
|