1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*	Copyright (c) 1988, 1989, 1997, 1998 Apple Computer, Inc.
29 *
30 *    Modified for MP, 1996 by Tuyen Nguyen
31 *   Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
32 */
33
34/* at_aarp.c: 2.0, 1.17; 10/4/93; Apple Computer, Inc. */;
35
36/* This file is at_aarp.c and it contains all the routines used by AARP. This
37 * is part of the LAP layer.
38 */
39
40#include <sys/errno.h>
41#include <sys/types.h>
42#include <sys/param.h>
43#include <machine/spl.h>
44#include <sys/systm.h>
45#include <sys/kernel.h>
46#include <sys/proc.h>
47#include <sys/filedesc.h>
48#include <sys/fcntl.h>
49#include <sys/mbuf.h>
50#include <sys/ioctl.h>
51#include <sys/malloc.h>
52#include <sys/socket.h>
53#include <sys/socketvar.h>
54
55#include <net/if.h>
56#include <net/if_types.h>
57
58#include <netat/sysglue.h>
59#include <netat/appletalk.h>
60#include <netat/ddp.h>
61#include <netat/at_snmp.h>
62#include <netat/at_pcb.h>
63#include <netat/at_var.h>
64#include <netat/at_aarp.h>
65#include <netat/at_pat.h>
66#include <netat/debug.h>
67
68#include <sys/kern_event.h>
69
70static int	probing;
71/* Following two variables are used to keep track of how many dynamic addresses
72 * we have tried out at startup.
73 */
74int	no_of_nodes_tried;	/* no of node addresses we've tried
75				 * so far, within a network number
76				 */
77int	no_of_nets_tried;	/* no. of network numbers tried
78				 */
79
80struct	etalk_addr	et_zeroaddr = {
81	{0, 0, 0, 0, 0, 0}};
82
83aarp_amt_t		probe_cb;
84aarp_amt_array *aarp_table[IF_TOTAL_MAX];
85
86
87StaticProc int aarp_req_cmd_in(aarp_pkt_t *, at_ifaddr_t*);
88StaticProc int aarp_resp_cmd_in(aarp_pkt_t *, at_ifaddr_t*);
89StaticProc int aarp_probe_cmd_in(aarp_pkt_t *, at_ifaddr_t*);
90StaticProc int aarp_send_resp(at_ifaddr_t *, aarp_pkt_t *);
91StaticProc int aarp_send_req(aarp_amt_t *);
92StaticProc int aarp_send_probe(void);
93StaticProc aarp_amt_t *aarp_lru_entry(aarp_amt_t *);
94StaticProc int aarp_glean_info(aarp_pkt_t *, at_ifaddr_t*);
95StaticProc int aarp_delete_amt_info(aarp_amt_t	*);
96StaticProc void aarp_build_pkt(aarp_pkt_t *, at_ifaddr_t*);
97StaticProc void aarp_sched_req(void *);
98StaticProc int aarp_get_rand_node(at_ifaddr_t	*);
99StaticProc int aarp_get_next_node(at_ifaddr_t	*);
100StaticProc int aarp_get_rand_net(at_ifaddr_t *);
101
102/****************************************************************************
103 * aarp_init()
104 *
105 ****************************************************************************/
106
107int aarp_init1(elapp)
108     register at_ifaddr_t	*elapp;
109{
110	elapp->ifThisNode.s_net = 0;
111	elapp->ifThisNode.s_node = 0;
112
113	if (probing != PROBE_TENTATIVE)	/* How do I set the initial probe */
114		probing = PROBE_IDLE;	/* state ???*/
115	else {
116		dPrintf(D_M_AARP,D_L_ERROR,
117			("aarp_init: error :probing == PROBE_TENTATIVE\n"));
118		return(-1);
119	}
120
121	/* pick a random addr or start with what we have from initial_node addr */
122	if (elapp->initial_addr.s_net == 0 && elapp->initial_addr.s_node == 0) {
123		dPrintf(D_M_AARP, D_L_INFO,
124			("aarp_init: pick up a new node number\n"));
125		aarp_get_rand_node(elapp);
126		aarp_get_rand_net(elapp);
127	}
128	probe_cb.elapp = elapp;
129	probe_cb.no_of_retries = 0;
130	probe_cb.error = 0;
131
132	no_of_nodes_tried = 0; /* haven't tried any addresses yet */
133	no_of_nets_tried = 0;
134
135	if (aarp_send_probe() == -1) {
136		probing = PROBE_IDLE;	/* not probing any more */
137		dPrintf(D_M_AARP, D_L_ERROR,
138			("aarp_init: aarp_send_probe returns error\n"));
139		return(-1);
140	}
141	return(ENOTREADY);
142}
143
144int aarp_init2(elapp)
145     register at_ifaddr_t	*elapp;
146{
147	if (probe_cb.error != 0) {
148		probing = PROBE_IDLE;	/* not probing any more */
149		dPrintf(D_M_AARP, D_L_ERROR,
150			("aarp_init: probe_cb.error creates error =%d\n",
151			 probe_cb.error));
152		return(-1);
153	}
154
155	if (aarp_table[elapp->ifPort])
156		bzero ((caddr_t)&aarp_table[elapp->ifPort]->et_aarp_amt[0],
157		       sizeof(aarp_amt_array));
158	else
159		return(-1);
160
161	elapp->ifThisNode = elapp->initial_addr;
162	probing = PROBE_DONE;
163
164	/* AppleTalk was successfully started up. Send event with node and net. */
165	atalk_post_msg(elapp->aa_ifp, KEV_ATALK_ENABLED, &(elapp->ifThisNode), 0);
166
167	/* Set global flag */
168	at_state.flags |= AT_ST_STARTED;
169
170	return(0);
171}
172
173/****************************************************************************
174 * aarp_rcv_pkt()
175 *
176 * remarks :
177 *	(1) The caller must take care of freeing the real storage (gbuf)
178 *	(2) The incoming packet is of the form {802.3, 802.2, aarp}.
179 *
180 ****************************************************************************/
181int aarp_rcv_pkt(pkt, elapp)
182     aarp_pkt_t *pkt;
183     at_ifaddr_t *elapp;
184{
185	switch (ntohs(pkt->aarp_cmd)) {
186	case AARP_REQ_CMD:
187		return (aarp_req_cmd_in (pkt, elapp));
188	case AARP_RESP_CMD:
189		return (aarp_resp_cmd_in (pkt, elapp));
190	case AARP_PROBE_CMD:
191		return (aarp_probe_cmd_in (pkt, elapp));
192	default:
193		return (-1);
194	}/* end of switch*/
195}
196
197/****************************************************************************
198 *  aarp_req_cmd_in()
199 *
200 ****************************************************************************/
201StaticProc   int	aarp_req_cmd_in (pkt, elapp)
202aarp_pkt_t		*pkt;
203at_ifaddr_t	*elapp;
204{
205/*
206	kprintf("aarp_req_cmd_in: ifThisNode=%d:%d srcNode=%d:%d dstNode=%d:%d\n",
207			elapp->ifThisNode.s_net,
208			elapp->ifThisNode.s_node,
209			NET_VALUE(pkt->src_at_addr.atalk_net),
210			pkt->src_at_addr.atalk_node,
211			NET_VALUE(pkt->dest_at_addr.atalk_net),
212			pkt->dest_at_addr.atalk_node);
213*/
214	if ((probing == PROBE_DONE) &&
215	    (NET_VALUE(pkt->dest_at_addr.atalk_net) == elapp->ifThisNode.s_net) &&
216	    (pkt->dest_at_addr.atalk_node == elapp->ifThisNode.s_node)) {
217		if (aarp_send_resp(elapp, pkt) == -1)
218			return(-1);
219	}
220	/* now to glean some info */
221	aarp_glean_info(pkt, elapp);
222	return (0);
223}
224
225
226
227/****************************************************************************
228 *  aarp_resp_cmd_in()
229 *
230 ****************************************************************************/
231StaticProc int aarp_resp_cmd_in (pkt, elapp)
232     aarp_pkt_t		*pkt;
233     at_ifaddr_t	*elapp;
234{
235	register aarp_amt_t	*amt_ptr;
236	gbuf_t		        *m;
237
238	switch (probing) {
239	case PROBE_TENTATIVE :
240		if ((NET_VALUE(pkt->src_at_addr.atalk_net) ==
241		     probe_cb.elapp->initial_addr.s_net) &&
242		    (pkt->src_at_addr.atalk_node ==
243		     probe_cb.elapp->initial_addr.s_node)) {
244
245			/* this is a response to AARP_PROBE_CMD.  There's
246			 * someone out there with the address we desire
247			 * for ourselves.
248			 */
249			untimeout(aarp_sched_probe, 0);
250			probe_cb.no_of_retries = 0;
251			aarp_get_next_node(probe_cb.elapp);
252			no_of_nodes_tried++;
253
254			if (no_of_nodes_tried == AARP_MAX_NODES_TRIED) {
255				aarp_get_rand_net(probe_cb.elapp);
256				aarp_get_rand_node(probe_cb.elapp);
257				no_of_nodes_tried = 0;
258				no_of_nets_tried++;
259			}
260			if (no_of_nets_tried == AARP_MAX_NETS_TRIED) {
261				/* We have tried enough nodes and nets, give up.
262				 */
263				probe_cb.error = EADDRNOTAVAIL;
264				AARPwakeup(&probe_cb);
265				return(0);
266			}
267			if (aarp_send_probe() == -1) {
268				/* expecting aarp_send_probe to fill in
269				 * probe_cb.error
270				 */
271				AARPwakeup(&probe_cb);
272				return(-1);
273			}
274		} else {
275			/* hmmmm! got a response packet while still probing
276			 * for AT address and the AT dest address doesn't
277			 * match!!
278			 * What should I do here??  kkkkkkkkk
279			 */
280			 return(-1);
281		}
282		break;
283
284	case PROBE_DONE :
285		AMT_LOOK(amt_ptr, pkt->src_at_addr, elapp)
286		if (amt_ptr == NULL)
287			return(-1);
288		if (amt_ptr->tmo) {
289		  	untimeout(aarp_sched_req, amt_ptr);
290			amt_ptr->tmo = 0;
291		}
292
293		if (amt_ptr->m == NULL) {
294			/* this may be because of a belated response to
295			 * aarp reaquest.  Based on an earlier response, we
296			 * might have already sent the packet out, so
297			 * there's nothing to send now.  This is okay, no
298			 * error.
299			 */
300			return(0);
301		}
302		amt_ptr->dest_addr = pkt->src_addr;
303		if (FDDI_OR_TOKENRING(elapp->aa_ifp->if_type))
304			ddp_bit_reverse((unsigned char *)&amt_ptr->dest_addr);
305		m = amt_ptr->m;
306		amt_ptr->m = NULL;
307		pat_output(amt_ptr->elapp, m,
308			   (unsigned char *)&amt_ptr->dest_addr, 0);
309		break;
310	default :
311		/* probing in a weird state?? */
312		return(-1);
313	}
314	return(0);
315}
316
317
318
319/****************************************************************************
320 *  aarp_probe_cmd_in()
321 *
322 ****************************************************************************/
323StaticProc   int	aarp_probe_cmd_in (pkt, elapp)
324register aarp_pkt_t	*pkt;
325at_ifaddr_t	*elapp;
326{
327	register aarp_amt_t	*amt_ptr;
328
329	switch (probing) {
330	case PROBE_TENTATIVE :
331		if ((elapp == probe_cb.elapp) &&
332		    (NET_VALUE(pkt->src_at_addr.atalk_net) ==
333		     probe_cb.elapp->initial_addr.s_net) &&
334		    (pkt->src_at_addr.atalk_node ==
335		     probe_cb.elapp->initial_addr.s_node)) {
336			/* some bozo is probing for address I want... and I
337			 * can't tell him to shove off!
338			 */
339			untimeout(aarp_sched_probe, 0);
340			probe_cb.no_of_retries = 0;
341			aarp_get_next_node(probe_cb.elapp);
342			no_of_nodes_tried++;
343
344			if (no_of_nodes_tried == AARP_MAX_NODES_TRIED) {
345				aarp_get_rand_net(probe_cb.elapp);
346				aarp_get_rand_node(probe_cb.elapp);
347				no_of_nodes_tried = 0;
348				no_of_nets_tried++;
349			}
350			if (no_of_nets_tried == AARP_MAX_NETS_TRIED) {
351				/* We have tried enough nodes and nets, give up.
352				 */
353				probe_cb.error = EADDRNOTAVAIL;
354				AARPwakeup(&probe_cb);
355				return(0);
356			}
357			if (aarp_send_probe() == -1) {
358				/* expecting aarp_send_probe to fill in
359				 * probe_cb.error
360				 */
361				AARPwakeup(&probe_cb);
362				return(-1);
363			}
364		} else {
365			/* somebody's probing... none of my business yet, so
366			 * just ignore the packet
367			 */
368			return (0);
369		}
370		break;
371
372	case PROBE_DONE :
373		if ((NET_VALUE(pkt->src_at_addr.atalk_net) == elapp->ifThisNode.s_net) &&
374		    (pkt->src_at_addr.atalk_node == elapp->ifThisNode.s_node)) {
375			if (aarp_send_resp(elapp, pkt) == -1)
376				return (-1);
377			return (0);
378		}
379		AMT_LOOK(amt_ptr, pkt->src_at_addr, elapp);
380
381		if (amt_ptr)
382		        aarp_delete_amt_info(amt_ptr);
383		break;
384	default :
385		/* probing in a weird state?? */
386		return (-1);
387	}
388	return (0);
389}
390
391
392
393/****************************************************************************
394 *  aarp_chk_addr()
395 ****************************************************************************/
396int aarp_chk_addr(ddp_hdrp, elapp)
397     at_ddp_t  *ddp_hdrp;
398     at_ifaddr_t *elapp;
399{
400	if ((ddp_hdrp->dst_node == elapp->ifThisNode.s_node) &&
401	    (NET_VALUE(ddp_hdrp->dst_net) == elapp->ifThisNode.s_net)) {
402	        return(0);	    /* exact match in address */
403		}
404
405	if (AARP_BROADCAST(ddp_hdrp, elapp)) {
406	        return(0);          /* some kind of broadcast address */
407	}
408	return (AARP_ERR_NOT_OURS); /* not for us */
409}
410
411
412
413/****************************************************************************
414 *  aarp_send_data()
415 *
416 * remarks :
417 *	1. The message coming in would be of the form {802.3, 802.2, ddp,...}
418 *
419 *	2. The message coming in would be freed here if transmission goes
420 *	through okay. If an error is returned by aarp_send_data, the caller
421 *	can assume that	the message is not freed.  The exception to
422 *	this scenario is the prepended atalk_addr field.  This field
423 * 	will ALWAYS be removed.  If the message is dropped,
424 *	it's not an "error".
425 *
426 *  Parameter dest_at_addr must have the net # in network byte order
427 ****************************************************************************/
428
429int	aarp_send_data(m, elapp, dest_at_addr, loop)
430     register gbuf_t	*m;
431     register at_ifaddr_t  *elapp;
432     struct  atalk_addr	   *dest_at_addr;	/* net# in network byte order */
433     int		loop;			/* if true, loopback broadcasts */
434{
435	register aarp_amt_t	*amt_ptr;
436	register at_ddp_t	*ddp_hdrp;
437	int			error;
438	struct timeval timenow;
439	getmicrouptime(&timenow);
440
441	if (gbuf_len(m) <= 0)
442		ddp_hdrp = (at_ddp_t *)gbuf_rptr(gbuf_cont(m));
443	else
444		ddp_hdrp = (at_ddp_t *)gbuf_rptr(m);
445
446	if ((ddp_hdrp->dst_node == ddp_hdrp->src_node) &&
447	    (NET_VALUE(ddp_hdrp->dst_net)  == NET_VALUE(ddp_hdrp->src_net))) {
448	        /*
449		 * we're sending to ourselves
450		 * so loop it back upstream
451		 */
452		ddp_input(m, elapp);
453		return(0);
454	}
455	AMT_LOOK(amt_ptr, *dest_at_addr, elapp);
456
457
458	if (amt_ptr) {
459	    if (amt_ptr->m) {
460		        /*
461			 * there's already a packet awaiting transmission, so
462			 * drop this one and let the upper layer retransmit
463			 * later.
464			 */
465		        gbuf_freel(m);
466			return (0);
467		}
468		return (pat_output(elapp, m,
469				   (unsigned char *)&amt_ptr->dest_addr, 0));
470        }
471	/*
472	 * either this is a packet to be broadcasted, or the address
473	 * resolution needs to be done
474	 */
475	if (AARP_BROADCAST(ddp_hdrp, elapp)) {
476	        gbuf_t	             *newm = 0;
477		struct	etalk_addr   *dest_addr;
478
479		dest_addr =  &elapp->cable_multicast_addr;
480		if (loop)
481			newm = (gbuf_t *)gbuf_dupm(m);
482
483		if ( !(error = pat_output(elapp, m,
484					  (unsigned char *)dest_addr, 0))) {
485			/*
486			 * The message transmitted successfully;
487			 * Also loop a copy back up since this
488			 * is a broadcast message.
489			 */
490			if (loop) {
491				if (newm == NULL)
492				        return (error);
493				ddp_input(newm, elapp);
494			} /* endif loop */
495		} else {
496		        if (newm)
497			        gbuf_freem(newm);
498		}
499		return (error);
500	}
501	NEW_AMT(amt_ptr, *dest_at_addr, elapp)
502
503        if (amt_ptr->m) {
504	        /*
505		 * no non-busy slots available in the cache, so
506		 * drop this one and let the upper layer retransmit
507		 * later.
508		 */
509	        gbuf_freel(m);
510		return (0);
511	}
512	amt_ptr->dest_at_addr = *dest_at_addr;
513	amt_ptr->dest_at_addr.atalk_unused = 0;
514
515	getmicrouptime(&timenow);
516	amt_ptr->last_time = timenow.tv_sec;
517	amt_ptr->m = m;
518	amt_ptr->elapp = elapp;
519	amt_ptr->no_of_retries = 0;
520
521	if ((error = aarp_send_req(amt_ptr))) {
522		aarp_delete_amt_info(amt_ptr);
523		return(error);
524	}
525	return(0);
526}
527
528
529
530/****************************************************************************
531 * aarp_send_resp()
532 *
533 * remarks :
534 *	The pkt being passed here is only to "look at".  It should neither
535 *	be used for transmission, nor freed.  Its contents also must not be
536 *	altered.
537 *
538 ****************************************************************************/
539StaticProc   int	aarp_send_resp(elapp, pkt)
540     register at_ifaddr_t   *elapp;
541     aarp_pkt_t		    *pkt;
542{
543	register aarp_pkt_t	*new_pkt;
544	register gbuf_t		*m;
545
546	if ((m = gbuf_alloc(AT_WR_OFFSET+sizeof(aarp_pkt_t), PRI_MED)) == NULL) {
547		return (-1);
548	}
549	gbuf_rinc(m,AT_WR_OFFSET);
550	gbuf_wset(m,0);
551
552	new_pkt = (aarp_pkt_t *)gbuf_rptr(m);
553	aarp_build_pkt(new_pkt, elapp);
554
555	new_pkt->aarp_cmd = htons(AARP_RESP_CMD);
556	new_pkt->dest_addr =  pkt->src_addr;
557
558	new_pkt->dest_at_addr = pkt->src_at_addr;
559	new_pkt->dest_at_addr.atalk_unused = 0;
560
561	ATALK_ASSIGN(new_pkt->src_at_addr, elapp->ifThisNode.s_net,
562		     elapp->ifThisNode.s_node, 0);
563
564	gbuf_winc(m,sizeof(aarp_pkt_t));
565	if (FDDI_OR_TOKENRING(elapp->aa_ifp->if_type))
566		ddp_bit_reverse((unsigned char *)&new_pkt->dest_addr);
567
568	if (pat_output(elapp, m, (unsigned char *)&new_pkt->dest_addr,
569		       AARP_AT_TYPE))
570	        return(-1);
571	return(0);
572}
573
574
575
576/****************************************************************************
577 * aarp_send_req()
578 *
579 ****************************************************************************/
580
581StaticProc   int	aarp_send_req (amt_ptr)
582register aarp_amt_t 	*amt_ptr;
583{
584	register aarp_pkt_t  *pkt;
585	register gbuf_t	     *m;
586	int	             error;
587
588	if ((m = gbuf_alloc(AT_WR_OFFSET+sizeof(aarp_pkt_t), PRI_MED)) == NULL) {
589		return (ENOBUFS);
590	}
591	gbuf_rinc(m,AT_WR_OFFSET);
592	gbuf_wset(m,0);
593
594	pkt = (aarp_pkt_t *)gbuf_rptr(m);
595	aarp_build_pkt(pkt, amt_ptr->elapp);
596
597	pkt->aarp_cmd = htons(AARP_REQ_CMD);
598	pkt->dest_addr = et_zeroaddr;
599	pkt->dest_at_addr = amt_ptr->dest_at_addr;
600	pkt->dest_at_addr.atalk_unused = 0;
601	ATALK_ASSIGN(pkt->src_at_addr, amt_ptr->elapp->ifThisNode.s_net,
602		     amt_ptr->elapp->ifThisNode.s_node, 0);
603	gbuf_winc(m,sizeof(aarp_pkt_t));
604
605	amt_ptr->no_of_retries++;
606	timeout(aarp_sched_req, amt_ptr, AARP_REQ_TIMER_INT);
607	amt_ptr->tmo = 1;
608	error = pat_output(amt_ptr->elapp, m,
609			   (unsigned char *)&amt_ptr->elapp->cable_multicast_addr, AARP_AT_TYPE);
610	if (error)
611	{
612		untimeout(aarp_sched_req, amt_ptr);
613		amt_ptr->tmo = 0;
614		return(error);
615	}
616
617	return(0);
618}
619
620
621
622/****************************************************************************
623 * aarp_send_probe()
624 *
625 ****************************************************************************/
626StaticProc  int	aarp_send_probe(void)
627{
628	register aarp_pkt_t  *pkt;
629	register gbuf_t	     *m;
630
631	if ((m = gbuf_alloc(AT_WR_OFFSET+sizeof(aarp_pkt_t), PRI_MED)) == NULL) {
632		probe_cb.error = ENOBUFS;
633		return (-1);
634	}
635	gbuf_rinc(m,AT_WR_OFFSET);
636	gbuf_wset(m,0);
637	pkt = (aarp_pkt_t *)gbuf_rptr(m);
638	aarp_build_pkt(pkt, probe_cb.elapp);
639
640	pkt->aarp_cmd = htons(AARP_PROBE_CMD);
641	pkt->dest_addr = et_zeroaddr;
642
643	ATALK_ASSIGN(pkt->src_at_addr, probe_cb.elapp->initial_addr.s_net,
644		     probe_cb.elapp->initial_addr.s_node, 0);
645
646	ATALK_ASSIGN(pkt->dest_at_addr, probe_cb.elapp->initial_addr.s_net,
647		     probe_cb.elapp->initial_addr.s_node, 0);
648
649	gbuf_winc(m,sizeof(aarp_pkt_t));
650
651	probe_cb.error = pat_output(probe_cb.elapp, m,
652		(unsigned char *)&probe_cb.elapp->cable_multicast_addr, AARP_AT_TYPE);
653	if (probe_cb.error) {
654		return(-1);
655	}
656
657	probing = PROBE_TENTATIVE;
658	probe_cb.no_of_retries++;
659	timeout(aarp_sched_probe, 0, AARP_PROBE_TIMER_INT);
660
661	return(0);
662}
663
664
665
666/****************************************************************************
667 * aarp_lru_entry()
668 *
669 ****************************************************************************/
670
671StaticProc   aarp_amt_t	*aarp_lru_entry(at)
672register aarp_amt_t	*at;
673{
674	register aarp_amt_t  *at_ret;
675	register int	     i;
676
677	at_ret = at;
678
679	for (i = 1, at++; i < AMT_BSIZ; i++, at++) {
680		if (at->last_time < at_ret->last_time && (at->m == NULL))
681			at_ret = at;
682	}
683        return(at_ret);
684}
685
686
687
688/****************************************************************************
689 * aarp_glean_info()
690 *
691 ****************************************************************************/
692
693StaticProc   int	aarp_glean_info(pkt, elapp)
694register aarp_pkt_t	*pkt;
695at_ifaddr_t	*elapp;
696{
697    register aarp_amt_t   *amt_ptr;
698
699	AMT_LOOK(amt_ptr, pkt->src_at_addr, elapp);
700
701	if (amt_ptr == NULL) {
702	        /*
703		 * amt entry for this address doesn't exist, add it to the cache
704	         */
705		NEW_AMT(amt_ptr, pkt->src_at_addr,elapp);
706
707		if (amt_ptr->m)
708			return(0);     /* no non-busy slots available in the cache */
709		amt_ptr->dest_at_addr = pkt->src_at_addr;
710		amt_ptr->dest_at_addr.atalk_unused = 0;
711
712		amt_ptr->last_time = (int)random();
713	}
714	/*
715	 * update the ethernet address
716	 * in either case
717	 */
718	amt_ptr->dest_addr = pkt->src_addr;
719	if (FDDI_OR_TOKENRING(elapp->aa_ifp->if_type))
720		ddp_bit_reverse((unsigned char *)&amt_ptr->dest_addr);
721	return(1);
722}
723
724
725/****************************************************************************
726 * aarp_delete_amt_info()
727 *
728 ****************************************************************************/
729
730StaticProc   int	aarp_delete_amt_info(amt_ptr)
731register aarp_amt_t	*amt_ptr;
732{
733	register gbuf_t		*m;
734	amt_ptr->last_time = 0;
735	ATALK_ASSIGN(amt_ptr->dest_at_addr, 0, 0, 0);
736	amt_ptr->no_of_retries = 0;
737
738	if (amt_ptr->m) {
739	    m = amt_ptr->m;
740	    amt_ptr->m = NULL;
741	    gbuf_freel(m);
742    }
743	return(0);
744}
745
746
747
748/****************************************************************************
749 * aarp_sched_probe()
750 *
751 ****************************************************************************/
752
753void  aarp_sched_probe(__unused void *arg)
754{
755
756	atalk_lock();
757
758	if (probe_cb.elapp->aa_ifp != 0 &&
759            probe_cb.no_of_retries != AARP_MAX_PROBE_RETRIES) {
760		if (aarp_send_probe() == -1)
761			AARPwakeup(&probe_cb);
762	} else {
763		probe_cb.error = 0;
764		AARPwakeup(&probe_cb);
765	}
766
767	atalk_unlock();
768}
769
770
771
772/****************************************************************************
773 * aarp_build_pkt()
774 *
775 ****************************************************************************/
776
777StaticProc void aarp_build_pkt(pkt, elapp)
778     register aarp_pkt_t *pkt;
779     at_ifaddr_t *elapp;
780{
781	pkt->hardware_type = htons(AARP_ETHER_HW_TYPE);
782	pkt->stack_type = htons(AARP_AT_PROTO);
783	pkt->hw_addr_len = ETHERNET_ADDR_LEN;
784	pkt->stack_addr_len = AARP_AT_ADDR_LEN;
785	bcopy(elapp->xaddr, pkt->src_addr.etalk_addr_octet, sizeof(elapp->xaddr));
786	if (FDDI_OR_TOKENRING(elapp->aa_ifp->if_type))
787		ddp_bit_reverse(pkt->src_addr.etalk_addr_octet);
788}
789
790/****************************************************************************
791 * aarp_sched_req()
792 *
793 ****************************************************************************/
794
795StaticProc void	aarp_sched_req(arg)
796     void *arg;
797{
798	int i;
799	aarp_amt_t *amt_ptr = (aarp_amt_t *)arg;
800
801	atalk_lock();
802
803	/*
804	 * make sure pointer still valid in case interface removed
805	 * while trying to acquire the funnel. make sure it points
806	 * into one of the amt arrays.
807	 */
808	for (i = 0; i < IF_TOTAL_MAX; i++) {
809	    if (aarp_table[i] == NULL || (void *)amt_ptr < (void *)aarp_table[i] ||
810		(void *)amt_ptr >= (void *)(aarp_table[i] + 1))
811	        continue;  /* no match - try next entry */
812
813	    /*
814	     * found match - pointer is valid
815	     */
816	    if (amt_ptr->tmo == 0) {
817			atalk_unlock();
818	        return;
819	    }
820	    if (amt_ptr->no_of_retries < AARP_MAX_REQ_RETRIES) {
821	        if (aarp_send_req(amt_ptr) == 0) {
822				atalk_unlock();
823	            return;
824	        }
825	    }
826	    aarp_delete_amt_info(amt_ptr);
827	    break;
828	}
829	atalk_unlock();
830
831	return;
832}
833
834
835
836/****************************************************************************
837 * aarp_get_rand_node()
838 *
839 ****************************************************************************/
840StaticProc   int	aarp_get_rand_node(elapp)
841at_ifaddr_t	*elapp;
842{
843	register u_char	node;
844
845	/*
846	 * generate a starting node number in the range 1 thru 0xfd.
847	 * we use this as the starting probe point for a given net
848	 * To generate a different node number each time we call
849         * aarp_get_next_node
850	 */
851	node = ((u_char)(random() & 0xff)) % 0xfd + 2;
852
853	elapp->initial_addr.s_node = node;
854	return(0);
855}
856
857
858
859StaticProc   int	aarp_get_next_node(elapp)
860at_ifaddr_t	*elapp;
861{
862	register u_char	node = elapp->initial_addr.s_node;
863
864	/*
865	 * return the next node number in the range 1 thru 0xfd.
866	 */
867	node = (node == 0xfd) ? (1) : (node+1);
868
869	elapp->initial_addr.s_node = node;
870	return(0);
871}
872
873
874
875
876
877/****************************************************************************
878 * aarp_get_rand_net()
879 *
880 ****************************************************************************/
881StaticProc   int	aarp_get_rand_net(elapp)
882register at_ifaddr_t	*elapp;
883{
884	register at_net_al	 last_net, new_net;
885
886	if (elapp->ifThisCableStart) {
887		last_net = elapp->initial_addr.s_net;
888		/*
889		 * the range of network numbers valid for this
890		 * cable is known.  Try to choose a number from
891		 * this range only.
892		 */
893		new_net= ((at_net_al)random() & 0xffff);
894		/* two-byte random number generated... now fit it in
895		 * the prescribed range
896		 */
897		new_net = new_net % (unsigned) (elapp->ifThisCableEnd -
898				     elapp->ifThisCableStart + 1)
899			  + elapp->ifThisCableStart;
900
901		if (new_net == last_net) {
902		        if (new_net == elapp->ifThisCableEnd)
903			        new_net = elapp->ifThisCableStart;
904			else
905			        new_net++;
906		}
907		elapp->initial_addr.s_net = new_net;
908	} else {
909		/* The range of valid network numbers for this cable
910		 * is not known... choose a network number from
911		 * startup range.
912		 */
913		last_net = (elapp->initial_addr.s_net & 0x00ff);
914		new_net = (at_net_al)random() & 0x00ff;
915
916		if (new_net == last_net)
917		        new_net++;
918		if (new_net == 0xff)
919		        new_net = 0;
920		elapp->initial_addr.s_net = (DDP_STARTUP_LOW | new_net);
921	}
922	return(0);
923}
924
925
926int getAarpTableSize(__unused int elapId)
927      			/* elap_specifics array index (should be
928					 * changed when we add a non-ethernet type
929					 * of I/F to the mix. Unused for now.
930					 */
931{
932	return(AMTSIZE);
933}
934
935int getPhysAddrSize(__unused int elapId)
936     			/* elap_specifics array index (should be
937					 * changed when we add a non-ethernet type
938					 * of I/F to the mix. Unused for now.
939					 */
940{
941	return(ETHERNET_ADDR_LEN);
942}
943
944#define ENTRY_SIZE 	sizeof(struct atalk_addr) + sizeof(struct etalk_addr)
945
946snmpAarpEnt_t *getAarp(elapId)
947     int		*elapId;		/* I/F table to retrieve & table
948					   size entries on return */
949
950/* gets aarp table for specified interface and builds
951   a table in SNMP expected format. Returns pointer to said
952   table and sets elapId to byte size of used portion of table
953*/
954{
955	int i, cnt=0;
956	aarp_amt_t *amtp;
957	static snmpAarpEnt_t  snmp[AMTSIZE];
958	snmpAarpEnt_t  *snmpp;
959	struct atalk_addr addr;
960	u_short  tmp_net;
961
962
963	if (*elapId <0 || *elapId >= IF_TOTAL_MAX)
964		return NULL;
965
966
967	for (i=0, amtp = &(aarp_table[*elapId]->et_aarp_amt[0]), snmpp = snmp;
968		 i < AMTSIZE; i++,amtp++)	{
969
970		/* last_time will be 0 if entry was never used */
971		if (amtp->last_time) {
972				/* copy just network & mac address.
973				 * For speed, we assume that the atalk_addr
974				 * & etalk_addr positions in the aarp_amt_t struct
975				 * has not changed and copy both at once
976				 */
977			addr.atalk_unused = 0;
978			tmp_net = UAS_VALUE(amtp->dest_at_addr.atalk_net);
979			NET_ASSIGN(addr.atalk_net, tmp_net);
980			addr.atalk_node = amtp->dest_at_addr.atalk_node;
981			bcopy(&addr, &snmpp->ap_ddpAddr, ENTRY_SIZE);
982			snmpp++;
983			cnt++;
984
985		}
986	}
987	*elapId = cnt;
988	return(snmp);
989}
990/*#endif *//*  COMMENTED_OUT */
991
992