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