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