1/*
2 * Copyright (c) 2000-2010 Apple 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/*
29 *	Copyright (c) 1988, 1989, 1993-1998 Apple Computer, Inc.
30 */
31
32/* at_elap.c: 2.0, 1.29; 10/4/93; Apple Computer, Inc. */
33
34/* This is the file which implements all the streams driver
35 * functionality required for EtherTalk.
36 */
37
38/* revision history
39
40 03-14-94  jjs 	Changed all functions which assumed only one port would
41 		ever be used.  Added validate_msg_size, changed elap_online
42		to work with the h/w name only (e.g. 'et2').
43
44 Modified for MP, 1996 by Tuyen Nguyen
45 Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
46
47*/
48
49#define RESOLVE_DBG				/* for debug.h global resolution */
50#include <sys/errno.h>
51#include <sys/types.h>
52#include <sys/param.h>
53#include <machine/spl.h>
54#include <sys/systm.h>
55#include <sys/kernel.h>
56#include <sys/proc.h>
57#include <sys/filedesc.h>
58#include <sys/fcntl.h>
59#include <sys/mbuf.h>
60#include <sys/ioctl.h>
61#include <sys/socket.h>
62#include <net/if_dl.h>
63#include <sys/socketvar.h>
64#include <sys/malloc.h>
65#include <sys/domain.h>
66#include <sys/sockio.h>
67#include <vm/vm_kern.h>         /* for kernel_map */
68
69
70#include <net/if.h>
71#include <net/if_types.h>
72
73#include <netat/sysglue.h>
74#include <netat/appletalk.h>
75#include <netat/at_pcb.h>
76#include <netat/at_var.h>
77#include <netat/ddp.h>
78#include <netat/lap.h>
79#include <netat/routing_tables.h>     /* rtmp+zip table structs  */
80#include <netat/zip.h>
81#include <netat/nbp.h>
82#include <netat/at_snmp.h>
83#include <netat/at_aarp.h>
84#include <netat/asp.h>
85#include <netat/atp.h>
86#include <netat/debug.h>
87#include <netat/adsp.h>
88#include <netat/adsp_internal.h>
89#include <netat/at_pat.h>
90#include <netat/rtmp.h>
91
92#include <sys/kern_event.h>
93
94/* globals */
95
96at_ifaddr_t at_interfaces[IF_TOTAL_MAX];
97	/* index for at_interfaces is not important */
98at_ifaddr_t  *ifID_table[IF_TOTAL_MAX];
99	/* the table of ifID structures, one per interface
100	   (not just ethernet),
101	 * NOTE: for MH, entry 0 in this table is
102	 *       now defined to be the default I/F
103	 */
104at_ifaddr_t  *ifID_home;
105	/* always ifID_table[IFID_HOME] for now, but will be used for
106	   dynamic "home port" assignment, later */
107
108at_state_t at_state;		/* global state of AT network */
109snmpFlags_t snmpFlags;
110
111int xpatcnt = 0;
112
113/* snmp defines */
114#define MAX_BUFSIZE	8192
115#define MAX_RTMP	(MAX_BUFSIZE/sizeof(RT_entry)-1)
116#define MAX_NBP 		\
117	((MAX_BUFSIZE - SNMP_NBP_HEADER_SIZE)/sizeof(snmpNbpEntry_t)-1)
118#define MAX_NBP_BYTES	(MAX_NBP * sizeof(snmpNbpEntry_t))
119#define MAX_ZIP		(MAX_BUFSIZE/sizeof(ZT_entry)-1)
120#define MAX_RTMP_BYTES	(MAX_RTMP * sizeof(RT_entry))
121#define MAX_ZIP_BYTES	(MAX_ZIP * sizeof(ZT_entry))
122
123/* externs */
124extern TAILQ_HEAD(name_registry, _nve_) name_registry;
125extern snmpStats_t	snmpStats;
126extern short appletalk_inited;
127extern int adspInited;
128extern struct atpcb ddp_head;
129extern gref_t *atp_inputQ[];
130extern struct atp_state *atp_used_list;
131extern asp_scb_t *asp_scbQ[];
132extern asp_scb_t *scb_used_list;
133extern CCB *adsp_inputQ[];
134extern CCB *ccb_used_list;
135extern at_ddp_stats_t at_ddp_stats;
136extern lck_mtx_t * atalk_mutex;
137
138/* protos */
139int rtmp_router_start(at_kern_err_t *);
140static void add_route(RT_entry 	*);
141void elap_offline(at_ifaddr_t *);
142static int elap_online1(at_ifaddr_t *);
143static void elap_online2(at_ifaddr_t *);
144 int elap_online3(at_ifaddr_t *);
145static int re_aarp(at_ifaddr_t *);
146static int getSnmpCfg(snmpCfg_t *);
147
148int routerStart(at_kern_err_t *);
149
150static int validate_msg_size(gbuf_t *, gref_t *, at_ifaddr_t **);
151at_ifaddr_t *find_ifID(char *);
152int lap_online( at_ifaddr_t *, at_if_cfg_t *cfgp);
153
154
155at_ifaddr_t *find_ifID(if_name)
156	char	*if_name;
157{
158	int pat_id;
159
160	if (strlen(if_name))
161		for (pat_id=0; pat_id < xpatcnt; pat_id++) {
162			if (!strcmp(at_interfaces[pat_id].ifName, if_name))
163				return(&at_interfaces[pat_id]);
164		}
165
166	return((at_ifaddr_t *)NULL);
167}
168
169static int validate_msg_size(m, gref, elapp)
170	register gbuf_t *m;
171	gref_t		*gref;
172	at_ifaddr_t **elapp;
173
174/* checks ioctl message type for minimum expected message size &
175   sends error back if size invalid
176*/
177{
178	register ioc_t *iocbp;
179	int i = 0, size = 1;
180
181	*elapp = NULL;
182	iocbp = (ioc_t *) gbuf_rptr(m);
183
184	dPrintf(D_M_ELAP, D_L_INFO, ("validate_msg_size: ioc_cmd = %d\n",
185				     iocbp->ioc_cmd));
186	switch (iocbp->ioc_cmd) {
187		case LAP_IOC_ADD_ROUTE:
188			size = sizeof(RT_entry);
189			break;
190		case LAP_IOC_GET_ROUTE:
191			size = sizeof(RT_entry);
192			break;
193		case LAP_IOC_GET_ZONE:
194			size = sizeof(ZT_entryno);
195			break;
196		case LAP_IOC_SNMP_GET_CFG:
197		case LAP_IOC_SNMP_GET_AARP:
198		case LAP_IOC_SNMP_GET_ZIP:
199		case LAP_IOC_SNMP_GET_RTMP:
200		case LAP_IOC_SNMP_GET_NBP:
201			size = sizeof(int);
202			break;
203
204		case ELAP_IOC_GET_STATS:
205		case LAP_IOC_SNMP_GET_DDP:
206			size = 0;
207			break;
208
209		default:
210			dPrintf(D_M_ELAP, D_L_ERROR, ("validate_msg_size: unknown ioctl\n"));
211			goto error;
212	}
213
214	if (size == 0) {				/* a non-data ioctl */
215		return(0);
216	}
217
218	if (gbuf_cont(m) != NULL)
219		i = gbuf_len(gbuf_cont(m));
220	if (iocbp->ioc_count < size || (gbuf_cont(m) == NULL) || i < size) {
221		dPrintf(D_M_ELAP, D_L_ERROR,
222			("ioctl msg error:s:%d c:%d bcont:%c delta:%d\n",
223			 size, iocbp->ioc_count,
224			 gbuf_cont(m)? 'Y' : 'N', i));
225		goto error;
226	}
227	else
228		return(0);
229error:
230	ioc_ack(EMSGSIZE, m, gref);
231	return (EMSGSIZE);
232} /* validate_msg_size */
233
234int lap_online(elapp, cfgp)
235     at_ifaddr_t *elapp;
236     at_if_cfg_t *cfgp;
237{
238	int error;
239
240	if (elapp->ifState != LAP_OFFLINE) {
241		return(EALREADY);
242	}
243
244	elapp->flags = 0;
245	if (cfgp->flags & ELAP_CFG_HOME) {
246		if (ifID_home)  {
247			/* only 1 home allowed! */
248			return(EEXIST);
249		}
250		dPrintf(D_M_ELAP, D_L_STARTUP,
251			("elap_wput home I/F:%s\n", cfgp->ifr_name));
252		elapp->flags |= ELAP_CFG_HOME;
253	}
254
255	if (MULTIPORT_MODE) {
256		elapp->flags |= ELAP_CFG_ZONELESS;
257		if (ROUTING_MODE && cfgp->netStart)
258			elapp->flags |= ELAP_CFG_SEED;
259	}
260
261	/* (VL) !? */
262	if ((!DEFAULT_ZONE(&cfgp->zonename) &&
263	    (elapp->flags & ELAP_CFG_HOME)) || MULTIHOME_MODE) {
264		elapp->startup_zone = cfgp->zonename;
265	}
266
267	if (elapp->flags & ELAP_CFG_SEED) {
268		dPrintf(D_M_ELAP, D_L_STARTUP_INFO,
269			("elap_wput: found to be seed\n"));
270		elapp->ifThisCableStart = cfgp->netStart;
271		elapp->ifThisCableEnd   = cfgp->netEnd;
272	}
273	else {
274		dPrintf(D_M_ELAP,D_L_ERROR,
275			("elap_wput: we believe we're not seed\n"));
276		/* from ELAP_IOC_SET_CFG */
277		if (ATALK_VALUE(cfgp->node)) {
278			u_short	initial_net;
279			u_char	initial_node;
280
281			initial_node = cfgp->node.s_node;
282			initial_net = cfgp->node.s_net;
283			if ((initial_node<0xfe) && (initial_node>0) &&
284			    !((initial_net == 0) ||
285			      ((initial_net >= DDP_STARTUP_LOW)&&
286			       (initial_net <= DDP_STARTUP_HIGH)))) {
287
288				elapp->initial_addr = cfgp->node;
289			}
290		}
291	}
292
293	elapp->startup_error = 0;
294	elapp->startup_inprogress = FALSE;
295	if ((error = elap_online1(elapp)))
296		ddp_rem_if(elapp);
297	else
298		if (!(MULTIPORT_MODE) &&
299		    elapp->ifZoneName.len == 1 &&
300		    elapp->ifZoneName.str[0] == '*' &&
301		    !DEFAULT_ZONE(&cfgp->zonename)) {
302			nbp_add_multicast(&cfgp->zonename, elapp);
303		}
304	return(error);
305} /* lap_online */
306
307/***********************************************************************
308 * elap_wput()
309 *
310 **********************************************************************/
311int elap_wput(gref, m)
312     gref_t *gref;
313     register gbuf_t	*m;
314{
315	at_ifaddr_t 	*elapp;
316	register ioc_t		*iocbp;
317	register at_if_cfg_t	*cfgp;
318	at_elap_stats_t		*statsp;
319	int i,j;
320	int size, totalsize = 0, tabsize;
321	gbuf_t	*mn;		/* new gbuf */
322	gbuf_t	*mo;		/* old gbuf */
323	gbuf_t	*mt = NULL;		/* temp */
324	snmpNbpTable_t		*nbp;
325
326
327	switch (gbuf_type(m)) {
328	case MSG_DATA:
329		gbuf_freem(m);
330		dPrintf(D_M_ELAP,D_L_ERROR,
331	       		("Output data to control channel is ignored\n"));
332	break;
333
334	case MSG_IOCTL:
335		iocbp = (ioc_t *) gbuf_rptr(m);
336
337	        if (validate_msg_size(m, gref, &elapp))
338			break;
339
340		if (elapp)
341			cfgp = (at_if_cfg_t*) gbuf_rptr(gbuf_cont(m));
342
343		if (LAP_IOC_MYIOCTL(iocbp->ioc_cmd) ||
344		    ELAP_IOC_MYIOCTL(iocbp->ioc_cmd)) {
345
346			switch (iocbp->ioc_cmd) {
347			case ELAP_IOC_GET_STATS:
348#ifdef APPLETALK_DEBUG
349				kprintf("LAP_IOC_GET_STATS\n");
350#endif
351				if ( (gbuf_cont(m) == NULL)
352				     || (elapp = find_ifID(gbuf_rptr(gbuf_cont(m)))) == NULL) {
353					ioc_ack(EINVAL, m, gref);
354					break;
355				}
356				gbuf_freem(gbuf_cont(m));
357				if ((gbuf_cont(m) =gbuf_alloc(sizeof(at_elap_stats_t),
358			    		PRI_MED)) == NULL) {
359					ioc_ack(ENOBUFS, m, gref);
360					break;
361				}
362				statsp = ((at_elap_stats_t *)gbuf_rptr(gbuf_cont(m)));
363				*statsp = elapp->stats;
364				gbuf_wset(gbuf_cont(m),sizeof(at_elap_stats_t));
365				iocbp->ioc_count = sizeof(at_elap_stats_t);
366				ioc_ack(0, m, gref);
367				break;
368
369			case LAP_IOC_ADD_ROUTE:
370#ifdef APPLETALK_DEBUG
371				kprintf("LAP_IOC_ADD_ROUTE\n");
372#endif
373				add_route((RT_entry *)gbuf_rptr(gbuf_cont(m)));
374				ioc_ack(0, m, gref);
375				break;
376
377			case LAP_IOC_GET_ZONE:
378#ifdef APPLETALK_DEBUG
379			  kprintf("LAP_IOC_GET_ZONE\n");
380#endif
381			  /* return next ZT_entryno from ZT_table
382			     a pointer to the struct ZT_entryno is passed down from
383			     user space and the first byte is cast to a int, if
384			     this int is non-zero, then the first ZT_entry is
385			     returned and subsequent calls with a zero value
386			     will return the next entry in the table. The next
387			     read after the last valid entry will return EINVAL
388			  */
389			{
390				ZT_entryno *pZTe;
391
392				i =  *(int *)gbuf_rptr(gbuf_cont(m));
393				gbuf_freem(gbuf_cont(m));
394				gbuf_cont(m) = NULL;
395
396				pZTe = zt_getNextZone(i);
397				if (pZTe) {
398					if ((gbuf_cont(m) = gbuf_alloc(sizeof(ZT_entryno), PRI_MED)) == NULL) {
399						ioc_ack(ENOBUFS, m, gref);
400						break;
401					}
402					*(ZT_entryno *)gbuf_rptr(gbuf_cont(m)) = *pZTe;
403					gbuf_wset(gbuf_cont(m),sizeof(ZT_entryno));
404					iocbp->ioc_count = sizeof(ZT_entryno);
405					ioc_ack(0, m, gref);
406				}
407				else
408					ioc_ack(EINVAL, m, gref);
409			}
410				break;
411
412			case LAP_IOC_GET_ROUTE:
413#ifdef APPLETALK_DEBUG
414				kprintf("LAP_IOC_GET_ROUTE\n");
415#endif
416				/* return next RT_entry from RT_table
417				 * a pointer to the struct RT_entry is
418				 * passed down from user space and the first
419				 * byte is cast to a int, if this int is
420				 * non-zero, then the first RT_entry is
421				 * returned and subsequent calls with a
422				 * zero value will return the next entry in
423				 * the table. The next read after the last
424				 * valid entry will return EINVAL
425				 */
426			{
427				RT_entry *pRT;
428
429				i =  *(int *)gbuf_rptr(gbuf_cont(m));
430				gbuf_freem(gbuf_cont(m));
431				gbuf_cont(m) = NULL;
432
433				pRT = rt_getNextRoute(i);
434				if (pRT) {
435					if ((gbuf_cont(m) = gbuf_alloc(sizeof(RT_entry), PRI_MED)) == NULL) {
436						ioc_ack(ENOBUFS, m, gref);
437						break;
438					}
439					*(RT_entry *)gbuf_rptr(gbuf_cont(m)) = *pRT;
440					gbuf_wset(gbuf_cont(m),sizeof(RT_entry));
441					iocbp->ioc_count = sizeof(RT_entry);
442					ioc_ack(0, m, gref);
443				}
444				else
445					ioc_ack(EINVAL, m, gref);
446			}
447				break;
448
449			case LAP_IOC_SNMP_GET_DDP:
450#ifdef APPLETALK_DEBUG
451				kprintf("LAP_IOC_SNMP_GET_DDP\n");
452#endif
453				if (!(at_state.flags & AT_ST_STARTED)) {
454					ioc_ack(ENOTREADY, m, gref);
455					break;
456				}
457				if ((gbuf_cont(m) = gbuf_alloc(sizeof(snmpStats_t),
458						PRI_MED)) == NULL) {
459					ioc_ack(ENOBUFS, m, gref);
460					break;
461				}
462
463				*(snmpStats_t *)gbuf_rptr(gbuf_cont(m)) = snmpStats;
464				gbuf_wset(gbuf_cont(m),sizeof(snmpStats));
465				iocbp->ioc_count = sizeof(snmpStats);
466				ioc_ack(0, m, gref);
467				break;
468			case LAP_IOC_SNMP_GET_CFG:
469#ifdef APPLETALK_DEBUG
470				kprintf("LAP_IOC_SNMP_GET_CFG\n");
471#endif
472			{
473				snmpCfg_t 	snmp;
474
475				i =  *(int *)gbuf_rptr(gbuf_cont(m));
476				gbuf_freem(gbuf_cont(m));
477				gbuf_cont(m) = NULL;
478				if (!(at_state.flags & AT_ST_STARTED)) {
479					/* if stack down */
480					iocbp->ioc_count = 0;
481					ioc_ack(ENOTREADY, m, gref);
482					dPrintf(D_M_ELAP_LOW, D_L_INFO,
483						("elap_wput: cfg req, stack down\n"));
484					break;
485				}
486				if (i == UPDATE_IF_CHANGED &&
487					!(at_state.flags & AT_ST_IF_CHANGED)) {
488					iocbp->ioc_count = 0;
489					ioc_ack(0, m, gref);
490					dPrintf(D_M_ELAP_LOW, D_L_INFO,
491						("elap_wput: cfg req, unchanged\n"));
492					break;
493				}
494				dPrintf(D_M_ELAP_LOW, D_L_INFO,
495					("elap_wput: cfg req, changed\n"));
496
497				if (getSnmpCfg(&snmp)) {
498					dPrintf(D_M_ELAP,D_L_ERROR,
499						("elap_wput:SNMP_GET_CFG error\n"));
500					ioc_ack(EOPNOTSUPP, m, gref);
501					break;
502				}
503					/* send up only used part of table */
504				size = sizeof(snmp) -
505					   sizeof(snmpIfCfg_t) * (MAX_IFS - snmp.cfg_ifCnt);
506
507				if ((gbuf_cont(m) = gbuf_alloc(size, PRI_MED)) == NULL) {
508					ioc_ack(ENOBUFS, m, gref);
509					break;
510				}
511				bcopy(&snmp,gbuf_rptr(gbuf_cont(m)),size);
512				gbuf_wset(gbuf_cont(m),size);
513				iocbp->ioc_count = size;
514				at_state.flags &= ~AT_ST_IF_CHANGED;
515				ioc_ack(0, m, gref);
516			}
517			break;
518
519			case LAP_IOC_SNMP_GET_AARP:
520			{
521				snmpAarpEnt_t *snmpp;
522				int bytes;
523#ifdef APPLETALK_DEBUG
524				kprintf("LAP_IOC_SNMP_GET_AARP\n");
525#endif
526				i =  *(int *)gbuf_rptr(gbuf_cont(m));
527				gbuf_freem(gbuf_cont(m));
528				gbuf_cont(m) = NULL;
529				dPrintf(D_M_ELAP,D_L_INFO,
530					("elap_wput:calling getarp,i=%d\n", i));
531				snmpp = getAarp(&i);
532				bytes = i * sizeof(snmpAarpEnt_t);
533				dPrintf(D_M_ELAP,D_L_INFO,
534					("elap_wput:getarp returned, i=%d,bytes=%d\n",
535					i, bytes));
536				if (snmpp) {
537					if ((gbuf_cont(m) = gbuf_alloc(bytes, PRI_MED)) == NULL) {
538						ioc_ack(ENOBUFS, m, gref);
539						break;
540					}
541					bcopy(snmpp, gbuf_rptr(gbuf_cont(m)), bytes);
542					gbuf_wset(gbuf_cont(m),bytes);
543					iocbp->ioc_count = bytes;
544					ioc_ack(0, m, gref);
545				}
546				else
547					ioc_ack(EOPNOTSUPP, m, gref);
548			}
549			break;
550
551			case LAP_IOC_SNMP_GET_ZIP:
552#ifdef APPLETALK_DEBUG
553				kprintf("LAP_IOC_SNMP_GET_ZIP\n");
554#endif
555			{ /* matching brace NOT in this case */
556
557				i =  *(int *)gbuf_rptr(gbuf_cont(m));
558				gbuf_freem(gbuf_cont(m));
559				gbuf_cont(m) = NULL;
560				if (!(at_state.flags & AT_ST_STARTED)) {
561					ioc_ack(ENOTREADY, m, gref);
562					break;
563				}
564				if (i == UPDATE_IF_CHANGED &&
565					!(at_state.flags & AT_ST_ZT_CHANGED)) {
566					iocbp->ioc_count = 0;
567					ioc_ack(0, m, gref);
568					break;
569				}
570				mo=(gbuf_t*)NULL;
571				tabsize = getZipTableSize();
572
573					/* retrieve table into multiple gbufs */
574				for (i =0; i<tabsize;  i+=j) {
575					j = tabsize - i >
576						MAX_ZIP ? MAX_ZIP : tabsize - i;
577					size = j < MAX_ZIP ? sizeof(ZT_entry)*j : MAX_ZIP_BYTES;
578					if ((mn = gbuf_alloc(size, PRI_MED)) == NULL) {
579						if (gbuf_cont(m))
580							gbuf_freem(gbuf_cont(m));
581						ioc_ack(ENOBUFS, m, gref);
582						break;
583					}
584					if (!mo)	{ 		/* if first new one */
585						mt = mn;
586						totalsize = size;
587					}
588					else {
589						gbuf_cont(mo) = mn;
590						totalsize += size;
591					}
592					mo = mn;
593					getZipTable((ZT_entry*)gbuf_rptr(mn),i,j);
594					gbuf_wset(mn,size);
595				}
596				if ((gbuf_cont(m) = gbuf_alloc(sizeof(int), PRI_MED)) == NULL) {
597					if (mt)
598						gbuf_freem(mt);
599					iocbp->ioc_count = 0;
600					ioc_ack(ENOBUFS, m, gref);
601					break;
602				}
603				if (!tabsize) {
604					dPrintf(D_M_ELAP,D_L_WARNING,
605						("elap_wput:snmp: empty zip table\n"));
606					totalsize = 0;
607				}
608				*(int*)gbuf_rptr(gbuf_cont(m)) = totalsize; 	/* return table size */
609				gbuf_wset(gbuf_cont(m),sizeof(int));
610				iocbp->ioc_count = sizeof(int);
611				ioc_ack(0, m, gref);
612				if (tabsize)
613					atalk_putnext(gref,mt);		/* send up table */
614				at_state.flags &= ~AT_ST_ZT_CHANGED;
615				break;
616
617			case LAP_IOC_SNMP_GET_RTMP:
618#ifdef APPLETALK_DEBUG
619				kprintf("LAP_IOC_SNMP_GET_RTMP\n");
620#endif
621				i =  *(int *)gbuf_rptr(gbuf_cont(m));
622				gbuf_freem(gbuf_cont(m));
623				gbuf_cont(m) = NULL;
624				if (!(at_state.flags & AT_ST_STARTED)) {
625					ioc_ack(ENOTREADY, m, gref);
626					break;
627				}
628				if (i == UPDATE_IF_CHANGED &&
629				    !(at_state.flags & AT_ST_RT_CHANGED)) {
630					iocbp->ioc_count = 0;
631					ioc_ack(0, m, gref);
632					break;
633				}
634
635				mo=(gbuf_t*)NULL;
636				tabsize = getRtmpTableSize();
637
638					/* retrieve table into multiple gbufs */
639				for (i =0; i<tabsize;  i+=j) {
640					j = tabsize - i >
641						MAX_RTMP ? MAX_RTMP : tabsize - i;
642					size = j < MAX_RTMP ? sizeof(RT_entry)*j : MAX_RTMP_BYTES;
643					if ((mn = gbuf_alloc(size, PRI_MED)) == NULL) {
644						if (gbuf_cont(m))
645							gbuf_freem(gbuf_cont(m));
646						ioc_ack(ENOBUFS, m, gref);
647						break;
648					}
649					if (!mo)	{ 		/* if first new one */
650						mt = mn;
651						totalsize = size;
652					}
653					else {
654						gbuf_cont(mo) = mn;
655						totalsize += size;
656					}
657					mo = mn;
658					getRtmpTable((RT_entry*)gbuf_rptr(mn),i,j);
659					gbuf_wset(mn,size);
660				}
661				if ((gbuf_cont(m) = gbuf_alloc(sizeof(int), PRI_MED)) == NULL) {
662					if (mt)
663						gbuf_freem(mt);
664					iocbp->ioc_count = 0;
665					ioc_ack(ENOBUFS, m, gref);
666					break;
667				}
668				if (!tabsize)
669					totalsize = 0;
670				*(int*)gbuf_rptr(gbuf_cont(m)) = totalsize;	/* return table size */
671				gbuf_wset(gbuf_cont(m),sizeof(int));
672				iocbp->ioc_count = sizeof(int);
673				ioc_ack(0, m, gref);
674				if (tabsize)
675					atalk_putnext(gref,mt);		/* send up table */
676				at_state.flags &= ~AT_ST_RT_CHANGED;
677				break;
678
679			case LAP_IOC_SNMP_GET_NBP:
680#ifdef APPLETALK_DEBUG
681				kprintf("LAP_IOC_SNMP_GET_NBP\n");
682#endif
683				i =  *(int *)gbuf_rptr(gbuf_cont(m));
684				gbuf_freem(gbuf_cont(m));
685				gbuf_cont(m) = NULL;
686				if (!(at_state.flags & AT_ST_STARTED)) {
687					ioc_ack(ENOTREADY, m, gref);
688					break;
689				}
690				if (i == UPDATE_IF_CHANGED &&
691				    !(at_state.flags & AT_ST_NBP_CHANGED)) {
692					iocbp->ioc_count = 0;
693					ioc_ack(0, m, gref);
694					dPrintf(D_M_ELAP_LOW, D_L_INFO,
695						("elap_wput: nbp req denied, no change\n"));
696					break;
697				}
698
699				mo=(gbuf_t*)NULL;
700				tabsize = getNbpTableSize();
701
702					/* retrieve table into multiple gbufs */
703				for (i =0; i<tabsize;  i+=j) {
704					j = tabsize - i >
705						MAX_NBP ? MAX_NBP : tabsize - i;
706					size = j < MAX_NBP ? sizeof(snmpNbpEntry_t)*j : MAX_NBP_BYTES;
707					if (!i)
708						size += SNMP_NBP_HEADER_SIZE;
709					if ((mn = gbuf_alloc(size, PRI_MED)) == NULL) {
710						if (gbuf_cont(m))
711							gbuf_freem(gbuf_cont(m));
712						ioc_ack(ENOBUFS, m, gref);
713						break;
714					}
715					if (!mo)	{ 		/* if first new one */
716						mt = mn;
717						totalsize = size;
718						nbp = (snmpNbpTable_t*)gbuf_rptr(mn);
719						nbp->nbpt_entries = tabsize;
720						nbp->nbpt_zone = ifID_home->ifZoneName;
721						getNbpTable(nbp->nbpt_table,i,j);
722					}
723					else {
724						gbuf_cont(mo) = mn;
725						totalsize += size;
726						getNbpTable((snmpNbpEntry_t *)gbuf_rptr(mn),i,j);
727					}
728					mo = mn;
729					gbuf_wset(mn,size);
730				}
731				if ((gbuf_cont(m) = gbuf_alloc(sizeof(int), PRI_MED)) == NULL) {
732					if (mt)
733						gbuf_freem(mt);
734					iocbp->ioc_count = 0;
735					ioc_ack(ENOBUFS, m, gref);
736					break;
737				}
738				if (!tabsize)
739					totalsize = 0;
740				*(int*)gbuf_rptr(gbuf_cont(m)) = totalsize;	/* return table size */
741				gbuf_wset(gbuf_cont(m),sizeof(int));
742				iocbp->ioc_count = sizeof(int);
743				ioc_ack(0, m, gref);
744				if (tabsize)
745					atalk_putnext(gref,mt);		/* send up table */
746				at_state.flags &= ~AT_ST_NBP_CHANGED;
747				break;
748			}
749
750			default:
751#ifdef APPLETALK_DEBUG
752				kprintf("unknown ioctl %d\n", iocbp->ioc_cmd);
753#endif
754				ioc_ack(ENOTTY, m, gref);
755				dPrintf(D_M_ELAP, D_L_WARNING,
756					("elap_wput: unknown ioctl (%d)\n", iocbp->ioc_cmd));
757
758				if (elapp)
759					elapp->stats.unknown_mblks++;
760				break;
761			}
762		}
763		break;
764
765	default:
766		gbuf_freem(m);
767		break;
768	}
769
770	return 0;
771} /* elap_wput */
772
773
774/* Called directly by ddp/zip.
775 */
776int
777elap_dataput(m, elapp, addr_flag, addr)
778     register	gbuf_t	*m;
779     register at_ifaddr_t *elapp;
780     u_char	addr_flag;
781     char *addr;
782{
783	register int		size;
784	int			error = 0;
785	struct	etalk_addr	dest_addr;
786	struct	atalk_addr	dest_at_addr;
787	int			loop = TRUE;
788				/* flag to aarp to loopback (default) */
789
790	/* the incoming frame is of the form {flag, address, ddp...}
791	 * where "flag" indicates whether the address is an 802.3
792	 * (link) address, or an appletalk address.  If it's an
793	 * 802.3 address, the packet can just go out to the network
794	 * through PAT, if it's an appletalk address, AT->802.3 address
795	 * resolution needs to be done.
796	 * If 802.3 address is known, strip off the flag and 802.3
797	 * address, and prepend 802.2 and 802.3 headers.
798	 */
799
800	if (addr == NULL) {
801		addr_flag = *(u_char *)gbuf_rptr(m);
802		gbuf_rinc(m,1);
803	}
804
805	switch (addr_flag) {
806	case AT_ADDR_NO_LOOP :
807		loop = FALSE;
808		/* pass thru */
809	case AT_ADDR :
810	if (addr == NULL) {
811	    dest_at_addr = *(struct atalk_addr *)gbuf_rptr(m);
812	    gbuf_rinc(m,sizeof(struct atalk_addr));
813	} else
814	    dest_at_addr = *(struct atalk_addr *)addr;
815	    break;
816	case ET_ADDR :
817	if (addr == NULL) {
818	    dest_addr = *(struct etalk_addr *)gbuf_rptr(m);
819	    gbuf_rinc(m,sizeof(struct etalk_addr));
820	} else
821	    dest_addr = *(struct etalk_addr *)addr;
822	    break;
823	default :
824	    gbuf_freel(m);		/* unknown address type, chuck it */
825	    return(EINVAL);
826        }
827
828	m = gbuf_strip(m);
829
830	/* At this point, rptr points to ddp header for sure */
831	if (elapp->ifState == LAP_OFFLINE) {
832	    gbuf_freel(m);
833		return(ENETDOWN);
834	}
835
836	if (elapp->ifState == LAP_ONLINE_FOR_ZIP) {
837		/* see if this is a ZIP packet that we need
838		 * to let through even though network is
839		 * not yet alive!!
840		 */
841		if (zip_type_packet(m) == 0) {
842		    	gbuf_freel(m);
843			return(ENETDOWN);
844		}
845	}
846
847	elapp->stats.xmit_packets++;
848	size = gbuf_msgsize(m);
849	elapp->stats.xmit_bytes += size;
850	snmpStats.dd_outLong++;
851
852	switch (addr_flag) {
853	case AT_ADDR_NO_LOOP :
854	case AT_ADDR :
855	    /*
856	     * we don't want elap to be looking into ddp header, so
857	     * it doesn't know net#, consequently can't do
858	     * AMT_LOOKUP.  That task left to aarp now.
859	     */
860	    error = aarp_send_data(m, elapp, &dest_at_addr, loop);
861	    break;
862	case ET_ADDR :
863	    error = pat_output(elapp, m, (unsigned char *)&dest_addr, 0);
864	    break;
865        }
866	return (error);
867} /* elap_dataput */
868
869/************************************************************************
870 * elap_online()
871 *
872 ************************************************************************/
873
874static int elap_online1(elapp)
875     at_ifaddr_t *elapp;
876{
877	int errno;
878
879	dPrintf(D_M_ELAP, D_L_STARTUP_INFO, ("elap_online:%s elapp:0x%x\n",
880		(elapp->ifName) ? &elapp->ifName[0] : "NULL interface", (u_int) elapp));
881	if (elapp->ifState != LAP_OFFLINE || elapp->startup_inprogress == TRUE)
882	        return (EALREADY);
883
884	at_state.flags |= AT_ST_IF_CHANGED;
885
886	if (elapp->flags & ELAP_CFG_HOME) /* tell ddp_add_if if this is home */
887		elapp->ifFlags |= AT_IFF_DEFAULT;
888
889	/* Get DDP started */
890	if ((errno = ddp_add_if(elapp)))
891		return(errno);
892
893	// check if we still have an interface - can be lost when
894	// ddp_add_if calls malloc
895	// need to make check here after ddp_add_if completes because
896	// lap_online will call ddp_rem_if if we fail here
897	if (elapp->aa_ifp == 0)
898		return ENOENT;
899
900	/* set up multicast address for cable-wide broadcasts */
901	(void)at_reg_mcast(elapp, (caddr_t)&elapp->cable_multicast_addr);
902
903        // need to check again if interface is present
904        // can be lost in at_reg_mcast
905	if (elapp->aa_ifp == 0)
906		return ENOENT;
907
908	elapp->startup_inprogress = TRUE;
909	if (! (elapp->startup_error = re_aarp(elapp))) {
910		lck_mtx_assert(atalk_mutex, LCK_MTX_ASSERT_OWNED);
911		(void)msleep(&elapp->startup_inprogress, atalk_mutex, PSOCK | PCATCH,
912			     "elap_online1", 0);
913	}
914
915	/* then later, after some timeouts AARPwakeup() is called */
916
917	return(elapp->startup_error);
918} /* elap_online1 */
919
920static int re_aarp(elapp)
921     at_ifaddr_t *elapp;
922{
923	int errno;
924
925	/* We now call aarp_init() to assign an appletalk node addr */
926	errno = aarp_init1(elapp);
927			/* aarp_init1() returns either -1 or ENOTREADY */
928	if (errno == ENOTREADY)
929		return(0);
930	else {
931		dPrintf(D_M_ELAP, D_L_STATE_CHG,
932			("elap_online aarp_init for %s\n", elapp->ifName));
933		(void)at_unreg_mcast(elapp, (caddr_t)&elapp->cable_multicast_addr);
934		ddp_rem_if(elapp);
935		elapp->ifState = LAP_OFFLINE;
936		return(EADDRNOTAVAIL);
937	}
938}
939
940/* called from AARPwakeup */
941static void elap_online2(elapp)
942     at_ifaddr_t *elapp;
943{
944	if (MULTIPORT_MODE) {
945		dPrintf(D_M_ELAP,D_L_STARTUP_INFO,
946			("elap_online: re_aarp, we know it's a router...\n"));
947
948		if (elapp->flags & ELAP_CFG_SEED) {
949			/* add route table entry (zones to be added later) */
950			dPrintf(D_M_ELAP, D_L_STARTUP_INFO,
951				("elap_online: rt_insert Cable %d-%d port =%d as SEED\n",
952				elapp->ifThisCableStart, elapp->ifThisCableEnd, elapp->ifPort));
953			rt_insert(elapp->ifThisCableEnd,
954				  elapp->ifThisCableStart,
955				  0,0,0,
956				  elapp->ifPort,
957				  RTE_STATE_PERMANENT | RTE_STATE_ZKNOWN | RTE_STATE_GOOD
958					 );
959			/* LD 081694: set the RTR_SEED_PORT flag for seed ports */
960			elapp->ifFlags |= RTR_SEED_PORT;
961		}
962#if DEBUG
963		else
964			dPrintf(D_M_ELAP,D_L_STARTUP_INFO,
965				("elap_online: it's a router, but non seed\n"));
966#endif
967	}
968
969	if (elapp->flags & ELAP_CFG_ZONELESS) {
970		/* ELAP_CFG_ZONELESS tells us that it is a router or in
971		       multihome mode, so we don't want to do the GetNetInfo
972		       exchange with the router.  */
973
974		elapp->ifState = LAP_ONLINE_ZONELESS;
975		elapp->startup_inprogress = FALSE;
976		wakeup(&elapp->startup_inprogress);
977		dPrintf(D_M_ELAP, D_L_STARTUP_INFO, ("elap_online: ack 3\n"));
978		return;
979	}
980
981	/* if we don't already have a zone and a multicast address */
982	if (*(int *)&elapp->ZoneMcastAddr == 0 || elapp->ifZoneName.len == 0) {
983		/* hzonehash is a global containing the nbp hash for the startup_zone */
984		sethzonehash(elapp);
985
986		/* Get ZIP rolling to get zone multicast address, etc. */
987		elapp->ifState = LAP_ONLINE_FOR_ZIP;
988		(void)zip_control(elapp, ZIP_ONLINE);
989		/* zip_control (w. control == ZIP_ONLINE) always returns ENOTREADY */
990
991		/* later, after some timeouts ZIPwakeup() is called. */
992	} else {
993		/* otherwise, we have the zone and the multicast already,
994		   so don't bother with another ZIP GetNetInfo request */
995		ZIPwakeup(elapp, 0);
996	}
997} /* elap_online2 */
998
999/* called from rtmp_router_start */
1000int elap_online3(elapp)
1001     at_ifaddr_t	*elapp;
1002{
1003	elapp->startup_inprogress = TRUE;
1004
1005	/* just reset the net range */
1006	elapp->initial_addr.s_net = 0;
1007	elapp->initial_addr.s_node = 0;
1008	dPrintf(D_M_ELAP_LOW, D_L_STARTUP_INFO,
1009		("elap_online: goto re_aarp port=%d\n", elapp->ifPort));
1010
1011	if ((elapp->startup_error = re_aarp(elapp)))
1012		return(elapp->startup_error);
1013
1014	/* then later, after some timeouts AARPwakeup() is called */
1015
1016	lck_mtx_assert(atalk_mutex, LCK_MTX_ASSERT_OWNED);
1017	(void)msleep(&elapp->startup_inprogress, atalk_mutex, PSOCK | PCATCH,
1018		     "elap_online3", 0);
1019	return(elapp->startup_error);
1020} /* elap_online3 */
1021
1022/****************************************************************************
1023 * elap_offline()
1024 *
1025 ****************************************************************************/
1026
1027void elap_offline(elapp)
1028     register at_ifaddr_t *elapp;
1029
1030{
1031	dPrintf(D_M_ELAP, D_L_SHUTDN_INFO, ("elap_offline:%s\n", elapp->ifName));
1032	if (elapp->ifState != LAP_OFFLINE) {
1033
1034		/* Since AppleTalk is going away, remove the cable
1035		 * multicast address  and turn the interface off so that all
1036		 * AppleTalk packets are dropped in the driver itself.
1037		 * Get rid of the zone multicast address prior to going Offline.
1038		 */
1039		(void)at_unreg_mcast(elapp, (caddr_t)&elapp->ZoneMcastAddr);
1040		(void)at_unreg_mcast(elapp, (caddr_t)&elapp->cable_multicast_addr);
1041		elapp->ifState = LAP_OFFLINE;
1042
1043		if (MULTIPORT_MODE)
1044			RT_DELETE(elapp->ifThisCableEnd,
1045				  elapp->ifThisCableStart);
1046
1047		/* make sure no zip timeouts are left running */
1048		elapp->ifGNIScheduled = 0;
1049		untimeout(zip_sched_getnetinfo, elapp);
1050	}
1051	ddp_rem_if(elapp);
1052} /* elap_offline */
1053
1054
1055static void add_route(rt)
1056RT_entry 	*rt;
1057
1058/* support ioctl to manually add routes to table.
1059   this is really only for testing
1060*/
1061{
1062	rt_insert( 	rt->NetStop, rt->NetStart, rt->NextIRNet,
1063			 	rt->NextIRNode, rt->NetDist, rt->NetPort,
1064			 	rt->EntryState);
1065	dPrintf(D_M_ELAP, D_L_STARTUP_INFO, ("adding route: %ud:%ud dist:%ud\n",
1066		rt->NetStart, rt->NetStop,rt->NetDist));
1067}
1068
1069/*
1070 * ddp_start()
1071 *
1072 * Initialization that takes place each time AppleTalk is restarted.
1073 *
1074 */
1075void ddp_start()
1076{
1077	TAILQ_INIT(&at_ifQueueHd);
1078	TAILQ_INIT(&name_registry);
1079	bzero(at_interfaces, sizeof(at_interfaces));
1080	bzero(ifID_table, sizeof(ifID_table));
1081	bzero(&at_ddp_stats, sizeof(at_ddp_stats_t));
1082	rtmp_init(); /* initialize trackedrouters */
1083
1084	add_ddp_handler(RTMP_SOCKET, rtmp_input);
1085	ifID_home = (at_ifaddr_t *)NULL;
1086	xpatcnt = 0;
1087}
1088
1089int ddp_shutdown(count_only)
1090     int count_only;
1091{
1092	at_ifaddr_t *ifID;
1093	asp_scb_t *scb, *scb_next;
1094	struct atp_state *atp, *atp_next;
1095	CCB *sp, *sp_next;
1096	gref_t *gref;
1097	int i, active_skts = 0;	/* count of active pids for non-socketized
1098				   AppleTalk protocols */
1099
1100	/* Network is shutting down... send error messages up on each open
1101	 * socket.
1102	 *** For now, for ASP, ATP and ADSP, attempt to notify open
1103	     sockets, but return EBUSY and don't complete shutdown. ***
1104	 */
1105
1106	if (!count_only)
1107		nbp_shutdown();	/* clear all known NVE */
1108
1109	/* ASP */
1110	for (scb = scb_used_list; scb; ) {
1111	    scb_next = scb->next_scb;
1112	    active_skts++;
1113	    if (!count_only) {
1114		dPrintf(D_M_ASP, D_L_TRACE, ("asp pid=%d\n", scb->pid));
1115	        atalk_notify(scb->gref, ESHUTDOWN);
1116	    }
1117	    scb = scb_next;
1118	}
1119	for (i = 0; i < 256 ; i++) {
1120	    if ((scb = asp_scbQ[i]))
1121		do {
1122		    scb_next = scb->next_scb;
1123		    active_skts++;
1124		    if (!count_only) {
1125			dPrintf(D_M_ASP, D_L_TRACE,
1126				("asp pid=%d\n", scb->pid));
1127		        atalk_notify(scb->gref, ESHUTDOWN);
1128		    }
1129		    scb = scb_next;
1130		} while (scb);
1131	}
1132
1133	/* ATP */
1134	for (atp = atp_used_list; atp; ) {
1135	    atp_next = atp->atp_trans_waiting;
1136	    active_skts++;
1137	    if (!count_only) {
1138		dPrintf(D_M_ATP, D_L_TRACE, ("atp pid=%d\n", atp->atp_pid));
1139	        atalk_notify(atp->atp_gref, ESHUTDOWN);
1140	    }
1141	    atp = atp_next;
1142	}
1143	for (i = 0; i < 256; i++) {
1144	  if ((gref = atp_inputQ[i]) && (gref != (gref_t *)1)) {
1145		atp = (struct atp_state *)gref->info;
1146		if (!atp->dflag) {
1147		    active_skts++;
1148		    if (!count_only) {
1149			dPrintf(D_M_ATP, D_L_TRACE,
1150				("atp pid=%d\n", atp->atp_pid));
1151		        atalk_notify(atp->atp_gref, ESHUTDOWN);
1152		    }
1153		}
1154	  }
1155	}
1156
1157	/* ADSP */
1158	for (sp = ccb_used_list; sp ; ) {
1159	    sp_next = sp->otccbLink;
1160	    active_skts++;
1161	    if (!count_only) {
1162		dPrintf(D_M_ADSP, D_L_TRACE, ("adsp pid=%d\n", sp->pid));
1163		atalk_notify(sp->gref, ESHUTDOWN);
1164	    }
1165	    sp = sp_next;
1166	}
1167	for (i = 0; i < 256 ; i++) {
1168	    if ((sp = adsp_inputQ[i]))
1169		do {
1170		    sp_next = sp->otccbLink;
1171		    active_skts++;
1172		    if (!count_only) {
1173			dPrintf(D_M_ADSP, D_L_TRACE,
1174				("adsp pid=%d\n", sp->pid));
1175			atalk_notify(sp->gref, ESHUTDOWN);
1176		    }
1177		    sp = sp_next;
1178		} while (sp);
1179	}
1180
1181	/* DDP */
1182	for (gref = ddp_head.atpcb_next; gref != &ddp_head;
1183	     gref = gref->atpcb_next) {
1184	    if (count_only) {
1185		active_skts++;
1186	    } else {
1187		dPrintf(D_M_DDP,D_L_TRACE, ("ddp pid=%d\n", gref->pid));
1188		atalk_notify(gref, ESHUTDOWN);
1189	    }
1190	}
1191	if (count_only)
1192		return(active_skts);
1193
1194	/* if there are no interfaces in the process of going online, continue shutting down DDP */
1195	for (i = 0; i < IF_TOTAL_MAX; i++) {
1196		if (at_interfaces[i].startup_inprogress == TRUE)
1197		        return(1);
1198	}
1199	if (MULTIPORT_MODE) {
1200                rtmp_shutdown();
1201                /* free memory allocated for the rtmp/zip tables */
1202		if (ZT_table) {
1203			FREE(ZT_table, M_RTABLE);
1204			ZT_table = (ZT_entry *)NULL;
1205		}
1206		if (RT_table) {
1207			FREE(RT_table, M_RTABLE);
1208			RT_table = (RT_entry *)NULL;
1209		}
1210	}
1211
1212	at_state.flags = 0;     /* make sure inits are done on restart */
1213
1214	wakeup(&ifID_home->startup_inprogress);	/* if rtmp_router_start still starting up */
1215
1216	/* from original ddp_shutdown() */
1217	routershutdown();
1218	ddp_brt_shutdown();
1219
1220	if (adspInited) {
1221		CleanupGlobals();
1222		adspInited = 0;
1223	}
1224
1225
1226	dPrintf(D_M_DDP, D_L_VERBOSE, ("DDP shutdown completed"));
1227
1228	/*
1229	 * make sure we don't have a probe timeout hanging around
1230	 * it's going to try and make use of an entry in at_interfaces
1231	 * which is going to be zero'd out by the call to ddp_start a
1232	 * little further down
1233	 */
1234	untimeout(aarp_sched_probe, 0);
1235
1236	/* *** after an SIOCSIFADDR and before an AIOCSIFADDR,
1237	       this is the only place to find the ifID *** */
1238	for (i = 0; i < IF_TOTAL_MAX; i++) {
1239		ifID = &at_interfaces[i];
1240		/* do LAP_IOC_OFFLINE processing */
1241		elap_offline(ifID);
1242	}
1243	ddp_start();
1244
1245	return(0);
1246} /* ddp_shutdown */
1247
1248int routerStart(keP)
1249     at_kern_err_t *keP;
1250{
1251	register at_ifaddr_t *ifID;
1252	int error;
1253	struct timespec ts;
1254
1255	if (! ifID_home)
1256		return(EINVAL);
1257
1258	/*
1259	 * this will cause the ports to glean from the net the relevant
1260	 * information before forwarding
1261	 */
1262	TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1263		dPrintf(D_M_ELAP, D_L_STARTUP_INFO,
1264			("routerStart Port %d (%s) set to activating\n",
1265			 ifID->ifPort, ifID->ifName));
1266		ifID->ifRoutingState = PORT_ACTIVATING;
1267		ifID->ifFlags |= RTR_XNET_PORT;
1268	}
1269
1270	/*
1271	 * The next step is to check the information for each port before
1272	 * declaring the ports up and forwarding
1273	 */
1274	dPrintf(D_M_ELAP, D_L_STARTUP_INFO,
1275		("router_start: waiting 20 sec before starting up\n"));
1276
1277	lck_mtx_assert(atalk_mutex, LCK_MTX_ASSERT_OWNED);
1278	/* sleep for 20 seconds */
1279
1280	/* the vaue of 10n terms of hz is 100ms */
1281	ts.tv_sec = 20;
1282	ts.tv_nsec = 0;
1283
1284	if ((error =
1285	     /* *** eventually this will be the ifID for the interface
1286		being brought up in router mode *** */
1287		msleep(&ifID_home->startup_inprogress, atalk_mutex,
1288		    PSOCK | PCATCH, "routerStart", &ts))
1289	    != EWOULDBLOCK) {
1290/*
1291		if (!error)
1292			panic("routerStart: spurious interrupt");
1293*/
1294		return(error);
1295	}
1296
1297	return(rtmp_router_start(keP));
1298	/* was timeout(rtmp_router_start, 0, 20 * SYS_HZ);  */
1299} /* routerStart */
1300
1301void ZIPwakeup(elapp, ZipError)
1302     at_ifaddr_t *elapp;
1303     int ZipError;
1304{
1305	int error = ZipError;
1306
1307	if ( (elapp != NULL) && elapp->startup_inprogress) {
1308
1309		/* was ZIPContinue */
1310		/* was elapp_online() with jump to ZIP_sleep */
1311
1312		/* instead of the goto ZIP_sleep ... */
1313		switch (ZipError) {
1314			case 0 : /* success */
1315			    elapp->ifState = LAP_ONLINE;
1316
1317				/* Send event with zone info. */
1318				atalk_post_msg(elapp->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(elapp->ifZoneName));
1319
1320			    break;
1321			case ZIP_RE_AARP :
1322			    /* instead of goto re_aarp; */
1323			    /* We now call aarp_init() to assign an
1324			       appletalk node addr */
1325			    if ((elapp->startup_error = re_aarp(elapp))) {
1326				elapp->startup_inprogress = FALSE;
1327				wakeup(&elapp->startup_inprogress);
1328				dPrintf(D_M_ELAP, D_L_STARTUP_INFO,
1329					("elap_online: ack 2\n"));
1330			    }
1331			    break;
1332			default :
1333			    break;
1334		}
1335		if (ZipError != ZIP_RE_AARP) {
1336			elapp->startup_error = error;
1337			elapp->startup_inprogress = FALSE;
1338			wakeup(&elapp->startup_inprogress);
1339			dPrintf(D_M_ELAP, D_L_STARTUP_INFO,
1340				("elap_online: ifZipError=%d\n", error));
1341		}
1342	}
1343} /* ZIPwakeup */
1344
1345void AARPwakeup(probe_cb)
1346     aarp_amt_t *probe_cb;
1347{
1348	int errno;
1349	at_ifaddr_t *elapp;
1350
1351	elapp = probe_cb->elapp;
1352	if ( (elapp != NULL) && elapp->startup_inprogress && elapp->aa_ifp != 0) {
1353
1354		/* was AARPContinue */
1355		errno = aarp_init2(elapp);
1356		/* aarp_init2() returns either -1 or 0 */
1357		if (errno != 0) {
1358			dPrintf(D_M_ELAP, D_L_STATE_CHG,
1359				("elap_online aarp_init for %s\n",
1360				 elapp->ifName));
1361			(void)at_unreg_mcast(elapp, (caddr_t)&elapp->ZoneMcastAddr);
1362			(void)at_unreg_mcast(elapp, (caddr_t)&elapp->cable_multicast_addr);
1363			elapp->ifState = LAP_OFFLINE;
1364			ddp_rem_if(elapp);
1365			elapp->startup_error = EADDRNOTAVAIL;
1366			elapp->startup_inprogress = FALSE;
1367			wakeup(&elapp->startup_inprogress);
1368			dPrintf(D_M_ELAP, D_L_STARTUP_INFO, ("elap_online: ack 2\n"));
1369		} else {
1370			dPrintf(D_M_ELAP,D_L_STARTUP_INFO,
1371				("elap_online: aarp_init returns zero\n"));
1372			elap_online2(elapp);
1373		}
1374	}
1375} /* AARPwakeup */
1376
1377void ddp_bit_reverse(addr)
1378	unsigned char *addr;
1379{
1380static unsigned char reverse_data[] = {
1381	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
1382	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
1383	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
1384	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
1385	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
1386	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
1387	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
1388	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
1389	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
1390	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
1391	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
1392	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
1393	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
1394	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
1395	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
1396	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
1397	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
1398	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
1399	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
1400	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
1401	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
1402	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
1403	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
1404	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
1405	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
1406	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
1407	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
1408	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
1409	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
1410	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
1411	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
1412	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
1413	};
1414
1415	unsigned char k;
1416
1417	for (k=0; k < 6; k++)
1418		addr[k] = reverse_data[addr[k]];
1419}
1420
1421static int elap_trackMcast(at_ifaddr_t *, int, caddr_t);
1422
1423static int elap_trackMcast(patp, func, addr)
1424	at_ifaddr_t    *patp;
1425	int func;
1426	caddr_t addr;
1427{
1428	int i, loc=-1;
1429	u_char c;
1430	switch(patp->aa_ifp->if_type) {
1431	case IFT_ETHER:
1432	case IFT_FDDI:
1433	case IFT_L2VLAN:
1434	case IFT_IEEE8023ADLAG: /* bonded ethernet */
1435		/* set addr to point to unique part of addr */
1436		c = addr[5];
1437
1438		/* first try to find match */
1439		/* *** save just one byte of the multicast address? *** */
1440		for (i=0; i< MAX_MCASTS; i++)
1441			if (c == patp->mcast[i]) {
1442				loc = i;
1443				break;
1444			}
1445
1446		switch (func) {
1447		case MCAST_TRACK_DELETE:
1448			if (loc >= 0)
1449				patp->mcast[loc] = 0;
1450
1451			break;
1452		case MCAST_TRACK_ADD:
1453			dPrintf(D_M_PAT_LOW, D_L_USR2, ("mctrack:add loc:%d\n", i));
1454			if (loc >= 0) {
1455				dPrintf(D_M_PAT_LOW, D_L_USR2, ("mctrack:add, addr was there\n"));
1456				return(1);
1457				break;			/* already there */
1458			}
1459			for (i=0; i< MAX_MCASTS; i++)
1460				if (patp->mcast[i] == 0) {
1461					loc = i;
1462					break;
1463				}
1464			dPrintf(D_M_PAT_LOW, D_L_USR2, ("mctrack:add1 loc:%d\n", i));
1465			if (loc >= 0) {
1466				patp->mcast[loc] = c;
1467				dPrintf(D_M_PAT_LOW, D_L_USR2, ("mctrack:add, adding(%x)\n",
1468					(*(int*)addr)&0xffffff));
1469			}
1470			else {
1471				/*errno = ENOMEM; */ /*LD 5/7/97 nobody is using that */
1472				return(-1);
1473			}
1474			break;
1475		case MCAST_TRACK_CHECK:
1476			if (loc >= 0) {
1477				dPrintf(D_M_PAT_LOW, D_L_USR2, ("mctrack:check, addr was there\n"));
1478				return(0);
1479			}
1480			else {
1481				dPrintf(D_M_PAT_LOW, D_L_USR2, ("mctrack:add, addr was NOT there\n"));
1482				return(-1);
1483			}
1484
1485		default:
1486			/*errno = EINVAL;*/ /*LD 5/7/97 nobody is using that */
1487			return(-1);
1488		}
1489
1490	case IFT_ISO88025: /* token ring */
1491		/* we would use the lowest byte of the addr argument as a value
1492		   to shift left a 1 to form the mcast mask for TR. We'll do this
1493		   when the time comes
1494		 */
1495	default:
1496		;
1497	}
1498	return(0);
1499}
1500
1501
1502static int getSnmpCfg(snmp)
1503	snmpCfg_t *snmp;
1504{
1505	int i;
1506	at_ifaddr_t 	*elapp;
1507	snmpIfCfg_t	*ifc;
1508
1509	snmp->cfg_ifCnt = 0;
1510
1511	bzero(snmp,sizeof(snmpCfg_t));
1512	for (i=0, elapp=at_interfaces,ifc=snmp->cfg_ifCfg;
1513		 i<IF_TOTAL_MAX; i++, elapp++, ifc++) {
1514		if (elapp->ifState != LAP_OFFLINE) {
1515			snmp->cfg_ifCnt++;
1516			strlcpy(ifc->ifc_name,elapp->ifName, sizeof(ifc->ifc_name));
1517			ifc->ifc_aarpSize = getAarpTableSize(i);
1518			ifc->ifc_addrSize = getPhysAddrSize(i);
1519			switch (elapp->aa_ifp->if_type) {
1520				case IFT_ETHER:
1521                                case IFT_L2VLAN:
1522				case IFT_IEEE8023ADLAG: /* bonded ethernet */
1523					ifc->ifc_type = SNMP_TYPE_ETHER2;
1524					break;
1525				case IFT_ISO88025: /* token ring */
1526					ifc->ifc_type = SNMP_TYPE_TOKEN;
1527					break;
1528				case IFT_FDDI:
1529				default:
1530					ifc->ifc_type = SNMP_TYPE_OTHER;
1531					break;
1532			}
1533			ifc->ifc_start 	= elapp->ifThisCableStart;
1534			ifc->ifc_end	= elapp->ifThisCableEnd;
1535			ifc->ifc_ddpAddr= elapp->ifThisNode;
1536			ifc->ifc_status	= elapp->ifState == LAP_ONLINE ? 1 : 2;
1537			ifc->ifc_zoneName.len = 0;
1538			if (elapp->ifZoneName.len != 0) {
1539				ifc->ifc_zoneName = elapp->ifZoneName;
1540			}
1541			else if (elapp->ifDefZone) {
1542				ifc->ifc_zoneName = ZT_table[elapp->ifDefZone-1].Zone;
1543			}
1544			else	/* temp, debug only */
1545				ifc->ifc_zoneName = ZT_table[0].Zone;
1546			if (ROUTING_MODE) {
1547				if (elapp->ifFlags & RTR_SEED_PORT) {
1548					ifc->ifc_netCfg  = SNMP_CFG_CONFIGURED;
1549					ifc->ifc_zoneCfg = SNMP_CFG_CONFIGURED;
1550				}
1551				else {
1552					ifc->ifc_netCfg  = SNMP_CFG_GARNERED;
1553					ifc->ifc_zoneCfg = SNMP_CFG_GARNERED;
1554				}
1555			}
1556			else  { 	/* single-port mode */
1557				if (elapp->ifRouterState == ROUTER_AROUND) {
1558					ifc->ifc_netCfg = SNMP_CFG_GARNERED;
1559				}
1560				else {
1561					ifc->ifc_netCfg = SNMP_CFG_GUESSED;
1562					ifc->ifc_zoneCfg = SNMP_CFG_UNCONFIG;
1563				}
1564			}
1565		}
1566	}
1567	snmp->cfg_flags = at_state.flags;
1568
1569
1570	return(0);
1571}
1572
1573int at_reg_mcast(ifID, data)
1574     at_ifaddr_t *ifID;
1575     caddr_t data;
1576{
1577	struct ifnet *nddp = ifID->aa_ifp;
1578	struct sockaddr_dl sdl;
1579
1580	if (*(int *)data) {
1581		if (!nddp) {
1582			dPrintf(D_M_PAT, D_L_STARTUP, ("pat_mcast: BAD ndpp\n"));
1583			return(-1);
1584		}
1585
1586		if (elap_trackMcast(ifID, MCAST_TRACK_ADD, data) == 1)
1587			return(0);
1588
1589		/* this is for ether_output */
1590		bzero(&sdl, sizeof(sdl));
1591		sdl.sdl_family = AF_LINK;
1592		sdl.sdl_alen = sizeof(struct etalk_addr);
1593		sdl.sdl_len = offsetof(struct sockaddr_dl, sdl_data)
1594		    + sizeof(struct etalk_addr);
1595		bcopy(data, sdl.sdl_data, sizeof(struct etalk_addr));
1596		/* these next two lines should not really be needed XXX */
1597		sdl.sdl_index = nddp->if_index;
1598		sdl.sdl_type = IFT_ETHER;
1599
1600		dPrintf(D_M_PAT, D_L_STARTUP,
1601			("pat_mcast: adding multicast %08x%04x ifID:0x%x\n",
1602			 *(unsigned*)data, (*(unsigned *)(data+2))&0x0000ffff,
1603			 (unsigned)ifID));
1604
1605		if (if_addmulti_anon(nddp, (struct sockaddr *)&sdl, NULL))
1606			return -1;
1607	}
1608	return 0;
1609
1610}
1611
1612int at_unreg_mcast(ifID, data)
1613     at_ifaddr_t *ifID;
1614     caddr_t data;
1615{
1616	struct ifnet *nddp = ifID->aa_ifp;
1617	struct sockaddr_dl sdl;
1618
1619	if (*(int *)data) {
1620		if (!nddp) {
1621			dPrintf(D_M_PAT, D_L_STARTUP, ("pat_mcast: BAD ndpp\n"));
1622			return(-1);
1623		}
1624
1625		elap_trackMcast(ifID, MCAST_TRACK_DELETE, data);
1626
1627		/* this is for ether_output */
1628		bzero(&sdl, sizeof(sdl));
1629		sdl.sdl_family = AF_LINK;
1630		sdl.sdl_alen = sizeof(struct etalk_addr);
1631		sdl.sdl_len = offsetof(struct sockaddr_dl, sdl_data)
1632		    + sizeof(struct etalk_addr);
1633		bcopy(data, sdl.sdl_data, sizeof(struct etalk_addr));
1634		/* these next two lines should not really be needed XXX */
1635		sdl.sdl_index = nddp->if_index;
1636		sdl.sdl_type = IFT_ETHER;
1637
1638		dPrintf(D_M_PAT, D_L_STARTUP,
1639			("pat_mcast: deleting multicast %08x%04x ifID:0x%x\n",
1640			 *(unsigned*)data, (*(unsigned *)(data+2))&0x0000ffff,
1641			 (unsigned)ifID));
1642		bzero(data, sizeof(struct etalk_addr));
1643
1644		if (if_delmulti_anon(nddp, (struct sockaddr *)&sdl))
1645			return -1;
1646	}
1647	return 0;
1648}
1649#ifdef NOT_YET
1650/* *** at_reg_mcast() and at_unreg_mcast() should be replaced as soon as the
1651       new code to allow an AF_LINK address family multicast to be (un)registered
1652       using the SIOCADDMULTI / SIOCDELMULTI ioctls has been completed.
1653
1654       The issue is that the "struct sockaddr_dl" needed for the AF_LINK does not
1655       fit in the "struct ifreq" that is used for these ioctls, and we do not want
1656       Blue/Classic, which currently uses AF_UNSPEC, to use a different address
1657       family multicast address than Mac OS X uses.
1658   *** */
1659
1660int at_reg_mcast(ifID, data)
1661     at_ifaddr_t *ifID;
1662     caddr_t data;
1663{
1664	struct ifnet *nddp = ifID->aa_ifp;
1665	struct sockaddr_dl sdl;
1666
1667	if (*(int *)data) {
1668		if (!nddp) {
1669			dPrintf(D_M_PAT, D_L_STARTUP, ("pat_mcast: BAD ndpp\n"));
1670			return(-1);
1671		}
1672		if (elap_trackMcast(ifID, MCAST_TRACK_ADD, data) == 1)
1673			return(0);
1674
1675		sdl.sdl_len = sizeof(struct sockaddr_dl);
1676		sdl.sdl_family = AF_LINK;
1677		sdl.sdl_index = 0;
1678		sdl.sdl_type = nddp->if_type;
1679		sdl.sdl_alen = nddp->if_addrlen;
1680		sdl.sdl_slen = 0;
1681		sdl.sdl_nlen = sprintf(sdl.sdl_data, "%s%d",
1682				       nddp->if_name , nddp->if_unit);
1683		bcopy(data, LLADDR(&sdl), sdl.sdl_alen);
1684
1685		dPrintf(D_M_PAT, D_L_STARTUP,
1686			("pat_mcast: adding multicast %08x%04x ifID:0x%x\n",
1687			 *(unsigned*)data, (*(unsigned *)(data+2))&0x0000ffff,
1688			 (unsigned)ifID));
1689
1690		if (if_addmulti_anon(nddp, (struct sockaddr *)&sdl, NULL))
1691			return -1;
1692	}
1693
1694	return 0;
1695}
1696
1697int at_unreg_mcast(ifID, data)
1698     at_ifaddr_t *ifID;
1699     caddr_t data;
1700{
1701	struct ifnet *nddp = ifID->aa_ifp;
1702	struct sockaddr_dl sdl;
1703
1704	if (*(int *)data) {
1705		if (!nddp) {
1706			dPrintf(D_M_PAT, D_L_STARTUP, ("pat_mcast: BAD ndpp\n"));
1707			return(-1);
1708		}
1709
1710		elap_trackMcast(ifID, MCAST_TRACK_DELETE, data);
1711
1712		sdl.sdl_len = sizeof(struct sockaddr_dl);
1713		sdl.sdl_family = AF_LINK;
1714		sdl.sdl_index = 0;
1715		sdl.sdl_type = nddp->if_type;
1716		sdl.sdl_alen = nddp->if_addrlen;
1717		sdl.sdl_slen = 0;
1718		sdl.sdl_nlen = sprintf(sdl.sdl_data, "%s%d",
1719				       nddp->if_name , nddp->if_unit);
1720
1721		dPrintf(D_M_PAT, D_L_STARTUP,
1722			("pat_mcast: deleting multicast %08x%04x ifID:0x%x\n",
1723			 *(unsigned*)data, (*(unsigned *)(data+2))&0x0000ffff,
1724			 (unsigned)ifID));
1725		bzero(data, ETHERNET_ADDR_LEN);
1726
1727		if (if_delmulti_anon(nddp, (struct sockaddr *)&sdl))
1728			return(-1);
1729	}
1730
1731	return 0;
1732}
1733
1734#endif
1735