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