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