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