]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/ddp.c
xnu-344.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;
0b4e3aa0 451 nve_entry_t *nve_entry, *nve_next;
1c79356b
A
452
453 if (at_state.flags & AT_ST_STARTED) {
454 /* *** NBP_CLOSE_NOTE processing (from ddp_nbp.c) *** */
455 ATDISABLE(nve_lock, NVE_LOCK);
0b4e3aa0
A
456 for ((nve_entry = TAILQ_FIRST(&name_registry)); nve_entry; nve_entry = nve_next) {
457 nve_next = TAILQ_NEXT(nve_entry, nve_link);
1c79356b
A
458 if ((at_socket)socket == nve_entry->address.socket &&
459 /* *** check complete address and ddptype here *** */
460 pid == nve_entry->pid &&
461 ot_ddp_check_socket(nve_entry->address.socket,
462 nve_entry->pid) < 2) {
0b4e3aa0 463 /* NB: nbp_delete_entry calls TAILQ_REMOVE */
1c79356b
A
464 nbp_delete_entry(nve_entry);
465 }
466 }
467 ATENABLE(nve_lock, NVE_LOCK);
468 }
469} /* ddp_notify_nbp */
470
471static void fillin_pkt_chain(m)
472 gbuf_t *m;
473{
474 gbuf_t *tmp_m = m;
475 register at_ddp_t
476 *ddp = (at_ddp_t *)gbuf_rptr(m),
477 *tmp_ddp;
478 u_short tmp;
479
480 if (UAS_VALUE(ddp->checksum)) {
481 tmp = ddp_checksum(m, 4);
482 UAS_ASSIGN(ddp->checksum, tmp);
483 }
484
485 for (tmp_m=gbuf_next(tmp_m); tmp_m; tmp_m=gbuf_next(tmp_m)) {
486 tmp_ddp = (at_ddp_t *)gbuf_rptr(tmp_m);
487 tmp_ddp->length = gbuf_msgsize(tmp_m);
488 tmp_ddp->hopcount =
489 tmp_ddp->unused = 0;
490 NET_NET(tmp_ddp->src_net, ddp->src_net);
491 tmp_ddp->src_node = ddp->src_node;
492 tmp_ddp->src_socket = ddp->src_socket;
493 if (UAS_VALUE(tmp_ddp->checksum)) {
494 tmp = ddp_checksum(tmp_m, 4);
495 UAS_ASSIGN(tmp_ddp->checksum, tmp);
496 }
497 }
498}
499
500/* There are various ways a packet may go out.... it may be sent out
501 * directly to destination node, or sent to a random router or sent
502 * to a router whose entry exists in Best Router Cache. Following are
503 * constants used WITHIN this routine to keep track of choice of destination
504 */
505#define DIRECT_ADDR 1
506#define BRT_ENTRY 2
507#define BRIDGE_ADDR 3
508
509/*
510 * ddp_output()
511 *
512 * Remarks :
513 * Called to queue a atp/ddp data packet on the network interface.
514 * It returns 0 normally, and an errno in case of error.
515 * The mbuf chain pointed to by *mp is consumed on success, and
516 * freed in case of error.
517 *
518 */
519int ddp_output(mp, src_socket, src_addr_included)
520 register gbuf_t **mp;
521 at_socket src_socket;
522 int src_addr_included;
523{
524 register at_ifaddr_t *ifID = ifID_home, *ifIDTmp = NULL;
525 register at_ddp_t *ddp;
526 register ddp_brt_t *brt;
527 register at_net_al dst_net;
528 register int len;
529 struct atalk_addr at_dest;
530 at_ifaddr_t *ARouterIf = NULL;
531 int loop = 0;
532 int error = 0;
533 int addr_type;
534 u_char addr_flag;
535 char *addr = NULL;
536 register gbuf_t *m;
537
538 KERNEL_DEBUG(DBG_AT_DDP_OUTPUT | DBG_FUNC_START, 0,
539 0,0,0,0);
540
541 snmpStats.dd_outReq++;
542
543 m = *mp;
544 ddp = (at_ddp_t *)gbuf_rptr(m);
9bccf70c
A
545
546 if (!ifID) {
547 /* Device/Interface not configured */
548 dPrintf(D_M_DDP, D_L_ERROR, ("Device/Interface not configured"));
549 error = ENXIO;
550 gbuf_freel(*mp);
551 goto exit_ddp_output;
552 }
1c79356b
A
553
554 if ((ddp->dst_socket > (unsigned) (DDP_SOCKET_LAST + 1)) ||
555 (ddp->dst_socket < DDP_SOCKET_1st_RESERVED)) {
556 dPrintf(D_M_DDP, D_L_ERROR,
557 ("Illegal destination socket on outgoing packet (0x%x)",
558 ddp->dst_socket));
559 at_ddp_stats.xmit_bad_addr++;
560 error = ENOTSOCK;
561 gbuf_freel(*mp);
562 goto exit_ddp_output;
563 }
564 if ((len = gbuf_msgsize(*mp)) > DDP_DATAGRAM_SIZE) {
565 /* the packet is too large */
566 dPrintf(D_M_DDP, D_L_ERROR,
567 ("Outgoing packet too long (len=%d bytes)", len));
568 at_ddp_stats.xmit_bad_length++;
569 error = EMSGSIZE;
570 gbuf_freel(*mp);
571 goto exit_ddp_output;
572 }
573 at_ddp_stats.xmit_bytes += len;
574 at_ddp_stats.xmit_packets++;
575
576 ddp->length = len;
577 ddp->hopcount =
578 ddp->unused = 0;
579
580 /* If this packet is for the same node, loop it back
581 * up... Note that for LocalTalk, dst_net zero means "THIS_NET", so
582 * address 0.nn is eligible for loopback. For Extended EtherTalk,
583 * dst_net 0 can be used only for cable-wide or zone-wide
584 * broadcasts (0.ff) and as such, address of the form 0.nn is NOT
585 * eligible for loopback.
586 */
587 dst_net = NET_VALUE(ddp->dst_net);
588
589 /* If our packet is destined for the 'virtual' bridge
590 * address of NODE==0xFE, replace that address with a
591 * real bridge address.
592 */
593 if ((ddp->dst_node == 0xfe) &&
594 ((dst_net == ATADDR_ANYNET) ||
595 (dst_net >= ifID_home->ifThisCableStart &&
596 dst_net <= ifID_home->ifThisCableEnd))) {
597 /* if there's a router that's not us, it's in ifID_home */
598 NET_ASSIGN(ddp->dst_net, ifID_home->ifARouter.s_net);
599 dst_net = ifID_home->ifARouter.s_net;
600 ddp->dst_node = ifID_home->ifARouter.s_node;
601 }
602
603 if (MULTIHOME_MODE && (ifIDTmp = forUs(ddp))) {
604 ifID = ifIDTmp;
605 loop = TRUE;
606 dPrintf(D_M_DDP_LOW, D_L_USR1,
607 ("ddp_out: for us if:%s\n", ifIDTmp->ifName));
608 }
609
610 if (!loop)
611 loop = ((ddp->dst_node == ifID->ifThisNode.s_node) &&
612 (dst_net == ifID->ifThisNode.s_net)
613 );
614 if (loop) {
615 gbuf_t *mdata, *mdata_next;
616
617 if (!MULTIHOME_MODE || !src_addr_included) {
618 NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
619 ddp->src_node = ifID->ifThisNode.s_node;
620 }
621 ddp->src_socket = src_socket;
622
623 dPrintf(D_M_DDP_LOW, D_L_OUTPUT,
624 ("ddp_output: loop to %d:%d port=%d\n",
625 NET_VALUE(ddp->dst_net),
626 ddp->dst_node,
627 ifID->ifPort));
628
629 fillin_pkt_chain(*mp);
630
631 dPrintf(D_M_DDP, D_L_VERBOSE,
632 ("Looping back packet from skt 0x%x to skt 0x%x\n",
633 ddp->src_socket, ddp->dst_socket));
634
635 for (mdata = *mp; mdata; mdata = mdata_next) {
636 mdata_next = gbuf_next(mdata);
637 gbuf_next(mdata) = 0;
638 ddp_input(mdata, ifID);
639 }
640 goto exit_ddp_output;
641 }
642 if ((ddp->dst_socket == ZIP_SOCKET) &&
643 (zip_type_packet(*mp) == ZIP_GETMYZONE)) {
644 ddp->src_socket = src_socket;
645 error = zip_handle_getmyzone(ifID, *mp);
646 gbuf_freel(*mp);
647 goto exit_ddp_output;
648 }
649 /*
650 * find out the interface on which the packet should go out
651 */
652 TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
653 if ((ifID->ifThisNode.s_net == dst_net) || (dst_net == 0))
654 /* the message is either going out (i) on the same
655 * NETWORK in case of LocalTalk, or (ii) on the same
656 * CABLE in case of Extended AppleTalk (EtherTalk).
657 */
658 break;
659
660 if ((ifID->ifThisCableStart <= dst_net) &&
661 (ifID->ifThisCableEnd >= dst_net)
662 )
663 /* We're on EtherTalk and the message is going out to
664 * some other network on the same cable.
665 */
666 break;
667
668 if (ARouterIf == NULL && ATALK_VALUE(ifID->ifARouter))
669 ARouterIf = ifID;
670 }
671 dPrintf(D_M_DDP_LOW, D_L_USR1,
672 ("ddp_output: after search ifid:0x%x %s ifID_home:0x%x\n",
673 (u_int)ifID, ifID ? ifID->ifName : "",
674 (u_int)ifID_home));
675
676 if (ifID) {
677 /* located the interface where the packet should
678 * go.... the "first-hop" destination address
679 * must be the same as real destination address.
680 */
681 addr_type = DIRECT_ADDR;
682 } else {
683 /* no, the destination network number does
684 * not match known network numbers. If we have
685 * heard from this network recently, BRT table
686 * may have address of a router we could use!
687 */
688 if (!MULTIPORT_MODE) {
689 BRT_LOOK (brt, dst_net);
690 if (brt) {
691 /* Bingo... BRT has an entry for this network.
692 * Use the link address as is.
693 */
694 dPrintf(D_M_DDP, D_L_VERBOSE,
695 ("Found BRT entry to send to net 0x%x", dst_net));
696 at_ddp_stats.xmit_BRT_used++;
697 addr_type = BRT_ENTRY;
698 ifID = brt->ifID;
699 } else {
700 /* No BRT entry available for dest network... do we
701 * know of any router at all??
702 */
703 if ((ifID = ARouterIf) != NULL)
704 addr_type = BRIDGE_ADDR;
705 else {
706 dPrintf(D_M_DDP, D_L_WARNING,
707 ("Found no interface to send pkt"));
708 at_ddp_stats.xmit_bad_addr++;
709 error = ENETUNREACH;
710 gbuf_freel(*mp);
711 goto exit_ddp_output;
712 }
713 }
714 }
715 else { /* We are in multiport mode, so we can bypass all the rest
716 * and directly ask for the routing of the packet
717 */
718 at_ddp_stats.xmit_BRT_used++;
719
720 ifID = ifID_home;
721 if (!src_addr_included) {
722 ddp->src_node = ifID->ifThisNode.s_node;
723 NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
724 }
725 ddp->src_socket = src_socket;
726 routing_needed(*mp, ifID, TRUE);
727
728 goto exit_ddp_output;
729 }
730 }
731 /* by the time we land here, we know the interface on
732 * which this packet is going out.... ifID.
733 */
734 if (ifID->ifState == LAP_OFFLINE) {
735 gbuf_freel(*mp);
736 goto exit_ddp_output;
737 }
738
739 switch (addr_type) {
740 case DIRECT_ADDR :
741/*
742 at_dest.atalk_unused = 0;
743*/
744 NET_ASSIGN(at_dest.atalk_net, dst_net);
745 at_dest.atalk_node = ddp->dst_node;
746 addr_flag = AT_ADDR;
747 addr = (char *)&at_dest;
748 break;
749 case BRT_ENTRY :
750 addr_flag = ET_ADDR;
751 addr = (char *)&brt->et_addr;
752 break;
753 case BRIDGE_ADDR :
754 NET_ASSIGN(at_dest.atalk_net, ifID->ifARouter.s_net);
755 at_dest.atalk_node = ifID->ifARouter.s_node;
756 addr_flag = AT_ADDR;
757 addr = (char *)&at_dest;
758 break;
759
760 }
761 /* Irrespective of the interface on which
762 * the packet is going out, we always put the
763 * same source address on the packet (unless multihoming mode).
764 */
765 if (MULTIHOME_MODE) {
766 if (!src_addr_included) {
767 ddp->src_node = ifID->ifThisNode.s_node;
768 NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
769 }
770 }
771 else {
772 ddp->src_node = ifID_home->ifThisNode.s_node;
773 NET_ASSIGN(ddp->src_net, ifID_home->ifThisNode.s_net);
774 }
775 ddp->src_socket = src_socket;
776
777 dPrintf(D_M_DDP_LOW, D_L_OUTPUT,
778 ("ddp_output: going out to %d:%d skt%d on %s\n",
779 dst_net, ddp->dst_node, ddp->dst_socket, ifID->ifName));
780
781 fillin_pkt_chain(*mp);
782
783 { /* begin block */
784 struct etalk_addr dest_addr;
785 struct atalk_addr dest_at_addr;
786 int loop = TRUE; /* flag to aarp to loopback (default) */
787
788 m = *mp;
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 dPrintf(D_M_DDP_LOW,D_L_ERROR,
825 ("ddp_output: Unknown addr_flag = 0x%x\n", addr_flag));
826 gbuf_freel(m); /* unknown address type, chuck it */
827 goto exit_ddp_output;
828 }
829
830 m = gbuf_strip(m);
831
832 /* At this point, rptr points to ddp header for sure */
833 if (ifID->ifState == LAP_ONLINE_FOR_ZIP) {
834 /* see if this is a ZIP packet that we need
835 * to let through even though network is
836 * not yet alive!!
837 */
838 if (zip_type_packet(m) == 0) {
839 gbuf_freel(m);
840 goto exit_ddp_output;
841 }
842 }
843
844 ifID->stats.xmit_packets++;
845 ifID->stats.xmit_bytes += gbuf_msgsize(m);
846 snmpStats.dd_outLong++;
847
848 switch (addr_flag) {
849 case AT_ADDR_NO_LOOP :
850 case AT_ADDR :
851 /*
852 * we don't want elap to be looking into ddp header, so
853 * it doesn't know net#, consequently can't do
854 * AMT_LOOKUP. That task left to aarp now.
855 */
856 aarp_send_data(m,ifID,&dest_at_addr, loop);
857 break;
858 case ET_ADDR :
859 pat_output(ifID, m, &dest_addr, 0);
860 break;
861 }
862 } /* end block */
863 exit_ddp_output:
864 KERNEL_DEBUG(DBG_AT_DDP_OUTPUT | DBG_FUNC_END, 0,
865 error, 0, 0, 0);
866 return(error);
867} /* ddp_output */
868
869void ddp_input(mp, ifID)
870 register gbuf_t *mp;
871 register at_ifaddr_t *ifID;
872{
873 register at_ddp_t *ddp; /* DDP header */
874 register int msgsize;
875 register at_socket socket;
876 register int len;
877 register at_net_al dst_net;
878
879 KERNEL_DEBUG(DBG_AT_DDP_INPUT | DBG_FUNC_START, 0,
880 ifID, mp, gbuf_len(mp),0);
881
882 /* Makes sure we know the default interface before starting to
883 * accept incomming packets. If we don't we may end up with a
884 * null ifID_table[0] and have impredicable results (specially
885 * in router mode. This is a transitory state (because we can
886 * begin to receive packet while we're not completly set up yet.
887 */
888
889 if (ifID_home == (at_ifaddr_t *)NULL) {
890 dPrintf(D_M_DDP, D_L_ERROR,
891 ("dropped incoming packet ifID_home not set yet\n"));
892 gbuf_freem(mp);
893 goto out; /* return */
894 }
895
896 /*
897 * if a DDP packet has been broadcast, we're going to get a copy of
898 * it here; if it originated at user level via a write on a DDP
899 * socket; when it gets here, the first block in the chain will be
900 * empty since it only contained the lap level header which will be
901 * stripped in the lap level immediately below ddp
902 */
903
904 if ((mp = (gbuf_t *)ddp_compress_msg(mp)) == NULL) {
905 dPrintf(D_M_DDP, D_L_ERROR,
906 ("dropped short incoming ET packet (len %d)", 0));
907 snmpStats.dd_inTotal++;
908 at_ddp_stats.rcv_bad_length++;
909 goto out; /* return; */
910 }
911 msgsize = gbuf_msgsize(mp);
912
913 at_ddp_stats.rcv_bytes += msgsize;
914 at_ddp_stats.rcv_packets++;
915
916 /* if the interface pointer is 0, the packet has been
917 * looped back by 'write' half of DDP. It is of the
918 * form {extended ddp,...}. The packet is meant to go
919 * up to some socket on the same node.
920 */
921 if (!ifID) /* if loop back is specified */
922 ifID = ifID_home; /* that means the home port */
923
924 /* the incoming datagram has extended DDP header and is of
925 * the form {ddp,...}.
926 */
927 if (msgsize < DDP_X_HDR_SIZE) {
928 dPrintf(D_M_DDP, D_L_ERROR,
929 ("dropped short incoming ET packet (len %d)", msgsize));
930 at_ddp_stats.rcv_bad_length++;
931 gbuf_freem(mp);
932 goto out; /* return; */
933 }
934 /*
935 * At this point, the message is always of the form
936 * {extended ddp, ... }.
937 */
938 ddp = (at_ddp_t *)gbuf_rptr(mp);
939 len = ddp->length;
940
941 if (msgsize != len) {
942 if ((unsigned) msgsize > len) {
943 if (len < DDP_X_HDR_SIZE) {
944 dPrintf(D_M_DDP, D_L_ERROR,
945 ("Length problems, ddp length %d, buffer length %d",
946 len, msgsize));
947 snmpStats.dd_tooLong++;
948 at_ddp_stats.rcv_bad_length++;
949 gbuf_freem(mp);
950 goto out; /* return; */
951 }
952 /*
953 * shave off the extra bytes from the end of message
954 */
955 mp = ddp_adjmsg(mp, -(msgsize - len)) ? mp : 0;
956 if (mp == 0)
957 goto out; /* return; */
958 } else {
959 dPrintf(D_M_DDP, D_L_ERROR,
960 ("Length problems, ddp length %d, buffer length %d",
961 len, msgsize));
962 snmpStats.dd_tooShort++;
963 at_ddp_stats.rcv_bad_length++;
964 gbuf_freem(mp);
965 goto out; /* return; */
966 }
967 }
968 socket = ddp->dst_socket;
969
970 /*
971 * We want everything in router mode, specially socket 254 for nbp so we need
972 * to bypass this test when we are a router.
973 */
974
975 if (!MULTIPORT_MODE && (socket > DDP_SOCKET_LAST ||
976 socket < DDP_SOCKET_1st_RESERVED)) {
977 dPrintf(D_M_DDP, D_L_WARNING,
978 ("Bad dst socket on incoming packet (0x%x)",
979 ddp->dst_socket));
980 at_ddp_stats.rcv_bad_socket++;
981 gbuf_freem(mp);
982 goto out; /* return; */
983 }
984 /*
985 * if the checksum is true, then upstream wants us to calc
986 */
987 if (UAS_VALUE(ddp->checksum) &&
988 (UAS_VALUE(ddp->checksum) != ddp_checksum(mp, 4))) {
989 dPrintf(D_M_DDP, D_L_WARNING,
990 ("Checksum error on incoming pkt, calc 0x%x, exp 0x%x",
991 ddp_checksum(mp, 4), UAS_VALUE(ddp->checksum)));
992 snmpStats.dd_checkSum++;
993 at_ddp_stats.rcv_bad_checksum++;
994 gbuf_freem(mp);
995 goto out; /* return; */
996 }
997
998/*############### routing input checking */
999
1000/* Router mode special: we send "up-stack" packets for this node or coming from any
1001 * other ports, but for the reserved atalk sockets (RTMP, ZIP, NBP [and EP])
1002 * BTW, the way we know it's for the router and not the home port is that the
1003 * MAC (ethernet) address is always the one of the interface we're on, but
1004 * the AppleTalk address must be the one of the home port. If it's a multicast
1005 * or another AppleTalk address, this is the router job's to figure out where it's
1006 * going to go.
1007 */
1008 /* *** a duplicate should be sent to any other client that is listening
1009 for packets of this type on a raw DDP socket *** */
1010 if (ddp_handler[socket].func) {
1011 dPrintf(D_M_DDP,D_L_INPUT,
1012 ("ddp_input: skt %d hdnlr:0x%x\n",
1013 (u_int) socket, ddp_handler[socket].func));
1014 pktsHome++;
1015 snmpStats.dd_inLocal++;
1016
1017 (*ddp_handler[socket].func)(mp, ifID);
1018 goto out; /* return; */
1019 }
1020 dst_net = NET_VALUE(ddp->dst_net);
1021 if (
1022 /* exact match */
1023 forUs(ddp) ||
1024 /* any node, wildcard or matching net */
1025 ((ddp->dst_node == 255) &&
1026 (((dst_net >= ifID_home->ifThisCableStart) &&
1027 (dst_net <= ifID_home->ifThisCableEnd)) ||
1028 dst_net == 0)) ||
1029 /* this node is not online yet(?) */
1030 (ifID->ifRoutingState < PORT_ONLINE)
1031 ) {
1032 gref_t *gref;
1033 pktsHome++;
1034 snmpStats.dd_inLocal++;
1035
1036 if (ddp->type == DDP_ATP) {
1037 if (atp_inputQ[socket] && (atp_inputQ[socket] != (gref_t *)1)) {
1038 /* if there's an ATP pcb */
1039 atp_input(mp);
1040 goto out; /* return; */
1041 }
1042 } else if (ddp->type == DDP_ADSP) {
1043 if (adsp_inputQ[socket]) {
1044 /* if there's an ADSP pcb */
1045 adsp_input(mp);
1046 goto out; /* return; */
1047 }
1048 }
1049
1050 /* otherwise look for a DDP pcb;
1051 ATP / raw-DDP and ADSP / raw-DDP are possible */
1052 for (gref = ddp_head.atpcb_next; gref != &ddp_head;
1053 gref = gref->atpcb_next)
0b4e3aa0
A
1054 if (gref->lport == socket &&
1055 (gref->ddptype == 0 || gref->ddptype == ddp->type)) {
1056 dPrintf(D_M_DDP, D_L_INPUT,
1057 ("ddp_input: streamq, skt %d\n", socket));
1c79356b
A
1058 if (gref->atpcb_socket) {
1059 struct sockaddr_at ddp_in;
1060 ddp_in.sat_len = sizeof(ddp_in);
1061 ddp_in.sat_family = AF_APPLETALK;
1062 ddp_in.sat_addr.s_net = NET_VALUE(ddp->src_net);
1063 ddp_in.sat_addr.s_node = ddp->src_node;
1064 ddp_in.sat_port = ddp->src_socket;
1065
1066 /* strip off DDP header if so indicated by
1067 sockopt */
1068 if (gref->ddp_flags & DDPFLG_STRIPHDR) {
1069 mp = m_pullup((struct mbuf *)mp,
1070 DDP_X_HDR_SIZE);
1071 if (mp) {
1072 gbuf_rinc(mp, DDP_X_HDR_SIZE);
1073 } else {
1074 /* this should never happen because
1075 msgsize was checked earlier */
1076 at_ddp_stats.rcv_bad_length++;
1077 goto out; /* return */
1078 }
1079 }
1080
1081 if (sbappendaddr(&((gref->atpcb_socket)->so_rcv),
1082 (struct sockaddr *)&ddp_in,
1083 mp, 0) == 0)
1084 gbuf_freem(mp);
1085 else
1086 sorwakeup(gref->atpcb_socket);
1087 } else {
1088 atalk_putnext(gref, mp);
1089 }
1090 goto out; /* return */
1091 }
1092
1093 at_ddp_stats.rcv_bad_socket++;
1094 gbuf_freem(mp);
1095 snmpStats.dd_noHandler++;
1096 dPrintf(D_M_DDP, D_L_WARNING,
1097 ("ddp_input: dropped pkt for socket %d\n", socket));
1098 } else {
1099 dPrintf(D_M_DDP, D_L_ROUTING,
1100 ("ddp_input: routing_needed from port=%d sock=%d\n",
1101 ifID->ifPort, ddp->dst_socket));
1102
1103 snmpStats.dd_fwdReq++;
1104 if (((pktsIn-pktsHome+200) >= RouterMix) && ((++pktsDropped % 5) == 0)) {
1105 at_ddp_stats.rcv_dropped_nobuf++;
1106 gbuf_freem(mp);
1107 }
1108 else {
1109 routing_needed(mp, ifID, FALSE);
1110 }
1111 }
1112out:
1113 KERNEL_DEBUG(DBG_AT_DDP_INPUT | DBG_FUNC_END, 0,0,0,0,0);
1114} /* ddp_input */
1115
1116
1117/*
1118 * ddp_router_output()
1119 *
1120 * Remarks :
1121 * This is a modified version of ddp_output for router use.
1122 * The main difference is that the interface on which the packet needs
1123 * to be sent is specified and a *destination* AppleTalk address is passed
1124 * as an argument, this address may or may not be the same as the destination
1125 * address found in the ddp packet... This is the trick about routing, the
1126 * AppleTalk destination of the packet may not be the same as the Enet address
1127 * we send the packet too (ie, we may pass the baby to another router).
1128 *
1129 */
1130int ddp_router_output(mp, ifID, addr_type, router_net, router_node, enet_addr)
1131 gbuf_t *mp;
1132 at_ifaddr_t *ifID;
1133 int addr_type;
1134 at_net_al router_net;
1135 at_node router_node;
1136 etalk_addr_t *enet_addr;
1137{
1138 register at_ddp_t *ddp;
1139 struct atalk_addr at_dest;
1140 int addr_flag;
1141 char *addr = NULL;
1142 register gbuf_t *m;
1143
1144 if (!ifID) {
1145 dPrintf(D_M_DDP, D_L_WARNING, ("BAD BAD ifID\n"));
1146 gbuf_freel(mp);
1147 return(EPROTOTYPE);
1148 }
1149 ddp = (at_ddp_t *)gbuf_rptr(mp);
1150
1151 if (ifID->ifFlags & AT_IFF_AURP) { /* AURP link? */
1152 if (ddp_AURPsendx) {
1153 fillin_pkt_chain(mp);
1154 if (router_node == 255)
1155 router_node = 0;
1156 ddp_AURPsendx(AURPCODE_DATAPKT, mp, router_node);
1157 return 0;
1158 } else {
1159 gbuf_freel(mp);
1160 return EPROTOTYPE;
1161 }
1162 }
1163
1164 /* keep some of the tests for now ####### */
1165
1166 if (gbuf_msgsize(mp) > DDP_DATAGRAM_SIZE) {
1167 /* the packet is too large */
1168 dPrintf(D_M_DDP, D_L_WARNING,
1169 ("ddp_router_output: Packet too large size=%d\n",
1170 gbuf_msgsize(mp)));
1171 gbuf_freel(mp);
1172 return (EMSGSIZE);
1173 }
1174
1175 switch (addr_type) {
1176
1177 case AT_ADDR :
1178
1179 /*
1180 * Check for packet destined to the home stack
1181 */
1182
1183 if ((ddp->dst_node == ifID->ifThisNode.s_node) &&
1184 (NET_VALUE(ddp->dst_net) == ifID->ifThisNode.s_net)) {
1185 dPrintf(D_M_DDP_LOW, D_L_ROUTING,
1186 ("ddp_r_output: sending back home from port=%d socket=%d\n",
1187 ifID->ifPort, ddp->dst_socket));
1188
1189 UAS_ASSIGN(ddp->checksum, 0);
1190 ddp_input(mp, ifID);
1191 return(0);
1192 }
1193
1194 NET_ASSIGN(at_dest.atalk_net, router_net);
1195 at_dest.atalk_node = router_node;
1196
1197 addr_flag = AT_ADDR_NO_LOOP;
1198 addr = (char *)&at_dest;
1199 dPrintf(D_M_DDP_LOW, D_L_ROUTING_AT,
1200 ("ddp_r_output: AT_ADDR out port=%d net %d:%d via rte %d:%d",
1201 ifID->ifPort, NET_VALUE(ddp->dst_net), ddp->dst_node, router_net,
1202 router_node));
1203 break;
1204
1205 case ET_ADDR :
1206 addr_flag = ET_ADDR;
1207 addr = (char *)enet_addr;
1208 dPrintf(D_M_DDP_LOW, D_L_ROUTING,
1209 ("ddp_r_output: ET_ADDR out port=%d net %d:%d\n",
1210 ifID->ifPort, NET_VALUE(ddp->dst_net), ddp->dst_node));
1211 break;
1212 }
1213
1214 if (ifID->ifState == LAP_OFFLINE) {
1215 gbuf_freel(mp);
1216 return 0;
1217 }
1218
1219 fillin_pkt_chain(mp);
1220
1221 { /* begin block */
1222 struct etalk_addr dest_addr;
1223 struct atalk_addr dest_at_addr;
1224 int loop = TRUE; /* flag to aarp to loopback (default) */
1225
1226 m = mp;
1227
1228 /* the incoming frame is of the form {flag, address, ddp...}
1229 * where "flag" indicates whether the address is an 802.3
1230 * (link) address, or an appletalk address. If it's an
1231 * 802.3 address, the packet can just go out to the network
1232 * through PAT, if it's an appletalk address, AT->802.3 address
1233 * resolution needs to be done.
1234 * If 802.3 address is known, strip off the flag and 802.3
1235 * address, and prepend 802.2 and 802.3 headers.
1236 */
1237
1238 if (addr == NULL) {
1239 addr_flag = *(u_char *)gbuf_rptr(m);
1240 gbuf_rinc(m,1);
1241 }
1242
1243 switch (addr_flag) {
1244 case AT_ADDR_NO_LOOP :
1245 loop = FALSE;
1246 /* pass thru */
1247 case AT_ADDR :
1248 if (addr == NULL) {
1249 dest_at_addr = *(struct atalk_addr *)gbuf_rptr(m);
1250 gbuf_rinc(m,sizeof(struct atalk_addr));
1251 } else
1252 dest_at_addr = *(struct atalk_addr *)addr;
1253 break;
1254 case ET_ADDR :
1255 if (addr == NULL) {
1256 dest_addr = *(struct etalk_addr *)gbuf_rptr(m);
1257 gbuf_rinc(m,sizeof(struct etalk_addr));
1258 } else
1259 dest_addr = *(struct etalk_addr *)addr;
1260 break;
1261 default :
1262 dPrintf(D_M_DDP_LOW,D_L_ERROR,
1263 ("ddp_router_output: Unknown addr_flag = 0x%x\n", addr_flag));
1264
1265 gbuf_freel(m); /* unknown address type, chuck it */
1266 return 0;
1267 }
1268
1269 m = gbuf_strip(m);
1270
1271 /* At this point, rptr points to ddp header for sure */
1272 if (ifID->ifState == LAP_ONLINE_FOR_ZIP) {
1273 /* see if this is a ZIP packet that we need
1274 * to let through even though network is
1275 * not yet alive!!
1276 */
1277 if (zip_type_packet(m) == 0) {
1278 gbuf_freel(m);
1279 return 0;
1280 }
1281 }
1282
1283 ifID->stats.xmit_packets++;
1284 ifID->stats.xmit_bytes += gbuf_msgsize(m);
1285 snmpStats.dd_outLong++;
1286
1287 switch (addr_flag) {
1288 case AT_ADDR_NO_LOOP :
1289 case AT_ADDR :
1290 /*
1291 * we don't want elap to be looking into ddp header, so
1292 * it doesn't know net#, consequently can't do
1293 * AMT_LOOKUP. That task left to aarp now.
1294 */
1295 aarp_send_data(m,ifID,&dest_at_addr, loop);
1296 break;
1297 case ET_ADDR :
1298 pat_output(ifID, m, &dest_addr, 0);
1299 break;
1300 }
1301 } /* end block */
1302
1303 return(0);
1304} /* ddp_router_output */
1305
1306/*****************************************/
1307
1308void rt_delete(NetStop, NetStart)
1309 unsigned short NetStop;
1310 unsigned short NetStart;
1311{
1312 RT_entry *found;
1313 int s;
1314
1315 ATDISABLE(s, ddpinp_lock);
1316 if ((found = rt_bdelete(NetStop, NetStart)) != 0) {
1317 bzero(found, sizeof(RT_entry));
1318 found->right = RT_table_freelist;
1319 RT_table_freelist = found;
1320 }
1321 ATENABLE(s, ddpinp_lock);
1322}
1323
1324int ddp_AURPfuncx(code, param, node)
1325 int code;
1326 void *param;
1327 unsigned char node;
1328{
1329 extern void rtmp_timeout();
1330 extern void rtmp_send_port();
1331 at_ifaddr_t *ifID;
1332 int k;
1333
1334 switch (code) {
1335 case AURPCODE_DATAPKT: /* data packet */
1336 if (aurp_ifID) {
1337 dPrintf(D_M_DDP, D_L_TRACE, ("ddp_AURPfuncx: data, 0x%x, %d\n",
1338 (u_int) aurp_ifID, node));
1339
1340 ddp_input((gbuf_t *)param, aurp_ifID);
1341 } else
1342 gbuf_freem((gbuf_t *)param);
1343 break;
1344
1345 case AURPCODE_REG: /* register/deregister */
1346 if (!ROUTING_MODE)
1347 return -1;
1348 ddp_AURPsendx = (void(*)())param;
1349
1350 if (param) {
1351 /* register AURP callback function */
1352 if (aurp_ifID)
1353 return 0;
1354 for (k=(IFID_HOME+1); k < IF_TOTAL_MAX; k++) {
1355 if (ifID_table[k] == 0) {
1356 aurp_ifID = &at_interfaces[k];
1357 aurp_ifID->ifFlags = RTR_XNET_PORT;
1358 ddp_add_if(aurp_ifID);
1359 aurp_ifID->ifState = LAP_ONLINE;
1360 aurp_ifID->ifRoutingState = PORT_ONLINE;
1361 dPrintf(D_M_DDP, D_L_TRACE,
1362 ("ddp_AURPfuncx: on, 0x%x\n",
1363 (u_int) aurp_ifID));
1364
1365 ddp_AURPsendx(AURPCODE_DEBUGINFO,
1366 &dbgBits, aurp_ifID->ifPort);
1367 return 0;
1368 }
1369 }
1370 return -1;
1371
1372 } else {
1373 /* deregister AURP callback function */
1374 if (aurp_ifID) {
1375 rtmp_purge(aurp_ifID);
1376 ddp_rem_if(aurp_ifID);
1377 aurp_ifID->ifState = LAP_OFFLINE;
1378 aurp_ifID->ifRoutingState = PORT_OFFLINE;
1379 dPrintf(D_M_DDP, D_L_TRACE,
1380 ("ddp_AURPfuncx: off, 0x%x\n", (u_int) aurp_ifID));
1381 aurp_ifID = 0;
1382 }
1383 }
1384 break;
1385
1386 case AURPCODE_AURPPROTO: /* proto type - AURP */
1387 if (aurp_ifID) {
1388 aurp_ifID->ifFlags |= AT_IFF_AURP;
1389 }
1390 break;
1391 }
1392
1393 return 0;
1394}
1395
1396
1397/* checks to see if address of packet is for one of our interfaces
1398 returns *ifID if it's for us, NULL if not
1399*/
1400at_ifaddr_t *forUs(ddp)
1401 register at_ddp_t *ddp;
1402{
1403 at_ifaddr_t *ifID;
1404
1405 TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
1406 if ((ddp->dst_node == ifID->ifThisNode.s_node) &&
1407 (NET_VALUE(ddp->dst_net) == ifID->ifThisNode.s_net)
1408 ) {
1409 dPrintf(D_M_DDP_LOW, D_L_ROUTING,
1410 ("pkt was for port %d\n", ifID->ifPort));
1411
1412 return(ifID);
1413 }
1414 }
1415
1416 return((at_ifaddr_t *)NULL);
1417} /* forUs */