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 *    Modified for MP, 1996 by Tuyen Nguyen
30 *    Added AURP support, April 8, 1996 by Tuyen Nguyen
31 *   Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
32 */
33
34#define RESOLVE_DBG			/* define debug globals in debug.h */
35
36#include <sys/errno.h>
37#include <sys/types.h>
38#include <sys/param.h>
39#include <machine/spl.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/proc.h>
43#include <sys/filedesc.h>
44#include <sys/fcntl.h>
45#include <sys/mbuf.h>
46#include <sys/ioctl.h>
47#include <sys/malloc.h>
48#include <sys/socket.h>
49#include <sys/socketvar.h>
50#include <sys/protosw.h>
51
52#include <net/if.h>
53#include <net/dlil.h>
54
55#include <netat/sysglue.h>
56#include <netat/appletalk.h>
57#include <netat/at_pcb.h>
58#include <netat/at_var.h>
59#include <netat/ddp.h>
60#include <netat/ep.h>
61#include <netat/nbp.h>
62#include <netat/rtmp.h>
63#include <netat/zip.h>
64#include <netat/routing_tables.h>
65#include <netat/at_snmp.h>
66#include <netat/aurp.h>
67#include <netat/debug.h>
68#include <netat/at_ddp_brt.h>
69#include <netat/at_aarp.h>
70#include <netat/adsp.h>
71#include <netat/adsp_internal.h>
72#include <netat/at_pat.h>
73#include <netat/atp.h>
74
75#include <net/kpi_protocol.h>
76
77/* globals */
78
79/* Queue of LAP interfaces which have registered themselves with DDP */
80struct at_ifQueueHd at_ifQueueHd;
81
82extern TAILQ_HEAD(name_registry, _nve_) name_registry;
83
84snmpStats_t snmpStats;		/* snmp ddp & echo stats */
85
86extern at_ddp_stats_t at_ddp_stats;	/* DDP statistics */
87extern struct atpcb ddp_head;
88extern at_ifaddr_t *ifID_home, *ifID_table[];
89extern aarp_amt_array *aarp_table[];
90extern at_ifaddr_t at_interfaces[];
91
92/* routing mode special */
93void (*ddp_AURPsendx)(void) = NULL;
94at_ifaddr_t *aurp_ifID = 0;
95
96int pktsIn = 0;
97int pktsOut = 0;
98int pktsDropped = 0;
99int pktsHome = 0;
100
101extern int *atp_pidM;
102extern int *adsp_pidM;
103extern struct atpcb *atp_inputQ[];
104extern CCB *adsp_inputQ[];
105
106static void fillin_pkt_chain(gbuf_t *);
107static int ot_ddp_check_socket(unsigned char ,int pid);
108
109
110struct {
111	ddp_handler_func func;
112} ddp_handler[256];
113
114void init_ddp_handler(void)
115{
116	bzero(ddp_handler, sizeof(ddp_handler));
117}
118
119void add_ddp_handler(ddp_socket, input_func)
120     u_char ddp_socket;
121     ddp_handler_func input_func;
122{
123	ddp_handler[ddp_socket].func = input_func;
124}
125
126void
127ddp_slowtimo()
128{
129	ddp_brt_sweep();
130}
131
132/*
133 * Raw DDP socket option processing.
134 */
135int ddp_ctloutput(so, sopt)
136     struct socket *so;
137     struct sockopt *sopt;
138{
139	struct atpcb *at_pcb = sotoatpcb(so);
140	int optval, error = 0;
141
142	if (sopt->sopt_level != ATPROTO_NONE)
143		return (EINVAL);
144
145	switch (sopt->sopt_dir) {
146
147	case SOPT_GET:
148		switch (sopt->sopt_name) {
149		case DDP_HDRINCL:
150			optval = at_pcb->ddp_flags & DDPFLG_HDRINCL;
151			error = sooptcopyout(sopt, &optval, sizeof optval);
152			break;
153		case DDP_CHKSUM_ON:
154			optval = at_pcb->ddp_flags & DDPFLG_CHKSUM;
155			error = sooptcopyout(sopt, &optval, sizeof optval);
156			break;
157		case DDP_STRIPHDR:
158			optval = at_pcb->ddp_flags & DDPFLG_STRIPHDR;
159			error = sooptcopyout(sopt, &optval, sizeof optval);
160			break;
161		case DDP_SLFSND_ON:
162			optval = at_pcb->ddp_flags & DDPFLG_SLFSND;
163			error = sooptcopyout(sopt, &optval, sizeof optval);
164			break;
165		case DDP_GETSOCKNAME:
166		  {
167		  	ddp_addr_t addr;
168			addr.inet.net = at_pcb->laddr.s_net;
169			addr.inet.node = at_pcb->laddr.s_node;
170			addr.inet.socket = at_pcb->lport;
171			addr.ddptype = at_pcb->ddptype;
172			error = sooptcopyout(sopt, &addr, sizeof addr);
173		  }
174			break;
175                default:
176			error = ENOPROTOOPT;
177			break;
178		}
179		break;
180	case SOPT_SET:
181		switch (sopt->sopt_name) {
182		case DDP_HDRINCL:
183			error = sooptcopyin(sopt, &optval, sizeof optval,
184					    sizeof optval);
185			if (error)
186				break;
187			if (optval)
188				at_pcb->ddp_flags |= DDPFLG_HDRINCL;
189			else
190				at_pcb->ddp_flags &= ~DDPFLG_HDRINCL;
191			break;
192		case DDP_CHKSUM_ON:
193			error = sooptcopyin(sopt, &optval, sizeof optval,
194					    sizeof optval);
195			if (error)
196				break;
197			if (optval)
198				at_pcb->ddp_flags |= DDPFLG_CHKSUM;
199			else
200				at_pcb->ddp_flags &= ~DDPFLG_CHKSUM;
201			break;
202		case DDP_STRIPHDR:
203			error = sooptcopyin(sopt, &optval, sizeof optval,
204					    sizeof optval);
205			if (error)
206				break;
207			if (optval)
208				at_pcb->ddp_flags |= DDPFLG_STRIPHDR;
209			else
210				at_pcb->ddp_flags &= ~DDPFLG_STRIPHDR;
211			break;
212		case DDP_SLFSND_ON:
213			error = sooptcopyin(sopt, &optval, sizeof optval,
214					    sizeof optval);
215			if (error)
216				break;
217			if (optval)
218				at_pcb->ddp_flags |= DDPFLG_SLFSND;
219			else
220				at_pcb->ddp_flags &= ~DDPFLG_SLFSND;
221			break;
222                default:
223			error = ENOPROTOOPT;
224			break;
225		}
226		break;
227	}
228
229	return(error);
230} /* ddp_cloutput */
231
232/****************************************************************/
233/*								*/
234/*								*/
235/*			Support Routines			*/
236/*								*/
237/*								*/
238/****************************************************************/
239
240/*
241 * Name:
242 * 	ddp_checksum
243 *
244 * Description:
245 *	This procedure determines the checksum of an extended DDP datagram.
246 *      Add the unsigned bytes into an unsigned 16-bit accumulator.
247 *      After each add, rotate the sign bit into the low order bit of
248 *      the accumulator. When done, if the checksum is 0, changed into 0xFFFF.
249 *
250 * Calling sequence:
251 *	checksum = ddp_checksum(mp, offset)
252 *
253 * Parameters:
254 *	mp		pointer to the datagram gbuf_t
255 *	offset		offset to start at in first gbuf_t block
256 *
257 * Return value:
258 *	The DDP checksum.
259 *
260 */
261
262u_short ddp_checksum(mp, offset)
263     register gbuf_t	*mp;
264     register int	offset;
265{
266	register u_char	*data;
267	register int   	 length;
268	register u_short checksum;
269
270	checksum = 0;
271
272	do {
273		if (offset >= gbuf_len(mp))
274			offset -= gbuf_len(mp);
275		else {
276			data = ((unsigned char *) gbuf_rptr(mp)) + offset;
277			length = gbuf_len(mp) - offset;
278			offset = 0;
279			/* Portable checksum from 3.0 */
280		   	while (length--) {
281				checksum += *data++;
282				checksum = (checksum & 0x8000) ?
283					((checksum << 1) | 1) : (checksum << 1);
284			}
285		}
286	} while ( (mp = gbuf_cont(mp)) );
287
288	if (checksum == 0)
289		checksum = 0xffff;
290
291	return(checksum);
292}
293
294/*
295 * ddp_add_if()
296 *
297 * Description:
298 *	This procedure is called by each LAP interface when it wants to place
299 *	itself online.  The LAP interfaces passes in a pointer to its at_if
300 *	struct, which is added to DDP's list of active interfaces (at_ifQueueHd).
301 *	When DDP wants to transmit a packet, it searches this list for the
302 *	interface to use.
303 *
304 *	If AT_IFF_DEFAULT is set, then this interface is to be brought online
305 *	as the interface DDP socket addresses are tied to.  Of course there can
306 *	be only one default interface; we return an error if it's already set.
307 *
308 * Calling Sequence:
309 *	ret_status = ddp_add_if(ifID)
310 *
311 * Formal Parameters:
312 *	ifID		pointer to LAP interface's at_if struct.
313 *
314 * Completion Status:
315 *	0		Procedure successfully completed.
316 *	EALREADY	This interface is already online, or there is
317 *			already a default interface.
318 *	ENOBUFS		Cannot allocate input queue
319 *
320 */
321int ddp_add_if(ifID)
322register at_ifaddr_t	*ifID;
323{
324	int port = -1;
325
326	dPrintf(D_M_DDP, D_L_STARTUP,
327		("ddp_add_if: called, ifID:0x%x\n", (u_int) ifID));
328
329	if (ifID->ifFlags & AT_IFF_DEFAULT) {
330		if (ifID_home)
331			return(EEXIST);    /* home port already set */
332		else {
333			port = IFID_HOME;
334			ifID_home = ifID;
335		}
336	} else {
337		for (port=IFID_HOME+1; port<IF_TOTAL_MAX; port++)
338			if (!ifID_table[port]) {
339				break;
340		}
341		if (port == IF_TOTAL_MAX)	/* no space left */
342			return(ENOMEM);
343	}
344
345	/* allocate an et_aarp_amt structure */
346	if ((aarp_table[port] =
347	     (aarp_amt_array *)_MALLOC(sizeof(aarp_amt_array),
348				       M_RTABLE, M_WAITOK)) == NULL)
349		return(ENOMEM);
350
351	dPrintf(D_M_DDP, D_L_STARTUP, ("ddp:adding ifID_table[%d]\n", port));
352
353	/* add i/f to port list */
354	ifID_table[port] = ifID;
355	ifID->ifPort = port;	/* set ddp port # in ifID */
356
357	/* Add this interface to the list of online interfaces */
358	TAILQ_INSERT_TAIL(&at_ifQueueHd, ifID, aa_link);
359
360	return (0);
361} /* ddp_add_if */
362
363/*
364 * ddp_rem_if()
365 *
366 * Description:
367 *	This procedure is called by each LAP interface when it wants to take
368 *	itself offline.  The LAP interfaces passes in a pointer to its at_if
369 *	struct; DDP's list of active interfaces (at_ifQueueHd) is searched and
370 *	this interface is removed from the list.  DDP can still transmit
371 *	packets as long as this interface is not the default interface; the
372 *	sender will just get ENETUNREACH errors when it tries to send to an
373 *	interface that went offline.  However, if the default interface is
374 *	taken offline, we no longer have a node ID to use as a source address
375 * 	and DDP must return ENETDOWN when a caller tries to send a packet.
376 *
377 * Formal Parameters:
378 *	ifID		pointer to LAP interface's at_if struct.
379 */
380
381void  ddp_rem_if(ifID)
382     register at_ifaddr_t	*ifID;
383{
384	struct ifaddr *ifa = &ifID->aa_ifa;
385
386	/* un-do processing done in SIOCSIFADDR */
387	ifnet_lock_exclusive(ifID->aa_ifp);
388	IFA_LOCK(ifa);
389	if (ifa->ifa_debug & IFD_ATTACHED) {
390		if_detach_ifa(ifID->aa_ifp, ifa);
391		ifa->ifa_addr = NULL;
392	}
393	IFA_UNLOCK(ifa);
394	/* release reference held for at_interfaces[] */
395	IFA_REMREF(ifa);
396	ifnet_lock_done(ifID->aa_ifp);
397
398	if (ifID->at_was_attached == 0 && ifID->aa_ifp != NULL) {
399		(void)proto_unplumb(PF_APPLETALK, ifID->aa_ifp);
400	}
401
402	/* un-do processing done in ddp_add_if() */
403	if (ifID->ifPort) {
404		if (aarp_table[ifID->ifPort]) {
405			FREE(aarp_table[ifID->ifPort], M_RTABLE);
406			aarp_table[ifID->ifPort] = NULL;
407		}
408
409		at_state.flags |= AT_ST_IF_CHANGED;
410		ifID->aa_ifp = NULL;
411
412		trackrouter_rem_if(ifID);
413		TAILQ_REMOVE(&at_ifQueueHd, ifID, aa_link);
414		ifID_table[ifID->ifPort] = NULL;
415		ifID->ifName[0] = '\0';
416		ifID->ifPort = 0;
417	}
418
419	/* *** deallocate ifID, eventually *** */
420} /* ddp_rem_if */
421
422/*
423 * The user may have registered an NVE with the NBP on a socket.  When the
424 * socket is closed, the NVE should be deleted from NBP's name table.  The
425 * user should delete the NVE before the socket is shut down, but there
426 * may be circumstances when they can't.  So, whenever a DDP socket is closed,
427 * this routine is used to notify NBP of the socket closure.  This would
428 * help NBP get rid of all NVE's registered on the socket.
429 */
430
431/* *** Do we still need to do this? *** */
432static int ot_ddp_check_socket(socket, pid)
433     unsigned char socket;
434     int pid;
435{
436	int cnt = 0;
437	gref_t *gref;
438
439	dPrintf(D_M_DDP, D_L_INFO, ("ot_ddp_check_socket: %d\n", socket));
440	for (gref = ddp_head.atpcb_next; gref != &ddp_head; gref = gref->atpcb_next)
441		if (gref->lport == socket && gref->pid == pid)
442		     cnt++;
443	if ((atp_inputQ[socket] != NULL) && (atp_inputQ[socket] != (gref_t *)1)
444	    && (atp_pidM[socket] == pid))
445		cnt++;
446	if ((adsp_inputQ[socket] != NULL) && (adsp_pidM[socket] == pid))
447		cnt++;
448
449	return(cnt);
450}
451
452void ddp_notify_nbp(
453     unsigned char socket,
454     int pid,
455     __unused unsigned char ddptype)
456{
457	nve_entry_t *nve_entry, *nve_next;
458
459	if (at_state.flags & AT_ST_STARTED) {
460		/* *** NBP_CLOSE_NOTE processing (from ddp_nbp.c) *** */
461                for ((nve_entry = TAILQ_FIRST(&name_registry)); nve_entry; nve_entry = nve_next) {
462                        nve_next = TAILQ_NEXT(nve_entry, nve_link);
463			if ((at_socket)socket == nve_entry->address.socket &&
464			    /* *** check complete address and ddptype here *** */
465			    pid == nve_entry->pid &&
466			    ot_ddp_check_socket(nve_entry->address.socket,
467						nve_entry->pid) < 2) {
468                                /* NB: nbp_delete_entry calls TAILQ_REMOVE */
469				nbp_delete_entry(nve_entry);
470			}
471		}
472	}
473} /* ddp_notify_nbp */
474
475static void fillin_pkt_chain(m)
476     gbuf_t *m;
477{
478	gbuf_t *tmp_m = m;
479	register at_ddp_t
480	  *ddp = (at_ddp_t *)gbuf_rptr(m),
481	  *tmp_ddp;
482	u_short tmp;
483
484	if (UAS_VALUE(ddp->checksum)) {
485		tmp = ddp_checksum(m, 4);
486		UAS_ASSIGN_HTON(ddp->checksum, tmp);
487	}
488
489	for (tmp_m=gbuf_next(tmp_m); tmp_m; tmp_m=gbuf_next(tmp_m)) {
490		tmp_ddp = (at_ddp_t *)gbuf_rptr(tmp_m);
491		DDPLEN_ASSIGN(tmp_ddp, gbuf_msgsize(tmp_m));
492		tmp_ddp->hopcount =
493		  tmp_ddp->unused = 0;
494		NET_NET(tmp_ddp->src_net, ddp->src_net);
495		tmp_ddp->src_node = ddp->src_node;
496		tmp_ddp->src_socket = ddp->src_socket;
497		if (UAS_VALUE(tmp_ddp->checksum)) {
498			tmp = ddp_checksum(tmp_m, 4);
499			UAS_ASSIGN_HTON(ddp->checksum, tmp);
500		}
501	}
502}
503
504/* There are various ways a packet may go out.... it may be sent out
505 * directly to destination node, or sent to a random router or sent
506 * to a router whose entry exists in Best Router Cache.  Following are
507 * constants used WITHIN this routine to keep track of choice of destination
508 */
509#define DIRECT_ADDR	1
510#define	BRT_ENTRY	2
511#define	BRIDGE_ADDR	3
512
513/*
514 * ddp_output()
515 *
516 * Remarks :
517 *	Called to queue a atp/ddp data packet on the network interface.
518 *	It returns 0 normally, and an errno in case of error.
519 *	The mbuf chain pointed to by *mp is consumed on success, and
520 *		freed in case of error.
521 *
522 */
523int ddp_output(mp, src_socket, src_addr_included)
524     register gbuf_t	**mp;
525     at_socket	src_socket;
526     int src_addr_included;
527{
528	register at_ifaddr_t	*ifID = ifID_home, *ifIDTmp = NULL;
529	register at_ddp_t	*ddp;
530	register ddp_brt_t	*brt = NULL;
531	register at_net_al	dst_net;
532	register int 		len;
533	struct	 atalk_addr	at_dest;
534	at_ifaddr_t		*ARouterIf = NULL;
535	int loop = 0;
536	int error = 0;
537	int addr_type;
538	u_char	addr_flag = 0;
539	char	*addr = NULL;
540	register gbuf_t	*m;
541
542	KERNEL_DEBUG(DBG_AT_DDP_OUTPUT | DBG_FUNC_START, 0,
543		     0,0,0,0);
544
545	snmpStats.dd_outReq++;
546
547	m = *mp;
548	ddp = (at_ddp_t *)gbuf_rptr(m);
549
550	if (!ifID) {
551		/* Device/Interface not configured */
552		dPrintf(D_M_DDP, D_L_ERROR, ("Device/Interface not configured"));
553		error = ENXIO;
554		gbuf_freel(*mp);
555		goto exit_ddp_output;
556	}
557
558	if ((ddp->dst_socket > (unsigned) (DDP_SOCKET_LAST + 1)) ||
559	    (ddp->dst_socket < DDP_SOCKET_1st_RESERVED)) {
560		dPrintf(D_M_DDP, D_L_ERROR,
561			("Illegal destination socket on outgoing packet (0x%x)",
562			 ddp->dst_socket));
563		at_ddp_stats.xmit_bad_addr++;
564		error = ENOTSOCK;
565		gbuf_freel(*mp);
566		goto exit_ddp_output;
567	}
568	if ((len = gbuf_msgsize(*mp)) > DDP_DATAGRAM_SIZE) {
569	        /* the packet is too large */
570	        dPrintf(D_M_DDP, D_L_ERROR,
571			("Outgoing packet too long (len=%d bytes)", len));
572		at_ddp_stats.xmit_bad_length++;
573		error = EMSGSIZE;
574		gbuf_freel(*mp);
575		goto exit_ddp_output;
576	}
577	at_ddp_stats.xmit_bytes += len;
578	at_ddp_stats.xmit_packets++;
579
580	DDPLEN_ASSIGN(ddp, len);
581	ddp->hopcount =
582	  ddp->unused = 0;
583
584	/* If this packet is for the same node, loop it back
585	 * up...  Note that for LocalTalk, dst_net zero means "THIS_NET", so
586	 * address 0.nn is eligible for loopback.  For Extended EtherTalk,
587	 * dst_net 0 can be used only for cable-wide or zone-wide
588	 * broadcasts (0.ff) and as such, address of the form 0.nn is NOT
589	 * eligible for loopback.
590	 */
591	dst_net = NET_VALUE(ddp->dst_net);
592
593	/* If our packet is destined for the 'virtual' bridge
594	 * address of NODE==0xFE, replace that address with a
595	 * real bridge address.
596	 */
597	if ((ddp->dst_node == 0xfe) &&
598	    ((dst_net == ATADDR_ANYNET) ||
599	     (dst_net >= ifID_home->ifThisCableStart &&
600	      dst_net <= ifID_home->ifThisCableEnd))) {
601		/* if there's a router that's not us, it's in ifID_home */
602		NET_ASSIGN(ddp->dst_net, ifID_home->ifARouter.s_net);
603		dst_net = ifID_home->ifARouter.s_net;
604		ddp->dst_node = ifID_home->ifARouter.s_node;
605	}
606
607	if (MULTIHOME_MODE && (ifIDTmp = forUs(ddp))) {
608		ifID = ifIDTmp;
609		loop = TRUE;
610		dPrintf(D_M_DDP_LOW, D_L_USR1,
611			("ddp_out: for us if:%s\n", ifIDTmp->ifName));
612	}
613
614	if (!loop)
615		loop = ((ddp->dst_node == ifID->ifThisNode.s_node) &&
616			(dst_net == ifID->ifThisNode.s_net)
617			);
618	if (loop) {
619		gbuf_t *mdata, *mdata_next;
620
621		if (!MULTIHOME_MODE || !src_addr_included) {
622			NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
623			ddp->src_node = ifID->ifThisNode.s_node;
624		}
625		ddp->src_socket = src_socket;
626
627		dPrintf(D_M_DDP_LOW, D_L_OUTPUT,
628			("ddp_output: loop to %d:%d port=%d\n",
629			  NET_VALUE(ddp->dst_net),
630			  ddp->dst_node,
631			  ifID->ifPort));
632
633		fillin_pkt_chain(*mp);
634
635		dPrintf(D_M_DDP, D_L_VERBOSE,
636			("Looping back packet from skt 0x%x to skt 0x%x\n",
637			ddp->src_socket, ddp->dst_socket));
638
639		for (mdata = *mp; mdata; mdata = mdata_next) {
640			mdata_next = gbuf_next(mdata);
641			gbuf_next(mdata) = 0;
642			ddp_input(mdata, ifID);
643		}
644		goto exit_ddp_output;
645	}
646        if ((ddp->dst_socket == ZIP_SOCKET) &&
647	    (zip_type_packet(*mp) == ZIP_GETMYZONE)) {
648	        ddp->src_socket = src_socket;
649	        error = zip_handle_getmyzone(ifID, *mp);
650		gbuf_freel(*mp);
651		goto exit_ddp_output;
652	}
653	/*
654	 * find out the interface on which the packet should go out
655	 */
656	TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
657		if ((ifID->ifThisNode.s_net == dst_net) || (dst_net == 0))
658			/* the message is either going out (i) on the same
659			 * NETWORK in case of LocalTalk, or (ii) on the same
660			 * CABLE in case of Extended AppleTalk (EtherTalk).
661			 */
662			break;
663
664		if ((ifID->ifThisCableStart <= dst_net) &&
665		    (ifID->ifThisCableEnd   >= dst_net)
666		   )
667			/* We're on EtherTalk and the message is going out to
668			 * some other network on the same cable.
669			 */
670			break;
671
672		if (ARouterIf == NULL && ATALK_VALUE(ifID->ifARouter))
673			ARouterIf = ifID;
674	}
675	dPrintf(D_M_DDP_LOW, D_L_USR1,
676			("ddp_output: after search ifid:0x%x %s ifID_home:0x%x\n",
677			(u_int)ifID, ifID ? ifID->ifName : "",
678			(u_int)ifID_home));
679
680	if (ifID) {
681		/* located the interface where the packet should
682		 * go.... the "first-hop" destination address
683		 * must be the same as real destination address.
684		 */
685		addr_type = DIRECT_ADDR;
686	} else {
687		/* no, the destination network number does
688		 * not match known network numbers.  If we have
689		 * heard from this network recently, BRT table
690		 * may have address of a router we could use!
691		 */
692		if (!MULTIPORT_MODE) {
693			BRT_LOOK (brt, dst_net);
694			if (brt) {
695				/* Bingo... BRT has an entry for this network.
696				 * Use the link address as is.
697				 */
698				dPrintf(D_M_DDP, D_L_VERBOSE,
699					("Found BRT entry to send to net 0x%x", dst_net));
700				at_ddp_stats.xmit_BRT_used++;
701				addr_type = BRT_ENTRY;
702				ifID = brt->ifID;
703			} else {
704				/* No BRT entry available for dest network... do we
705				 * know of any router at all??
706				 */
707				if ((ifID = ARouterIf) != NULL)
708					addr_type = BRIDGE_ADDR;
709				else {
710		 		dPrintf(D_M_DDP, D_L_WARNING,
711						("Found no interface to send pkt"));
712					at_ddp_stats.xmit_bad_addr++;
713					error = ENETUNREACH;
714					gbuf_freel(*mp);
715					goto exit_ddp_output;
716				}
717			}
718		}
719		else { /* We are in multiport mode,  so we can bypass all the rest
720			* and directly ask for the routing of the packet
721			*/
722			at_ddp_stats.xmit_BRT_used++;
723
724			ifID = ifID_home;
725			if (!src_addr_included) {
726			  ddp->src_node = ifID->ifThisNode.s_node;
727			  NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
728			}
729			ddp->src_socket = src_socket;
730			routing_needed(*mp, ifID, TRUE);
731
732			goto exit_ddp_output;
733		}
734	}
735	/* by the time we land here, we know the interface on
736	 * which this packet is going out....  ifID.
737	 */
738	if (ifID->ifState == LAP_OFFLINE) {
739		gbuf_freel(*mp);
740		goto exit_ddp_output;
741	}
742
743	switch (addr_type) {
744		case DIRECT_ADDR :
745/*
746			at_dest.atalk_unused = 0;
747*/
748			NET_ASSIGN(at_dest.atalk_net, dst_net);
749			at_dest.atalk_node = ddp->dst_node;
750			addr_flag = AT_ADDR;
751			addr = (char *)&at_dest;
752			break;
753		case BRT_ENTRY :
754			addr_flag = ET_ADDR;
755			addr = (char *)&brt->et_addr;
756			break;
757		case BRIDGE_ADDR :
758			NET_ASSIGN(at_dest.atalk_net, ifID->ifARouter.s_net);
759			at_dest.atalk_node = ifID->ifARouter.s_node;
760			addr_flag = AT_ADDR;
761			addr = (char *)&at_dest;
762			break;
763
764	}
765	/* Irrespective of the interface on which
766	 * the packet is going out, we always put the
767	 * same source address on the packet (unless multihoming mode).
768	 */
769	if (MULTIHOME_MODE) {
770		if (!src_addr_included) {
771			ddp->src_node = ifID->ifThisNode.s_node;
772			NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
773		}
774	}
775	else {
776		ddp->src_node = ifID_home->ifThisNode.s_node;
777		NET_ASSIGN(ddp->src_net, ifID_home->ifThisNode.s_net);
778	}
779	ddp->src_socket = src_socket;
780
781	dPrintf(D_M_DDP_LOW, D_L_OUTPUT,
782		("ddp_output: going out to %d:%d skt%d on %s\n",
783		dst_net, ddp->dst_node, ddp->dst_socket, ifID->ifName));
784
785	fillin_pkt_chain(*mp);
786
787	{ /* begin block */
788	struct	etalk_addr	dest_addr;
789	struct	atalk_addr	dest_at_addr;
790
791	loop = TRUE;		/* flag to aarp to loopback (default) */
792
793	m = *mp;
794
795	/* the incoming frame is of the form {flag, address, ddp...}
796	 * where "flag" indicates whether the address is an 802.3
797	 * (link) address, or an appletalk address.  If it's an
798	 * 802.3 address, the packet can just go out to the network
799	 * through PAT, if it's an appletalk address, AT->802.3 address
800	 * resolution needs to be done.
801	 * If 802.3 address is known, strip off the flag and 802.3
802	 * address, and prepend 802.2 and 802.3 headers.
803	 */
804
805	if (addr == NULL) {
806		addr_flag = *(u_char *)gbuf_rptr(m);
807		gbuf_rinc(m,1);
808	}
809
810	switch (addr_flag) {
811	case AT_ADDR_NO_LOOP :
812		loop = FALSE;
813		/* pass thru */
814	case AT_ADDR :
815		if (addr == NULL) {
816		    dest_at_addr = *(struct atalk_addr *)gbuf_rptr(m);
817		    gbuf_rinc(m,sizeof(struct atalk_addr));
818		} else
819		    dest_at_addr = *(struct atalk_addr *)addr;
820		break;
821	case ET_ADDR :
822		if (addr == NULL) {
823		  dest_addr = *(struct etalk_addr *)gbuf_rptr(m);
824		  gbuf_rinc(m,sizeof(struct etalk_addr));
825		} else
826		  dest_addr = *(struct etalk_addr *)addr;
827		break;
828	default :
829		dPrintf(D_M_DDP_LOW,D_L_ERROR,
830		    ("ddp_output: Unknown addr_flag = 0x%x\n", addr_flag));
831		gbuf_freel(m);		/* unknown address type, chuck it */
832		goto exit_ddp_output;
833        }
834
835	m = gbuf_strip(m);
836
837	/* At this point, rptr points to ddp header for sure */
838	if (ifID->ifState == LAP_ONLINE_FOR_ZIP) {
839		/* see if this is a ZIP packet that we need
840		 * to let through even though network is
841		 * not yet alive!!
842		 */
843		if (zip_type_packet(m) == 0) {
844			gbuf_freel(m);
845			goto exit_ddp_output;
846		}
847	}
848
849	ifID->stats.xmit_packets++;
850	ifID->stats.xmit_bytes += gbuf_msgsize(m);
851	snmpStats.dd_outLong++;
852
853	switch (addr_flag) {
854	case AT_ADDR_NO_LOOP :
855	case AT_ADDR :
856	    /*
857	     * we don't want elap to be looking into ddp header, so
858	     * it doesn't know net#, consequently can't do
859	     * AMT_LOOKUP.  That task left to aarp now.
860	     */
861	    aarp_send_data(m,ifID, &dest_at_addr, loop);
862	    break;
863	case ET_ADDR :
864	    pat_output(ifID, m, (unsigned char *)&dest_addr, 0);
865	    break;
866        }
867	} /* end block */
868 exit_ddp_output:
869	KERNEL_DEBUG(DBG_AT_DDP_OUTPUT | DBG_FUNC_END, 0,
870		     error, 0, 0, 0);
871	return(error);
872} /* ddp_output */
873
874void ddp_input(mp, ifID)
875     register gbuf_t   *mp;
876     register at_ifaddr_t *ifID;
877{
878	register at_ddp_t *ddp;		/* DDP header */
879	register int       msgsize;
880	register at_socket socket;
881	register int	   len;
882	register at_net_al dst_net;
883
884	KERNEL_DEBUG(DBG_AT_DDP_INPUT | DBG_FUNC_START, 0,
885		     ifID, mp, gbuf_len(mp),0);
886
887	/* Makes sure we know the default interface before starting to
888	 * accept incomming packets. If we don't we may end up with a
889	 * null ifID_table[0] and have impredicable results (specially
890	 * in router mode. This is a transitory state (because we can
891	 * begin to receive packet while we're not completly set up yet.
892	 */
893
894	if (ifID_home == (at_ifaddr_t *)NULL) {
895		dPrintf(D_M_DDP, D_L_ERROR,
896			("dropped incoming packet ifID_home not set yet\n"));
897		gbuf_freem(mp);
898		goto out; /* return */
899	}
900
901	/*
902	 * if a DDP packet has been broadcast, we're going to get a copy of
903	 * it here; if it originated at user level via a write on a DDP
904	 * socket; when it gets here, the first block in the chain will be
905	 * empty since it only contained the lap level header which will be
906	 * stripped in the lap level immediately below ddp
907	 */
908
909	if ((mp = (gbuf_t *)ddp_compress_msg(mp)) == NULL) {
910		dPrintf(D_M_DDP, D_L_ERROR,
911			("dropped short incoming ET packet (len %d)", 0));
912		snmpStats.dd_inTotal++;
913		at_ddp_stats.rcv_bad_length++;
914		goto out; /* return; */
915	}
916	msgsize = gbuf_msgsize(mp);
917
918	at_ddp_stats.rcv_bytes += msgsize;
919	at_ddp_stats.rcv_packets++;
920
921	/* if the interface pointer is 0, the packet has been
922	 * looped back by 'write' half of DDP.  It is of the
923	 * form {extended ddp,...}.  The packet is meant to go
924	 * up to some socket on the same node.
925	 */
926	if (!ifID)			/* if loop back is specified */
927		ifID = ifID_home;	/* that means the home port */
928
929	/* the incoming datagram has extended DDP header and is of
930	 * the form {ddp,...}.
931	 */
932	if (msgsize < DDP_X_HDR_SIZE) {
933		dPrintf(D_M_DDP, D_L_ERROR,
934			("dropped short incoming ET packet (len %d)", msgsize));
935		at_ddp_stats.rcv_bad_length++;
936		gbuf_freem(mp);
937		goto out; /* return; */
938	}
939	/*
940	 * At this point, the message is always of the form
941	 * {extended ddp, ... }.
942	 */
943	ddp = (at_ddp_t *)gbuf_rptr(mp);
944	len = DDPLEN_VALUE(ddp);
945
946	if (msgsize != len) {
947	        if (msgsize > len) {
948		        if (len < DDP_X_HDR_SIZE) {
949			        dPrintf(D_M_DDP, D_L_ERROR,
950				       ("Length problems, ddp length %d, buffer length %d",
951				       len, msgsize));
952				snmpStats.dd_tooLong++;
953				at_ddp_stats.rcv_bad_length++;
954				gbuf_freem(mp);
955				goto out; /* return; */
956			}
957		        /*
958			 * shave off the extra bytes from the end of message
959		         */
960		        mp = ddp_adjmsg(mp, -(msgsize - len)) ? mp : 0;
961		        if (mp == 0)
962				goto out; /* return; */
963		} else {
964		        dPrintf(D_M_DDP, D_L_ERROR,
965				("Length problems, ddp length %d, buffer length %d",
966				len, msgsize));
967				snmpStats.dd_tooShort++;
968			at_ddp_stats.rcv_bad_length++;
969			gbuf_freem(mp);
970			goto out; /* return; */
971		}
972	}
973	socket = ddp->dst_socket;
974
975	/*
976	 * We want everything in router mode, specially socket 254 for nbp so we need
977	 * to bypass this test when we are a router.
978	 */
979
980	if (!MULTIPORT_MODE && (socket > DDP_SOCKET_LAST ||
981			 socket < DDP_SOCKET_1st_RESERVED)) {
982		dPrintf(D_M_DDP, D_L_WARNING,
983			("Bad dst socket on incoming packet (0x%x)",
984			ddp->dst_socket));
985		at_ddp_stats.rcv_bad_socket++;
986		gbuf_freem(mp);
987		goto out; /* return; */
988	}
989	/*
990	 * if the checksum is true, then upstream wants us to calc
991	 */
992	if (UAS_VALUE(ddp->checksum) &&
993           (UAS_VALUE_NTOH(ddp->checksum) != ddp_checksum(mp, 4))) {
994		dPrintf(D_M_DDP, D_L_WARNING,
995			("Checksum error on incoming pkt, calc 0x%x, exp 0x%x",
996			ddp_checksum(mp, 4), UAS_VALUE_NTOH(ddp->checksum)));
997		snmpStats.dd_checkSum++;
998		at_ddp_stats.rcv_bad_checksum++;
999		gbuf_freem(mp);
1000		goto out; /* return; */
1001	}
1002
1003/*############### routing input checking */
1004
1005/* Router mode special: we send "up-stack" packets for this node or coming from any
1006 * other ports, but for the reserved atalk sockets (RTMP, ZIP, NBP [and EP])
1007 * BTW, the way we know it's for the router and not the home port is that the
1008 * MAC (ethernet) address is always the one of the interface we're on, but
1009 * the AppleTalk address must be the one of the home port. If it's a multicast
1010 * or another AppleTalk address, this is the router job's to figure out where it's
1011 * going to go.
1012 */
1013	/* *** a duplicate should be sent to any other client that is listening
1014	   for packets of this type on a raw DDP socket *** */
1015	if (ddp_handler[socket].func) {
1016		dPrintf(D_M_DDP,D_L_INPUT,
1017			("ddp_input: skt %u hdnlr:0x%p\n",
1018			 (u_int) socket, ddp_handler[socket].func));
1019		pktsHome++;
1020		snmpStats.dd_inLocal++;
1021
1022		(*ddp_handler[socket].func)(mp, ifID);
1023		goto out; /* return; */
1024	}
1025	dst_net = NET_VALUE(ddp->dst_net);
1026	if (
1027	    /* exact match */
1028	    forUs(ddp) ||
1029	    /* any node, wildcard or matching net */
1030	    ((ddp->dst_node == 255) &&
1031	     (((dst_net >= ifID_home->ifThisCableStart) &&
1032	       (dst_net <= ifID_home->ifThisCableEnd)) ||
1033	      dst_net == 0)) ||
1034	    /* this node is not online yet(?) */
1035	    (ifID->ifRoutingState < PORT_ONLINE)
1036	    ) {
1037		gref_t   *gref;
1038		pktsHome++;
1039		snmpStats.dd_inLocal++;
1040
1041		if (ddp->type == DDP_ATP) {
1042		  if (atp_inputQ[socket] && (atp_inputQ[socket] != (gref_t *)1)) {
1043			/* if there's an ATP pcb */
1044			atp_input(mp);
1045			goto out; /* return; */
1046		  }
1047		} else if (ddp->type == DDP_ADSP) {
1048		  if (adsp_inputQ[socket]) {
1049		        /* if there's an ADSP pcb */
1050			adsp_input(mp);
1051			goto out; /* return; */
1052		  }
1053		}
1054
1055		/* otherwise look for a DDP pcb;
1056		   ATP / raw-DDP and ADSP / raw-DDP are possible */
1057		for (gref = ddp_head.atpcb_next; gref != &ddp_head;
1058		       gref = gref->atpcb_next)
1059		    if (gref->lport == socket &&
1060		    	(gref->ddptype == 0 || gref->ddptype == ddp->type)) {
1061					dPrintf(D_M_DDP, D_L_INPUT,
1062					("ddp_input: streamq, skt %d\n", socket));
1063			if (gref->atpcb_socket) {
1064				struct sockaddr_at ddp_in;
1065				ddp_in.sat_len = sizeof(ddp_in);
1066				ddp_in.sat_family = AF_APPLETALK;
1067				ddp_in.sat_addr.s_net = NET_VALUE(ddp->src_net);
1068				ddp_in.sat_addr.s_node = ddp->src_node;
1069				ddp_in.sat_port = ddp->src_socket;
1070
1071				/* strip off DDP header if so indicated by
1072				   sockopt */
1073				if (gref->ddp_flags & DDPFLG_STRIPHDR) {
1074					mp = m_pullup((struct mbuf *)mp,
1075                                                           DDP_X_HDR_SIZE);
1076					if (mp) {
1077						gbuf_rinc(mp, DDP_X_HDR_SIZE);
1078					} else {
1079					  /* this should never happen because
1080					     msgsize was checked earlier */
1081						at_ddp_stats.rcv_bad_length++;
1082					 	goto out; /* return */
1083					}
1084				}
1085
1086				if (sbappendaddr(&((gref->atpcb_socket)->so_rcv),
1087						 (struct sockaddr *)&ddp_in,
1088						 mp, 0, NULL) != 0) {
1089				 	sorwakeup(gref->atpcb_socket);
1090				 }
1091			} else {
1092				atalk_putnext(gref, mp);
1093			}
1094			goto out; /* return */
1095		    }
1096
1097		at_ddp_stats.rcv_bad_socket++;
1098		gbuf_freem(mp);
1099		snmpStats.dd_noHandler++;
1100		dPrintf(D_M_DDP, D_L_WARNING,
1101			("ddp_input: dropped pkt for socket %d\n", socket));
1102	} else {
1103		dPrintf(D_M_DDP, D_L_ROUTING,
1104			("ddp_input: routing_needed from  port=%d sock=%d\n",
1105			 ifID->ifPort, ddp->dst_socket));
1106
1107		snmpStats.dd_fwdReq++;
1108		if (((pktsIn-pktsHome+200) >= RouterMix) && ((++pktsDropped % 5) == 0)) {
1109			at_ddp_stats.rcv_dropped_nobuf++;
1110			gbuf_freem(mp);
1111		}
1112		else {
1113			routing_needed(mp, ifID, FALSE);
1114		}
1115	}
1116out:
1117	KERNEL_DEBUG(DBG_AT_DDP_INPUT | DBG_FUNC_END, 0,0,0,0,0);
1118} /* ddp_input */
1119
1120
1121/*
1122 * ddp_router_output()
1123 *
1124 * Remarks :
1125 *	This is a modified version of ddp_output for router use.
1126 *	The main difference is that the interface on which the packet needs
1127 *	to be sent is specified and a *destination* AppleTalk address is passed
1128 *	as an argument, this address may or may not be the same as the destination
1129 *	address found in the ddp packet... This is the trick about routing, the
1130 *	AppleTalk destination of the packet may not be the same as the Enet address
1131 *	we send the packet too (ie, we may pass the baby to another router).
1132 *
1133 */
1134int ddp_router_output(mp, ifID, addr_type, router_net, router_node, enet_addr)
1135     gbuf_t	*mp;
1136     at_ifaddr_t *ifID;
1137     int addr_type;
1138     at_net_al router_net;
1139     at_node router_node;
1140     etalk_addr_t *enet_addr;
1141{
1142	register at_ddp_t	*ddp;
1143	struct	 atalk_addr	at_dest;
1144	int		addr_flag = 0;
1145	char	*addr = NULL;
1146	register gbuf_t	*m;
1147
1148	if (!ifID) {
1149		dPrintf(D_M_DDP, D_L_WARNING, ("BAD BAD ifID\n"));
1150		gbuf_freel(mp);
1151		return(EPROTOTYPE);
1152	}
1153	ddp = (at_ddp_t *)gbuf_rptr(mp);
1154
1155#ifdef AURP_SUPPORT
1156	if (ifID->ifFlags & AT_IFF_AURP) { /* AURP link? */
1157		if (ddp_AURPsendx) {
1158			fillin_pkt_chain(mp);
1159			if (router_node == 255)
1160				router_node = 0;
1161			ddp_AURPsendx(AURPCODE_DATAPKT, mp, router_node);
1162			return 0;
1163		} else {
1164			gbuf_freel(mp);
1165			return EPROTOTYPE;
1166		}
1167	}
1168#endif
1169
1170	/* keep some of the tests for now ####### */
1171
1172	if (gbuf_msgsize(mp) > DDP_DATAGRAM_SIZE) {
1173	        /* the packet is too large */
1174		dPrintf(D_M_DDP, D_L_WARNING,
1175			("ddp_router_output: Packet too large size=%d\n",
1176			 gbuf_msgsize(mp)));
1177		gbuf_freel(mp);
1178		return (EMSGSIZE);
1179	}
1180
1181	switch (addr_type) {
1182
1183		case AT_ADDR :
1184
1185			/*
1186			 * Check for packet destined to the home stack
1187			 */
1188
1189		  if	((ddp->dst_node == ifID->ifThisNode.s_node) &&
1190			 (NET_VALUE(ddp->dst_net) == ifID->ifThisNode.s_net)) {
1191		  	dPrintf(D_M_DDP_LOW, D_L_ROUTING,
1192				("ddp_r_output: sending back home from port=%d socket=%d\n",
1193				 ifID->ifPort, ddp->dst_socket));
1194
1195			UAS_ASSIGN(ddp->checksum, 0);
1196			ddp_input(mp, ifID);
1197			return(0);
1198		  }
1199
1200		  NET_ASSIGN(at_dest.atalk_net, router_net);
1201		  at_dest.atalk_node = router_node;
1202
1203		  addr_flag = AT_ADDR_NO_LOOP;
1204		  addr = (char *)&at_dest;
1205		  dPrintf(D_M_DDP_LOW, D_L_ROUTING_AT,
1206			  ("ddp_r_output: AT_ADDR out port=%d net %d:%d via rte %d:%d",
1207			   ifID->ifPort, NET_VALUE(ddp->dst_net), ddp->dst_node, router_net,
1208			   router_node));
1209		  break;
1210
1211		case ET_ADDR :
1212		  addr_flag = ET_ADDR;
1213		  addr = (char *)enet_addr;
1214		  dPrintf(D_M_DDP_LOW, D_L_ROUTING,
1215			  ("ddp_r_output: ET_ADDR out port=%d net %d:%d\n",
1216			   ifID->ifPort, NET_VALUE(ddp->dst_net), ddp->dst_node));
1217		  break;
1218		}
1219
1220	if (ifID->ifState == LAP_OFFLINE) {
1221	      gbuf_freel(mp);
1222	      return 0;
1223	}
1224
1225	fillin_pkt_chain(mp);
1226
1227	{ /* begin block */
1228	    struct	etalk_addr	dest_addr;
1229	    struct	atalk_addr	dest_at_addr;
1230	    int	loop = TRUE;		/* flag to aarp to loopback (default) */
1231
1232	    m = mp;
1233
1234	    /* the incoming frame is of the form {flag, address, ddp...}
1235	     * where "flag" indicates whether the address is an 802.3
1236	     * (link) address, or an appletalk address.  If it's an
1237	     * 802.3 address, the packet can just go out to the network
1238	     * through PAT, if it's an appletalk address, AT->802.3 address
1239	     * resolution needs to be done.
1240	     * If 802.3 address is known, strip off the flag and 802.3
1241	     * address, and prepend 802.2 and 802.3 headers.
1242	     */
1243
1244	    if (addr == NULL) {
1245	    	addr_flag = *(u_char *)gbuf_rptr(m);
1246		gbuf_rinc(m,1);
1247	    }
1248
1249	    switch (addr_flag) {
1250	    case AT_ADDR_NO_LOOP :
1251	      loop = FALSE;
1252	      /* pass thru */
1253	    case AT_ADDR :
1254	      if (addr == NULL) {
1255		dest_at_addr = *(struct atalk_addr *)gbuf_rptr(m);
1256		gbuf_rinc(m,sizeof(struct atalk_addr));
1257	      } else
1258		dest_at_addr = *(struct atalk_addr *)addr;
1259	      break;
1260	    case ET_ADDR :
1261	      if (addr == NULL) {
1262		dest_addr = *(struct etalk_addr *)gbuf_rptr(m);
1263		gbuf_rinc(m,sizeof(struct etalk_addr));
1264	      } else
1265		dest_addr = *(struct etalk_addr *)addr;
1266	      break;
1267	    default :
1268	      dPrintf(D_M_DDP_LOW,D_L_ERROR,
1269		      ("ddp_router_output: Unknown addr_flag = 0x%x\n", addr_flag));
1270
1271	      gbuf_freel(m);		/* unknown address type, chuck it */
1272	      return 0;
1273	    }
1274
1275	    m = gbuf_strip(m);
1276
1277	    /* At this point, rptr points to ddp header for sure */
1278	    if (ifID->ifState == LAP_ONLINE_FOR_ZIP) {
1279		      /* see if this is a ZIP packet that we need
1280		       * to let through even though network is
1281		       * not yet alive!!
1282		       */
1283		      if (zip_type_packet(m) == 0) {
1284			gbuf_freel(m);
1285			return 0;
1286		      }
1287	    }
1288
1289	    ifID->stats.xmit_packets++;
1290	    ifID->stats.xmit_bytes += gbuf_msgsize(m);
1291	    snmpStats.dd_outLong++;
1292
1293	    switch (addr_flag) {
1294	    case AT_ADDR_NO_LOOP :
1295	    case AT_ADDR :
1296	      /*
1297	       * we don't want elap to be looking into ddp header, so
1298	       * it doesn't know net#, consequently can't do
1299	       * AMT_LOOKUP.  That task left to aarp now.
1300	       */
1301	      aarp_send_data(m,ifID,&dest_at_addr, loop);
1302	      break;
1303	    case ET_ADDR :
1304	      pat_output(ifID, m, (unsigned char *)&dest_addr, 0);
1305	      break;
1306	    }
1307	} /* end block */
1308
1309	return(0);
1310} /* ddp_router_output */
1311
1312/*****************************************/
1313
1314#ifdef AURP_SUPPORT
1315
1316void rt_delete(NetStop, NetStart)
1317	unsigned short NetStop;
1318	unsigned short NetStart;
1319{
1320	RT_entry *found;
1321
1322	if ((found = rt_bdelete(NetStop, NetStart)) != 0) {
1323		bzero(found, sizeof(RT_entry));
1324		found->right = RT_table_freelist;
1325		RT_table_freelist = found;
1326	}
1327}
1328
1329int ddp_AURPfuncx(code, param, node)
1330	int code;
1331	void *param;
1332	unsigned char node;
1333{
1334	at_ifaddr_t *ifID;
1335	int k;
1336
1337	switch (code) {
1338	case AURPCODE_DATAPKT: /* data packet */
1339		if (aurp_ifID) {
1340			dPrintf(D_M_DDP, D_L_TRACE, ("ddp_AURPfuncx: data, 0x%x, %d\n",
1341				(u_int) aurp_ifID, node));
1342
1343			ddp_input((gbuf_t *)param, aurp_ifID);
1344		} else
1345			gbuf_freem((gbuf_t *)param);
1346		break;
1347
1348	case AURPCODE_REG: /* register/deregister */
1349		if (!ROUTING_MODE)
1350			return -1;
1351		ddp_AURPsendx = (void(*)())param;
1352
1353		if (param) {
1354			/* register AURP callback function */
1355			if (aurp_ifID)
1356				return 0;
1357			for (k=(IFID_HOME+1); k < IF_TOTAL_MAX; k++) {
1358				if (ifID_table[k] == 0) {
1359					aurp_ifID = &at_interfaces[k];
1360					aurp_ifID->ifFlags = RTR_XNET_PORT;
1361					ddp_add_if(aurp_ifID);
1362					aurp_ifID->ifState = LAP_ONLINE;
1363					aurp_ifID->ifRoutingState = PORT_ONLINE;
1364					dPrintf(D_M_DDP, D_L_TRACE,
1365						("ddp_AURPfuncx: on, 0x%x\n",
1366						(u_int) aurp_ifID));
1367
1368					ddp_AURPsendx(AURPCODE_DEBUGINFO,
1369							&dbgBits, aurp_ifID->ifPort);
1370					return 0;
1371				}
1372			}
1373			return -1;
1374
1375		} else {
1376			/* deregister AURP callback function */
1377			if (aurp_ifID) {
1378				rtmp_purge(aurp_ifID);
1379				ddp_rem_if(aurp_ifID);
1380				aurp_ifID->ifState = LAP_OFFLINE;
1381				aurp_ifID->ifRoutingState = PORT_OFFLINE;
1382				dPrintf(D_M_DDP, D_L_TRACE,
1383					("ddp_AURPfuncx: off, 0x%x\n", (u_int) aurp_ifID));
1384				aurp_ifID = 0;
1385			}
1386		}
1387		break;
1388
1389	case AURPCODE_AURPPROTO: /* proto type - AURP */
1390		if (aurp_ifID) {
1391			aurp_ifID->ifFlags |= AT_IFF_AURP;
1392		}
1393		break;
1394	}
1395
1396	return 0;
1397}
1398#endif
1399
1400/* checks to see if address of packet is for one of our interfaces
1401   returns *ifID if it's for us, NULL if not
1402*/
1403at_ifaddr_t *forUs(ddp)
1404     register at_ddp_t *ddp;
1405{
1406	at_ifaddr_t *ifID;
1407
1408	TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1409		if ((ddp->dst_node == ifID->ifThisNode.s_node) &&
1410		    (NET_VALUE(ddp->dst_net) ==  ifID->ifThisNode.s_net)
1411		   ) {
1412			dPrintf(D_M_DDP_LOW, D_L_ROUTING,
1413				("pkt was for port %d\n", ifID->ifPort));
1414
1415			return(ifID);
1416		}
1417	}
1418
1419	return((at_ifaddr_t *)NULL);
1420} /* forUs */
1421