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