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