1/* 2 * Copyright (c) 1988-2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * 0.01 05/12/94 Laurent Dumont Creation 30 * 31 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX. 32 */ 33/* 34 * 35 * Router ZIP protocol functions: 36 * 37 * This file contains Routing specifics to handle ZIP requests and responses 38 * sent and received by a router node. 39 * 40 * The entry point for the zip input in ddp is valid only when we're 41 * running in router mode. 42 * 43 */ 44 45#include <sys/errno.h> 46#include <sys/types.h> 47#include <sys/param.h> 48#include <machine/spl.h> 49#include <sys/systm.h> 50#include <sys/kernel.h> 51#include <sys/proc.h> 52#include <sys/filedesc.h> 53#include <sys/fcntl.h> 54#include <sys/mbuf.h> 55#include <sys/ioctl.h> 56#include <sys/malloc.h> 57#include <sys/socket.h> 58#include <sys/socketvar.h> 59 60#include <net/if.h> 61#include <net/if_types.h> 62 63#include <netat/sysglue.h> 64#include <netat/appletalk.h> 65#include <netat/at_pcb.h> 66#include <netat/at_var.h> 67#include <netat/ddp.h> 68#include <netat/nbp.h> 69#include <netat/zip.h> 70#include <netat/atp.h> 71#include <netat/routing_tables.h> 72#include <netat/rtmp.h> 73#include <netat/debug.h> 74 75#include <sys/kern_event.h> 76 77/* globals */ 78extern at_ifaddr_t *ifID_table[], *ifID_home; 79extern short ErrorZIPoverflow; 80 81/********************************************************************** 82 * Remarks : 83 * ZIP is implemented as a "peer" of DDP, so the packets coming in 84 * to ZIP have the same headers as those coming in to DDP {ddp...}. 85 * Same applies to outgoing packets. Also, unlike DDP, ZIP assumes 86 * that an incoming packet is in a contiguous gbuf_t. 87 * 88 **********************************************************************/ 89 90static int netinfo_reply_pending; 91static void zip_netinfo_reply(at_x_zip_t *, at_ifaddr_t *); 92static void zip_getnetinfo(at_ifaddr_t *); 93static void zip_getnetinfo_locked(void *); 94static void send_phony_reply(void *); 95 96int zip_reply_received(gbuf_t *, at_ifaddr_t *, int); 97int zip_reply_to_getlocalzones(at_ifaddr_t *, gbuf_t *); 98int zip_reply_to_getzonelist(at_ifaddr_t *, gbuf_t *); 99static void zip_reply_to_getmyzone(at_ifaddr_t *, gbuf_t *); 100gbuf_t *zip_prep_query_packet(at_ifaddr_t *, at_net_al, at_node); 101 102static void zip_send_reply_to_query(gbuf_t *, at_ifaddr_t *); 103static void zip_send_ext_reply_to_query(gbuf_t *, at_ifaddr_t *, RT_entry *, u_short); 104static gbuf_t *prep_ZIP_reply_packet(gbuf_t *, at_ifaddr_t *); 105static void zip_send_getnetinfo_reply(gbuf_t *, at_ifaddr_t *); 106 107/* 108 * zip_send_getnetinfo_reply: we received a GetNetInfo packet, we need to reply 109 * with the right information for the port. 110 */ 111static void zip_send_getnetinfo_reply(m, ifID) 112 register gbuf_t *m; 113 register at_ifaddr_t *ifID; 114{ 115 at_nvestr_t *zname; 116 gbuf_t *m_sent; 117 at_ddp_t *ddp, *ddp_sent; 118 short ZoneNameProvided = FALSE; 119 short RequestIsBroadcasted = FALSE; 120 u_short znumber, len, packet_length = 0, size, status; 121 RT_entry *Entry; 122 char GNIReply[128]; 123 124 ddp = (at_ddp_t *)gbuf_rptr(m); 125 126 /* access the Zone Name info part of the GetNetInfo Request */ 127 128 zname = (at_nvestr_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE + 6); 129 130 if (zname->len > ZIP_MAX_ZONE_LENGTH) { 131 dPrintf(D_M_ZIP, D_L_WARNING, 132 ("zip_s_gni_r: zone len too long l=%d ddplen=%d\n", 133 zname->len, DDPLEN_VALUE(ddp))); 134 return; 135 } 136 137 138 if (zname->len) 139 ZoneNameProvided = TRUE; 140 141 GNIReply[0] = ZIP_NETINFO_REPLY; 142 GNIReply[1] = ZIP_ZONENAME_INVALID; 143 144 /* check if we are the originator is in the cable range for this interface */ 145 146 if ((NET_VALUE(ddp->src_net) < CableStart || NET_VALUE(ddp->src_net) > CableStop) && 147 (NET_VALUE(ddp->dst_net) == 0 && ddp->dst_node == 0xff)) { 148 RequestIsBroadcasted = TRUE; 149 } 150 Entry = rt_blookup(CableStop); 151 152 if (Entry != NULL && RT_ALL_ZONES_KNOWN(Entry)) { /* this net is well known... */ 153 154 GNIReply[2] = (Entry->NetStart & 0xFF00) >> 8; 155 GNIReply[3] = (Entry->NetStart & 0x00FF); 156 GNIReply[4] = (Entry->NetStop & 0xFF00) >> 8; 157 GNIReply[5] = (Entry->NetStop & 0x00FF); 158 159 /* copy the zone name found in the request */ 160 161 GNIReply[6] = zname->len; 162 bcopy(&zname->str, &GNIReply[7], zname->len); 163 164 165 if ((znumber = zt_find_zname(zname))) { 166 167 if (ZT_ISIN_ZMAP((znumber), Entry->ZoneBitMap)) { 168 169 GNIReply[1] = 0; /* Zone Valid */ 170 171 if ((len = zt_get_zmcast(ifID, zname, &GNIReply[8+zname->len]))) 172 GNIReply[7+zname->len] = len; 173 else { 174 GNIReply[1] |= ZIP_USE_BROADCAST; 175 GNIReply[7+zname->len] = 0; /* multicast address length */ 176 } 177 packet_length = 8 + zname->len + len; 178 } 179 } 180 181 } 182 183 else { /* should not happen, we are supposed to know our net */ 184 dPrintf(D_M_ZIP, D_L_WARNING, ("zip_s_gni_r: Don't know about our zone infos!!!\n")); 185 return; 186 } 187 188 if (zt_ent_zcount(Entry) == 1) 189 GNIReply[1] |= ZIP_ONE_ZONE; 190 191 if (GNIReply[1] & ZIP_ZONENAME_INVALID) { 192 193 short Index = ifID->ifDefZone; 194 195 if (Index <= 0 || Index >= ZT_MAXEDOUT) { 196 dPrintf(D_M_ZIP, D_L_WARNING, 197 ("zip_s_gni_r: Invalid starting index =%d port%d\n", 198 Index, ifID->ifPort)); 199 return; 200 } 201 202 203 Index--; 204 205 if ((len = zt_get_zmcast(ifID, &ZT_table[Index].Zone, &GNIReply[8+zname->len]))) 206 GNIReply[7+zname->len] = len; 207 else { 208 GNIReply[1] |= ZIP_USE_BROADCAST; 209 GNIReply[7+zname->len] = 0; /* multicast address length */ 210 } 211 212 packet_length = 7 + zname->len + len; 213 214 /* in the case the zone name asked for in the request was invalid, we need 215 * to copy the good default zone for this net 216 */ 217 218 GNIReply[packet_length + 1] = ZT_table[Index].Zone.len; 219 bcopy(&ZT_table[Index].Zone.str, &GNIReply[packet_length + 2], 220 ZT_table[Index].Zone.len); 221 packet_length = packet_length +2 + ZT_table[Index].Zone.len; 222 } 223 224 225 /* 226 * we're finally ready to send out the GetNetInfo Reply 227 * 228 */ 229 230 231 size = DDP_X_HDR_SIZE + packet_length; 232 if ((m_sent = gbuf_alloc(AT_WR_OFFSET+size, PRI_HI)) == NULL) { 233 return; /* was return(ENOBUFS); */ 234 } 235 236 gbuf_rinc(m_sent,AT_WR_OFFSET); 237 gbuf_wset(m_sent,size); 238 ddp_sent = (at_ddp_t *)(gbuf_rptr(m_sent)); 239 240 /* Prepare the DDP header */ 241 242 ddp_sent->unused = ddp_sent->hopcount = 0; 243 UAS_ASSIGN(ddp->checksum, 0); 244 DDPLEN_ASSIGN(ddp_sent, size); 245 NET_ASSIGN(ddp_sent->src_net, ifID->ifThisNode.s_net); 246 ddp_sent->src_node = ifID->ifThisNode.s_node; 247 ddp_sent->src_socket = ZIP_SOCKET; 248 ddp_sent->dst_socket = ddp->src_socket; 249 250 if (RequestIsBroadcasted) { /* if this was a broadcast, must respond from that */ 251 252 NET_ASSIGN(ddp_sent->dst_net, 0); 253 ddp_sent->dst_node = 0xFF; 254 } 255 else { 256 257 NET_NET(ddp_sent->dst_net, ddp->src_net); 258 ddp_sent->dst_node = ddp->src_node; 259 } 260 ddp_sent->type = DDP_ZIP; 261 262 bcopy(&GNIReply, &ddp_sent->data, packet_length); 263 264 dPrintf(D_M_ZIP_LOW, D_L_ROUTING, 265 ("zip_s_gni_r: send to %d:%d port#%d pack_len=%d\n", 266 NET_VALUE(ddp_sent->dst_net), ddp_sent->dst_node, 267 ifID->ifPort, packet_length)); 268 if ((status = 269 ddp_router_output(m_sent, ifID, AT_ADDR, 270 NET_VALUE(ddp_sent->dst_net), ddp_sent->dst_node, 0))) { 271 dPrintf(D_M_ZIP, D_L_ERROR, 272 ("zip_s_gni_r: ddp_router_output returns =%d\n", status)); 273 return; /* was return(status); */ 274 } 275} /* zip_send_getnetinfo_reply */ 276 277 278/* 279 * build_ZIP_reply_packet: is used to create and send a DDP packet and use the 280 * provided buffer as a ZIP reply. This is used by zip_send_ext_reply_to_query 281 * and zip_send_reply_to_query for sending their replies to ZIP queries. 282 */ 283gbuf_t *prep_ZIP_reply_packet(m, ifID) 284 register gbuf_t *m; /* this is the original zip query */ 285 register at_ifaddr_t *ifID; 286{ 287 register gbuf_t *m_sent; 288 register at_ddp_t *ddp, *src_ddp; 289 290 /* access the source Net and Node informations */ 291 292 src_ddp = (at_ddp_t *)gbuf_rptr(m); 293 294 if ((m_sent = gbuf_alloc (AT_WR_OFFSET+1024, PRI_HI)) == NULL) { 295 return((gbuf_t *)NULL); 296 } 297 gbuf_rinc(m_sent,AT_WR_OFFSET); 298 gbuf_wset(m_sent,DDP_X_HDR_SIZE); 299 ddp = (at_ddp_t *)(gbuf_rptr(m_sent)); 300 301 /* Prepare the DDP header */ 302 303 ddp->unused = ddp->hopcount = 0; 304 UAS_ASSIGN(ddp->checksum, 0); 305 306 NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net); 307 ddp->src_node = ifID->ifThisNode.s_node; 308 ddp->src_socket = ZIP_SOCKET; 309 310 ddp->dst_socket = src_ddp->src_socket; 311 NET_NET(ddp->dst_net, src_ddp->src_net); 312 ddp->dst_node = src_ddp->src_node; 313 314 ddp->type = DDP_ZIP; 315 316 return(m_sent); 317} 318/* 319 * zip_send_ext_reply_to_query: this function deals with ZIP Queries for extended nets. 320 * When we recognize an extended net (that might have several zone name associated with 321 * it), we send A SEPARATE ZIP reply for that network. This is called from the 322 * regular zip_send_reply_to_query, that just deals with non-ext nets. 323 */ 324 325static void zip_send_ext_reply_to_query(mreceived, ifID, Entry, NetAsked) 326 register gbuf_t *mreceived; 327 register at_ifaddr_t *ifID; 328 RT_entry *Entry; /* info about the network we're looking for */ 329 u_short NetAsked; 330{ 331 register gbuf_t *m; 332 register at_ddp_t *ddp; 333 short i, j, reply_length, Index, zone_count, status; 334 u_char *zmap; 335 char *ReplyBuff, *ZonesInPacket; 336 337 zone_count = zt_ent_zcount(Entry); 338 zmap = Entry->ZoneBitMap; 339 i = ZT_BYTES -1; 340 341 342newPacket: 343 344 if (!(m = prep_ZIP_reply_packet (mreceived, ifID))) { 345 return; /* was return(ENOBUFS); */ 346 } 347 348 ddp = (at_ddp_t *)(gbuf_rptr(m)); 349 ReplyBuff = (char *)(ddp->data); 350 351 352 *ReplyBuff++ = 8; /* ZIP function = 8 [extended reply] */ 353 354 ZonesInPacket= ReplyBuff; 355 *ZonesInPacket= 0; 356 ReplyBuff ++; 357 reply_length = 2; /* 1st byte is ZIP reply code, 2nd is network count */ 358 j= 0; 359 360 /* For all zones, we check if they belong to the map for that Network */ 361 362 for (; i >= 0; i--) { 363 364 /* find the zones defined in this entry bitmap */ 365 366 if (zmap[i]) { 367 for (; j < 8 ; j++) 368 if (zmap[i] << j & 0x80) { /* bingo */ 369 370 Index = i*8 + j; /* zone index in zone table */ 371 372 if (reply_length + 3 + ZT_table[Index].Zone.len > DDP_DATA_SIZE) { 373 374 /* we need to send the packet before, this won't fit... */ 375 376 zone_count -= *ZonesInPacket; 377 378 DDPLEN_ASSIGN(ddp, (reply_length + DDP_X_HDR_SIZE)); 379 gbuf_winc(m,reply_length); 380 if ((status = 381 ddp_router_output(m, ifID, AT_ADDR, 382 NET_VALUE(ddp->dst_net), ddp->dst_node, 0))) { 383 dPrintf(D_M_ZIP, D_L_ERROR, 384 ("zip_s_ext_repl: ddp_router_output returns =%d\n", 385 status)); 386 return; /* was return (status); */ 387 } 388 389 goto newPacket; 390 391 } 392 /* this should fit in this packet, build the NetNumber, ZoneLen, 393 * ZoneName triple 394 */ 395 396 if (ZT_table[Index].Zone.len) { 397 *ZonesInPacket += 1; /* bump NetCount field */ 398 *ReplyBuff++ = (NetAsked & 0xFF00) >> 8; 399 *ReplyBuff++ = (NetAsked & 0x00FF) ; 400 *ReplyBuff++ = ZT_table[Index].Zone.len; 401 402 bcopy(&ZT_table[Index].Zone.str, ReplyBuff, 403 ZT_table[Index].Zone.len); 404 405 ReplyBuff += ZT_table[Index].Zone.len; 406 reply_length += ZT_table[Index].Zone.len +3; 407 } 408 409 } 410 } 411 j= 0; /* reset the bit count */ 412 } 413 414 /* if we have some zone info in a half-empty packet, send it now. 415 * Remember, for extended nets we send *at least* one Reply 416 */ 417 418 if (zone_count) { 419 DDPLEN_ASSIGN(ddp, (reply_length + DDP_X_HDR_SIZE)); 420 gbuf_winc(m,reply_length); 421 if ((status = 422 ddp_router_output(m, ifID, AT_ADDR, 423 NET_VALUE(ddp->dst_net), ddp->dst_node, 0))) { 424 dPrintf(D_M_ZIP, D_L_ERROR, 425 ("zip_s_ext_reply: ddp_router_output returns =%d\n", status)); 426 return; /* was return (status); */ 427 } 428 } 429 else /* free the buffer not used */ 430 431 gbuf_freem(m); 432} /* zip_send_ext_reply_to_query */ 433 434/* 435 * zip_send_reply_to_query: we received a ZIPQuery packet, we need to reply 436 * with the right information for the nets requested (if we have 437 * the right information. 438 */ 439static void zip_send_reply_to_query(mreceived, ifID) 440 register gbuf_t *mreceived; 441 register at_ifaddr_t *ifID; 442{ 443 register gbuf_t *m; 444 register at_ddp_t *ddp = NULL, *ddp_received; 445 RT_entry *Entry; 446 short i, reply_length, Index, status; 447 u_char network_count; 448 u_short *NetAsked; 449 char *ReplyBuff, *ZonesInPacket; 450 451 ddp_received = (at_ddp_t *)gbuf_rptr(mreceived); 452 453 /* access the number of nets requested in the Query */ 454 network_count = *((char *)(ddp_received->data) + 1); 455 NetAsked = (u_short *)(ddp_received->data + 2); 456 457 /* check the validity of the Query packet */ 458 459 if (DDPLEN_VALUE(ddp_received) != 460 (2 + network_count * 2 + DDP_X_HDR_SIZE)) { 461 462 dPrintf(D_M_ZIP, D_L_WARNING, 463 ("zip_s_reply_to_q: bad length netcount=%d len=%d\n", 464 network_count, DDPLEN_VALUE(ddp))); 465 return; /* was return(1); */ 466 } 467 468 /* walk the Query Network list */ 469 /* we want to build a response with the network number followed by the zone name 470 * length and the zone name. If there is more than one zone per network asked, 471 * we repeat the network number and stick the zone length and zone name. 472 * We need to be carefull with the max DDP size for data. If we see that a new 473 * NetNum, ZoneLen, ZoneName sequence won't fit, we send the previous packet and 474 * begin to build a new one. 475 */ 476 477newPacket: 478 479 if (!(m = prep_ZIP_reply_packet (mreceived, ifID))) { 480 return; /* was return(ENOBUFS); */ 481 } 482 483 ddp = (at_ddp_t *)(gbuf_rptr(m)); 484 ReplyBuff = (char *)(ddp->data); 485 486 *ReplyBuff++ = 2; /* ZIP function = 2 [Non extended reply] */ 487 ZonesInPacket = ReplyBuff; 488 *ZonesInPacket = 0; 489 ReplyBuff++; 490 reply_length = 2; /* 1st byte is ZIP reply code, 2nd is network count */ 491 492 for (i = 0 ; i < network_count ; i ++, NetAsked++) { 493 Entry = rt_blookup(ntohs(*NetAsked)); 494 495 if (Entry != NULL && ((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) && 496 RT_ALL_ZONES_KNOWN(Entry)) { /* this net is well known... */ 497 498 if (Entry->NetStart == 0) { /* asking for a NON EXTENDED network */ 499 500 if ( (Index = zt_ent_zindex(Entry->ZoneBitMap)) == 0) 501 continue; 502 503 Index--; 504 505 if (reply_length + 3 + ZT_table[Index].Zone.len > DDP_DATA_SIZE) { 506 507 /* we need to send the packet before, this won't fit... */ 508 509 DDPLEN_ASSIGN(ddp, (reply_length + DDP_X_HDR_SIZE)); 510 gbuf_winc(m,reply_length); 511 512 if ((status = 513 ddp_router_output(m, ifID, AT_ADDR, 514 NET_VALUE(ddp->dst_net), 515 ddp->dst_node, 0))) { 516 dPrintf(D_M_ZIP, D_L_ERROR, 517 ("zip_s_reply: ddp_router_output returns =%d\n", 518 status)); 519 return; /* was return (status); */ 520 } 521 522 /* this is not nice, I know, but we reenter the loop with 523 * a packet is sent with the next network field in the Query 524 */ 525 526 network_count -= i; 527 goto newPacket; 528 529 } 530 531 /* this should fit in this packet, build the NetNumber, ZoneLen, 532 * ZoneName triple 533 */ 534 535 if (ZT_table[Index].Zone.len) { 536 ZonesInPacket += 1; /* bump NetCount field */ 537 *ReplyBuff++ = (*NetAsked & 0xFF00) >> 8; 538 *ReplyBuff++ = (*NetAsked & 0x00FF) ; 539 *ReplyBuff++ = ZT_table[Index].Zone.len; 540 bcopy(&ZT_table[Index].Zone.str, ReplyBuff, 541 ZT_table[Index].Zone.len); 542 543 ReplyBuff += ZT_table[Index].Zone.len; 544 545 reply_length += ZT_table[Index].Zone.len + 3; 546 547 548 } 549 550 551 } 552 else { /* extended network, check for multiple zone name attached 553 * and build a separate packet for each extended network requested 554 */ 555 556 zip_send_ext_reply_to_query(mreceived, ifID, Entry, ntohs(*NetAsked)); 557 558 } 559 } 560 } 561 562 /* If we have a non extended packet (code 2) with some stuff in it, 563 * we need to send it now 564 */ 565 566 if ( reply_length > 2) { 567 DDPLEN_ASSIGN(ddp, (reply_length + DDP_X_HDR_SIZE)); 568 gbuf_winc(m,reply_length); 569 if ((status = 570 ddp_router_output(m, ifID, AT_ADDR, 571 NET_VALUE(ddp->dst_net), 572 ddp->dst_node, 0))) { 573 dPrintf(D_M_ZIP, D_L_ERROR, 574 ("zip_send_reply: ddp_router_output returns =%d\n", status)); 575 return; /* was return (status); */ 576 } 577 } 578 else /* free the buffer not used */ 579 gbuf_freem(m); 580} /* zip_send_reply_to_query */ 581 582/*********************************************************************** 583 * zip_router_input() 584 * 585 **********************************************************************/ 586 587void zip_router_input (m, ifID) 588 register gbuf_t *m; 589 register at_ifaddr_t *ifID; 590{ 591 register at_ddp_t *ddp; 592 register at_atp_t *atp; 593 register at_zip_t *zip; 594 u_char user_bytes[4]; 595 register u_short user_byte; 596 597 /* variables for ZipNotify processing */ 598 register char old_zone_len; 599 register char new_zone_len; 600 register char *old_zone; 601 char *new_zone; 602 603 if (gbuf_type(m) != MSG_DATA) { 604 /* If this is a M_ERROR message, DDP is shutting down, 605 * nothing to do here...If it's something else, we don't 606 * understand what it is 607 */ 608 dPrintf(D_M_ZIP, D_L_WARNING, ("zip_router_input: not an M_DATA message\n")); 609 gbuf_freem(m); 610 return; 611 } 612 613 if (!ifID) { 614 dPrintf(D_M_ZIP, D_L_WARNING, ("zip_router_input: BAD ifID\n")); 615 gbuf_freem(m); 616 return; 617 } 618 619 /* 620 * The ZIP listener receives two types of requests: 621 * 622 * ATP requests: GetZoneList, GetLocalZone, or GetMyZone 623 * ZIP requests: Netinfo, Query, Reply, takedown, bringup 624 */ 625 626 ddp = (at_ddp_t *)gbuf_rptr(m); 627 628 if (ddp->type == DDP_ZIP) { 629 zip = (at_zip_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE); 630 dPrintf(D_M_ZIP_LOW, D_L_INPUT, 631 ("zip_input: received a ZIP_DDP command=%d\n", 632 zip->command)); 633 switch (zip->command) { 634 case ZIP_QUERY : /* we received a Zip Query request */ 635 dPrintf(D_M_ZIP, D_L_INPUT, 636 ("zip_input: Received a Zip Query in from %d.%d\n", 637 NET_VALUE(ddp->src_net), ddp->src_node)); 638 639 if (!RT_LOOKUP_OKAY(ifID, ddp)) { 640 dPrintf(D_M_ZIP, D_L_INPUT, 641 ("zip_input:: refused ZIP_QUERY from %d:%d\n", 642 NET_VALUE(ddp->src_net), ddp->src_node)); 643 } 644 else 645 zip_send_reply_to_query(m, ifID); 646 gbuf_freem(m); 647 break; 648 649 case ZIP_REPLY : /* we received a Zip Query Reply packet */ 650 case ZIP_EXTENDED_REPLY: 651 if (ifID->ifRoutingState == PORT_OFFLINE) { 652 dPrintf(D_M_ZIP, D_L_INPUT, 653 ("zip_input: Received a Zip Reply in user mode\n")); 654 } 655 else 656 zip_reply_received(m, ifID, zip->command); 657 gbuf_freem(m); 658 break; 659 660 case ZIP_TAKEDOWN : 661 /* we received a Zip Takedown packet */ 662 dPrintf(D_M_ZIP, D_L_WARNING, ("zip_input: Received a Zip takedown!!!\n")); 663 gbuf_freem(m); 664 break; 665 666 case ZIP_BRINGUP : 667 /* we received a Zip BringUp packet */ 668 dPrintf(D_M_ZIP, D_L_WARNING, ("zip_input: Received a Zip BringUp!!!\n")); 669 gbuf_freem(m); 670 break; 671 672 case ZIP_GETNETINFO: /* we received a GetNetInfo request */ 673 dPrintf(D_M_ZIP, D_L_INPUT, 674 ("zip_input: Received a GetNetInfo Req in from %d.%d\n", 675 NET_VALUE(ddp->src_net), ddp->src_node)); 676 if (RT_LOOKUP_OKAY(ifID, ddp)) { 677 dPrintf(D_M_ZIP, D_L_OUTPUT, 678 ("zip_input: we, as node %d:%d send GNI reply to %d:%d\n", 679 ifID->ifThisNode.s_net, ifID->ifThisNode.s_node, 680 NET_VALUE(ddp->src_net), ddp->src_node)); 681 zip_send_getnetinfo_reply(m, ifID); 682 } 683 gbuf_freem(m); 684 break; 685 686 687 case ZIP_NETINFO_REPLY : 688 689 /* If we are not waiting for a GetNetInfo reply 690 * to arrive, this must be a broadcast 691 * message for someone else on the zone, so 692 * no need to even look at it! 693 */ 694 if (!ROUTING_MODE && 695 ((NET_VALUE(ddp->src_net) != ifID->ifThisNode.s_net) || 696 (ddp->src_node != ifID->ifThisNode.s_node)) && netinfo_reply_pending) 697 { 698 dPrintf(D_M_ZIP, D_L_INPUT, 699 ("zip_input: Received a GetNetInfo Reply from %d.%d\n", 700 NET_VALUE(ddp->src_net), ddp->src_node)); 701 trackrouter(ifID, NET_VALUE(ddp->src_net), ddp->src_node); 702 zip_netinfo_reply((at_x_zip_t *)zip, ifID); 703 } 704 705 gbuf_freem(m); 706 break; 707 708 case ZIP_NOTIFY : 709 /* processing of ZipNotify message : first, change 710 * our zone name, then if NIS is open, let NBP demon 711 process know of this change...(just forward the 712 * Notify packet 713 */ 714 /* First, check if this is really a packet for us */ 715 old_zone = &zip->data[4]; 716 if (!zonename_equal(&ifID->ifZoneName, 717 (at_nvestr_t *)old_zone)) { 718 /* the old zone name in the packet is not the 719 * same as ours, so this packet couldn't be 720 * for us. 721 */ 722 gbuf_freem(m); 723 break; 724 725 } 726 old_zone_len = *old_zone; 727 new_zone_len = zip->data[4 + old_zone_len + 1]; 728 new_zone = old_zone + old_zone_len; 729 730 /* Reset the zone multicast address */ 731 (void)at_unreg_mcast(ifID, (caddr_t)&ifID->ZoneMcastAddr); 732 bzero((caddr_t)&ifID->ZoneMcastAddr, ETHERNET_ADDR_LEN); 733 734 /* change the zone name - copy both the length and the string */ 735 bcopy((caddr_t)new_zone, (caddr_t)&ifID->ifZoneName, 736 new_zone_len+1); 737 738 /* Send network zone change event and new zone for this interface. */ 739 atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName)); 740 atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONELISTCHANGED, 0, 0); 741 742 /* add the new zone to the list of local zones */ 743 if (!MULTIPORT_MODE && !DEFAULT_ZONE(&ifID->ifZoneName)) 744 (void)setLocalZones(&ifID->ifZoneName, 745 (ifID->ifZoneName.len+1)); 746 747 /* Before trying to request our new multicast address, 748 * wait a while... someone might have alredy requested 749 * it, so we may see some broadcast messages flying 750 * by... Set up the structures so that it appears that 751 * we have already requested the NetInfo. 752 */ 753 ifID->ifNumRetries = ZIP_NETINFO_RETRIES; 754 netinfo_reply_pending = 1; 755 ifID->ifGNIScheduled = 1; 756 timeout(zip_sched_getnetinfo, (caddr_t) ifID, 757 2*ZIP_TIMER_INT); 758 759 gbuf_freem(m); 760 break; 761 default : 762 routing_needed(m, ifID, TRUE); 763 break; 764 } 765 } 766 else if (ddp->type == DDP_ATP && 767 RT_LOOKUP_OKAY(ifID, ddp)) { 768 if (gbuf_len(m) > DDP_X_HDR_SIZE) 769 atp = (at_atp_t *)(gbuf_rptr(m)+DDP_X_HDR_SIZE); 770 else 771 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m))); 772 773 /* Get the user bytes in network order */ 774 775 *((u_long*)user_bytes) = UAL_VALUE(atp->user_bytes); 776 user_byte = user_bytes[0]; /* Get the zeroth byte */ 777 778 dPrintf(D_M_ZIP, D_L_INPUT, 779 ("zip_input: received a ZIP_ATP command=%d\n", user_byte)); 780 781 switch (user_byte) { 782 case ZIP_GETMYZONE: 783 zip_reply_to_getmyzone(ifID, m); 784 gbuf_freem(m); 785 break; 786 787 case ZIP_GETZONELIST: 788 zip_reply_to_getzonelist(ifID, m); 789 gbuf_freem(m); 790 break; 791 792 case ZIP_GETLOCALZONES: 793 zip_reply_to_getlocalzones(ifID, m); 794 gbuf_freem(m); 795 break; 796 797 default: 798 dPrintf(D_M_ZIP, D_L_WARNING, 799 ("zip_input: received unknown ZIP_ATP command=%d\n", user_byte)); 800 routing_needed(m, ifID, TRUE); 801 break; 802 } 803 } else { 804 gbuf_freem(m); 805 } 806 return; 807} /* zip_router_input */ 808 809/*********************************************************************** 810 * zonename_equal() 811 * 812 * Remarks : 813 * 814 **********************************************************************/ 815int zonename_equal (zone1, zone2) 816 register at_nvestr_t *zone1, *zone2; 817{ 818 register char c1, c2; 819 register int i; 820 821 if (zone1->len != zone2->len) 822 return(0); 823 824 for (i=0; i< (int) zone1->len; i++) { 825 c1 = zone1->str[i]; 826 c2 = zone2->str[i]; 827 if (c1 >= 'a' && c1 <= 'z') 828 c1 += 'A' - 'a'; 829 if (c2 >= 'a' && c2 <= 'z') 830 c2 += 'A' - 'a'; 831 if (c1 & 0x80) 832 c1 = upshift8(c1); 833 if (c2 & 0x80) 834 c2 = upshift8(c2); 835 if (c1 != c2) 836 return(0); 837 } 838 return(1); 839} 840 841 842char upshift8 (ch) 843 register char ch; 844{ 845 register int i; 846 847 static unsigned char lower_case[] = 848 {0x8a, 0x8c, 0x8d, 0x8e, 0x96, 0x9a, 0x9f, 0xbe, 849 0xbf, 0xcf, 0x9b, 0x8b, 0x88, 0}; 850 static unsigned char upper_case[] = 851 {0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xae, 852 0xaf, 0xce, 0xcd, 0xcc, 0xcb, 0}; 853 854 for (i=0; lower_case[i]; i++) 855 if (ch == lower_case[i]) 856 return (upper_case[i]); 857 858 return(ch); 859} 860 861 862/*********************************************************************** 863 * zip_netinfo_reply () 864 * 865 * Remarks : 866 * 867 **********************************************************************/ 868static void zip_netinfo_reply (netinfo, ifID) 869 register at_x_zip_t *netinfo; 870 register at_ifaddr_t *ifID; 871{ 872 u_char mcast_len; 873 register at_net_al this_net; 874 char *default_zone; 875 register u_char zone_name_len; 876 877 /* There may be multiple zones on the cable.... we need to 878 * worry about whether or not this packet is addressed 879 * to us. 880 */ 881 /* *** Do we really need to check this? *** */ 882 if (!zonename_equal((at_nvestr_t *)netinfo->data, &ifID->ifZoneName)) { 883 dPrintf(D_M_ZIP, D_L_INFO, ("zip_netinfo_reply, !zonename_equal!!!")); 884 return; 885 } 886 887 ifID->ifThisCableStart = NET_VALUE(netinfo->cable_range_start); 888 ifID->ifThisCableEnd = NET_VALUE(netinfo->cable_range_end); 889 dPrintf(D_M_ZIP, D_L_OUTPUT, ("Zip_netinfo_reply: Set cable to %d-%d\n", 890 ifID->ifThisCableStart, ifID->ifThisCableEnd)); 891 892 /* The packet is in response to our request */ 893 ifID->ifGNIScheduled = 0; 894 untimeout (zip_sched_getnetinfo, (caddr_t) ifID); 895 netinfo_reply_pending = 0; 896 zone_name_len = netinfo->data[0]; 897 mcast_len = netinfo->data[zone_name_len + 1]; 898 899 if (netinfo->flags & ZIP_ZONENAME_INVALID) { 900 /* copy out the default zone name from packet */ 901 default_zone = (char *)&netinfo->data[zone_name_len+1+mcast_len+1]; 902 bcopy((caddr_t)default_zone, (caddr_t)&ifID->ifZoneName, 903 *default_zone + 1); 904 } 905 906 /* add the new zone to the list of local zones */ 907 if (!MULTIPORT_MODE && !DEFAULT_ZONE(&ifID->ifZoneName)) 908 (void)setLocalZones(&ifID->ifZoneName, (ifID->ifZoneName.len+1)); 909 910 /* get the multicast address out of the GetNetInfo reply, if there is one */ 911 if (!(netinfo->flags & ZIP_USE_BROADCAST)) { 912 /* If ZIP_USE_BROADCAST is set, we will use the cable 913 broadcast address as the multicast address, however 914 the cable multicast address has already been registered. 915 */ 916 /* This packet contains a multicast address, so 917 * send to elap to register it. 918 */ 919 if (FDDI_OR_TOKENRING(ifID->aa_ifp->if_type)) 920 ddp_bit_reverse(&netinfo->data[zone_name_len + 2]); 921 922 bcopy((caddr_t)&netinfo->data[zone_name_len + 2], 923 (caddr_t)&ifID->ZoneMcastAddr, ETHERNET_ADDR_LEN); 924 (void)at_reg_mcast(ifID, (caddr_t)&ifID->ZoneMcastAddr); 925 } 926 927 this_net = ifID->ifThisNode.s_net; 928 if ((this_net >= ifID->ifThisCableStart) && 929 (this_net <= ifID->ifThisCableEnd)) { 930 /* ThisNet is in the range of valid network numbers 931 * for the cable. Do nothing. 932 */ 933 } else { 934 /* ThisNet is not in the range of valid network 935 * numbers for the cable. This may be either because 936 * the chosen number was from start-up range, or 937 * because the user has a misconception of where the 938 * machine is!! Since ThisCableRange is set up, next 939 * time aarp is invoked, it would select address in 940 * the right range. 941 */ 942 943 /* to reset initial_net and initial_node to zero, so 944 * that aarp is forced to choose new values 945 */ 946 ifID->initial_addr.s_net = 0; 947 ifID->initial_addr.s_node = 0; 948 949 /* Wake up elap_online sleeping on this interface. */ 950 ZIPwakeup(ifID, ZIP_RE_AARP); 951 return; 952 } 953 954 if (!ifID->startup_inprogress) { 955 /* Send event with zone info. This covers case where we get zone info 956 after startup. During startup this event is sent from ZIPwakeup. */ 957 atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName)); 958 } 959 960 ZIPwakeup(ifID, 0); /* no error */ 961 return; 962} /* zip_netinfo_reply */ 963 964 965/********************************************************************** 966 * zip_control() 967 * 968 **********************************************************************/ 969int zip_control (ifID, control) 970 register at_ifaddr_t *ifID; 971 int control; 972{ 973 dPrintf(D_M_ZIP, D_L_INFO, ("zip_control called port=%d control=%d\n", 974 ifID->ifPort, control)); 975 switch (control) { 976 case ZIP_ONLINE : 977 case ZIP_LATE_ROUTER : 978 if (!ifID->ifGNIScheduled) { 979 ifID->ifNumRetries = 0; 980 /* Get the desired zone name from elap and put it in 981 * ifID for zip_getnetinfo() to use. 982 */ 983 if (ifID->startup_zone.len) 984 ifID->ifZoneName = ifID->startup_zone; 985 zip_getnetinfo(ifID); 986 } 987 break; 988 case ZIP_NO_ROUTER : 989 ifID->ifZoneName.len = 1; 990 ifID->ifZoneName.str[0] = '*'; 991 ifID->ifZoneName.str[1] = '\0'; 992 993 /* Send event with zone info. */ 994 atalk_post_msg(ifID->aa_ifp, KEV_ATALK_ZONEUPDATED, 0, &(ifID->ifZoneName)); 995 996 break; 997 default : 998 break; 999 } 1000 return (0); 1001} 1002 1003/* locked version of zip_getnetinfo */ 1004static void 1005zip_getnetinfo_locked(void *arg) 1006{ 1007 at_ifaddr_t *ifID; 1008 1009 atalk_lock(); 1010 if (arg != NULL) { // make sure it hasn't been closed 1011 ifID = (at_ifaddr_t *)arg; 1012 ifID->ifGNIScheduled = 0; 1013 zip_getnetinfo(ifID); 1014 } 1015 atalk_unlock(); 1016} 1017 1018 1019/********************************************************************** 1020 * zip_getnetinfo() 1021 * 1022 **********************************************************************/ 1023static void zip_getnetinfo (ifID) 1024 register at_ifaddr_t *ifID; 1025{ 1026 register at_x_zip_t *zip; 1027 gbuf_t *m; 1028 register at_ddp_t *ddp; 1029 register struct atalk_addr *at_dest; 1030 register int size; 1031 1032 1033 size = DDP_X_HDR_SIZE + ZIP_X_HDR_SIZE + ifID->ifZoneName.len + 1 1034 + sizeof(struct atalk_addr) + 1; 1035 if ((m = gbuf_alloc (AT_WR_OFFSET+size, PRI_HI)) == NULL) { 1036 /* This time, we're unable to allocate buffer to 1037 * send a packet out, so schedule to send a packet 1038 * out later, and exit. 1039 */ 1040 dPrintf(D_M_ZIP, D_L_WARNING, ("zip_getnetinfo: no buffer, call later port=%d\n", 1041 ifID->ifPort)); 1042 ifID->ifGNIScheduled = 1; 1043 timeout (zip_getnetinfo_locked, (caddr_t) ifID, ZIP_TIMER_INT/10); 1044 return; 1045 } 1046 1047 gbuf_rinc(m,AT_WR_OFFSET); 1048 gbuf_wset(m,0); 1049 *(u_char *)gbuf_rptr(m) = AT_ADDR; 1050 at_dest = (struct atalk_addr *)(gbuf_rptr(m) + 1); 1051 ddp = (at_ddp_t *)(gbuf_rptr(m) + sizeof(struct atalk_addr) + 1); 1052 zip = (at_x_zip_t *)ddp->data; 1053 gbuf_winc(m,size); 1054 1055 zip->command = ZIP_GETNETINFO; 1056 zip->flags = 0; 1057 NET_ASSIGN(zip->cable_range_start, 0); 1058 NET_ASSIGN(zip->cable_range_end, 0); 1059 if (ifID->ifZoneName.len) /* has to match reply exactly */ 1060 bcopy((caddr_t)&ifID->ifZoneName, (caddr_t)zip->data, 1061 ifID->ifZoneName.len + 1); 1062 else 1063 zip->data[0] = 0; /* No zone name is availbale */ 1064 1065 /* let the lap fields be uninitialized, 'cause it doesn't 1066 * matter. 1067 */ 1068 DDPLEN_ASSIGN(ddp, (size - (sizeof(struct atalk_addr) + 1))); 1069 UAS_ASSIGN(ddp->checksum, 0); 1070 ddp->hopcount = ddp->unused = 0; 1071 NET_ASSIGN(ddp->dst_net, 0); /* cable-wide broadcast */ 1072 NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net); 1073 /* By this time, AARP is done */ 1074 1075 ddp->dst_node = 0xff; 1076 ddp->src_node = ifID->ifThisNode.s_node; 1077 ddp->dst_socket = ZIP_SOCKET; 1078 ddp->src_socket = ZIP_SOCKET; 1079 ddp->type = DDP_ZIP; 1080 1081 at_dest->atalk_unused = 0; 1082 NET_NET(at_dest->atalk_net, ddp->dst_net); 1083 at_dest->atalk_node = ddp->dst_node; 1084 1085 dPrintf(D_M_ZIP, D_L_INPUT, ("zip_getnetinfo: called for port=%d\n", 1086 ifID->ifPort)); 1087 1088 if (elap_dataput(m, ifID, 0, NULL)) { 1089 dPrintf(D_M_ZIP, D_L_ERROR, 1090 ("zip_getnetinfo: error sending zip_getnetinfo\n")); 1091 return; 1092 } 1093 1094 ifID->ifNumRetries++; 1095 netinfo_reply_pending = 1; 1096 ifID->ifGNIScheduled = 1; 1097 timeout (zip_sched_getnetinfo, (caddr_t) ifID, ZIP_TIMER_INT); 1098} /* zip_getnetinfo */ 1099 1100 1101/********************************************************************** 1102 * zip_sched_getnetinfo() 1103 * 1104 **********************************************************************/ 1105 1106void zip_sched_getnetinfo(void *arg) 1107{ 1108 register at_ifaddr_t *ifID = (at_ifaddr_t *)arg; 1109 1110 atalk_lock(); 1111 1112 ifID->ifGNIScheduled = 0; 1113 1114 if (ifID->ifNumRetries >= ZIP_NETINFO_RETRIES) { 1115 /* enough packets sent.... give up! */ 1116 /* we didn't get any response from the net, so 1117 * assume there's no router around and the given 1118 * zone name, if any, is not valid. Change the 1119 * zone name to "*". 1120 */ 1121 ifID->ifZoneName.len = 1; 1122 ifID->ifZoneName.str[0] = '*'; 1123 ifID->ifZoneName.str[1] = '\0'; 1124 /* Should NBP be notified of this "new" zone name?? */ 1125 netinfo_reply_pending = 0; 1126 1127 ifID->ifRouterState = NO_ROUTER; 1128 ifID->ifARouter.s_net = 0; 1129 ifID->ifARouter.s_node = 0; 1130 1131 dPrintf(D_M_ZIP, D_L_INFO, ("zip_sched_getnetinfo: Reset Cable Range\n")); 1132 1133 ifID->ifThisCableStart = DDP_MIN_NETWORK; 1134 ifID->ifThisCableEnd = DDP_MAX_NETWORK; 1135 1136 if (ifID->ifState == LAP_ONLINE_FOR_ZIP) 1137 ZIPwakeup (ifID, 0); /* no error */ 1138 } else 1139 zip_getnetinfo(ifID); 1140 1141 atalk_unlock(); 1142} 1143 1144 1145/********************************************************************** 1146 * zip_type_packet() 1147 * 1148 * Remarks: 1149 * This routine checks whether or not the packet contained in "m" 1150 * is an (outgoing) ZIP packet. If not, it returns 0. If it is a 1151 * ZIP packet, it returns the ZIP packet type (ZIP command). "m" 1152 * points to a packet with extended DDP header. The rest of the 1153 * DDP data may or may not be in the first gbuf. 1154 * 1155 **********************************************************************/ 1156int zip_type_packet (m) 1157 register gbuf_t *m; 1158{ 1159 register at_atp_t *atp; 1160 register at_ddp_t *ddp; 1161 register at_zip_t *zip; 1162 u_char user_bytes[4]; 1163 register int user_byte; 1164 1165 ddp = (at_ddp_t *)gbuf_rptr(m); 1166 if (ddp->dst_socket == ZIP_SOCKET) { 1167 switch (ddp->type) { 1168 case DDP_ZIP : 1169 if (gbuf_len(m) > DDP_X_HDR_SIZE) 1170 zip = (at_zip_t *)(gbuf_rptr(m) 1171 + DDP_X_HDR_SIZE); 1172 else 1173 zip=(at_zip_t *)(gbuf_rptr(gbuf_cont(m))); 1174 return ((int)zip->command); 1175 case DDP_ATP : 1176 if (gbuf_len(m) > DDP_X_HDR_SIZE) 1177 atp = (at_atp_t *)(gbuf_rptr(m)+DDP_X_HDR_SIZE); 1178 else 1179 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m))); 1180 /* Get the user bytes in network order */ 1181 *((u_long*)user_bytes) = UAL_VALUE(atp->user_bytes); 1182 user_byte = user_bytes[0]; /* Get the zeroth byte */ 1183 if ((user_byte == ZIP_GETMYZONE) || 1184 (user_byte == ZIP_GETZONELIST) || 1185 (user_byte == ZIP_GETLOCALZONES)) 1186 return (user_byte); 1187 else 1188 return (0); 1189 default : 1190 return (0); 1191 } 1192 } else 1193 return (0); 1194} 1195 1196/********************************************************************** 1197 * zip_handle_getmyzone() 1198 * 1199 * Remarks: 1200 * Routine to handle ZIP GetMyZone request locally. It generates 1201 * a phony response to the outgoing ATP request and sends it up. 1202 * 1203 * 07/12/94 : remark2 only called from ddp.c / ddp_output 1204 * should only be called from the home port, but 1205 * when we are a router we should know the infos for all 1206 * anyway, so reply locally with what we have in stock... 1207 * 1208 **********************************************************************/ 1209 1210int zip_handle_getmyzone(ifID, m) 1211 register at_ifaddr_t *ifID; 1212 register gbuf_t *m; 1213{ 1214 at_atp_t *atp; 1215 register at_ddp_t *ddp; 1216 register at_ddp_t *r_ddp; 1217 register at_atp_t *r_atp; 1218 gbuf_t *rm; /* reply message */ 1219 register int size; 1220 u_long ulongtmp; 1221 1222 dPrintf(D_M_ZIP, D_L_INFO, 1223 ("zip_handle_getmyzone: local reply for port=%d\n", 1224 ifID->ifPort)); 1225 1226 size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + 1 + ifID->ifZoneName.len; 1227 /* space for two headers and the zone name */ 1228 if ((rm = gbuf_alloc(AT_WR_OFFSET+size, PRI_HI)) == NULL) { 1229 dPrintf(D_M_ZIP, D_L_WARNING, 1230 ("zip_handle_getmyzone: no buffer, port=%d\n", 1231 ifID->ifPort)); 1232 return (ENOBUFS); 1233 } 1234 1235 gbuf_rinc(rm,AT_WR_OFFSET); 1236 gbuf_wset(rm,0); 1237 r_ddp = (at_ddp_t *)(gbuf_rptr(rm)); 1238 r_atp = (at_atp_t *)r_ddp->data; 1239 gbuf_winc(rm,size); 1240 1241 ddp = (at_ddp_t *)gbuf_rptr(m); 1242 if (gbuf_len(m) > DDP_X_HDR_SIZE) 1243 atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE); 1244 else 1245 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m))); 1246 1247 /* fill up the ddp header for reply */ 1248 DDPLEN_ASSIGN(r_ddp, size); 1249 r_ddp->hopcount = r_ddp->unused = 0; 1250 UAS_ASSIGN(r_ddp->checksum, 0); 1251 NET_ASSIGN(r_ddp->dst_net, ifID->ifThisNode.s_net); 1252 NET_NET(r_ddp->src_net, ddp->dst_net); 1253 r_ddp->dst_node = ifID->ifThisNode.s_node; 1254 r_ddp->src_node = ddp->dst_node; 1255 r_ddp->dst_socket = ddp->src_socket; 1256 r_ddp->src_socket = ZIP_SOCKET; 1257 r_ddp->type = DDP_ATP; 1258 1259 /* fill up the atp header */ 1260 r_atp->cmd = ATP_CMD_TRESP; 1261 r_atp->xo = 0; 1262 r_atp->eom = 1; 1263 r_atp->sts = 0; 1264 r_atp->xo_relt = 0; 1265 r_atp->bitmap = 0; 1266 UAS_UAS(r_atp->tid, atp->tid); 1267 ulongtmp = 1; 1268 UAL_ASSIGN_HTON(r_atp->user_bytes, ulongtmp); /* no of zones */ 1269 1270 /* fill up atp data part */ 1271 bcopy((caddr_t) &ifID->ifZoneName, (caddr_t) r_atp->data, ifID->ifZoneName.len+1); 1272 1273 /* all set to send the packet back up */ 1274 1275 timeout(send_phony_reply, (caddr_t) rm, HZ/20); 1276 return (0); 1277} 1278 1279static void 1280send_phony_reply(arg) 1281 void *arg; 1282{ 1283 gbuf_t *rm = (gbuf_t *)arg; 1284 1285 atalk_lock(); 1286 ddp_input(rm, ifID_home); 1287 atalk_unlock(); 1288 1289 return; 1290} 1291 1292 1293/* 1294 * zip_prep_query_packet: build the actual ddp packet for the zip query 1295 */ 1296 1297gbuf_t *zip_prep_query_packet(ifID, RouterNet, RouterNode) 1298 at_ifaddr_t *ifID; 1299 at_net_al RouterNet; /* we want to send the Zip Query to that router */ 1300 at_node RouterNode; 1301{ 1302 1303 register gbuf_t *m; 1304 register at_ddp_t *ddp; 1305 1306 if ((m = gbuf_alloc (AT_WR_OFFSET+1024, PRI_HI)) == NULL) { 1307 dPrintf(D_M_ZIP, D_L_WARNING, 1308 ("zip_send_query_packet: no buffer, port=%d\n", 1309 ifID->ifPort)); 1310 return((gbuf_t *)NULL); 1311 } 1312 gbuf_rinc(m,AT_WR_OFFSET); 1313 gbuf_wset(m,0); 1314 1315 ddp = (at_ddp_t *)(gbuf_rptr(m)); 1316 1317 /* Prepare the DDP header */ 1318 1319 ddp->unused = ddp->hopcount = 0; 1320 UAS_ASSIGN(ddp->checksum, 0); 1321 NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net); 1322 ddp->src_node = ifID->ifThisNode.s_node; 1323 ddp->src_socket = ZIP_SOCKET; 1324 1325 ddp->dst_socket = ZIP_SOCKET; 1326 NET_ASSIGN(ddp->dst_net, RouterNet); 1327 ddp->dst_node = RouterNode; 1328 1329 ddp->type = DDP_ZIP; 1330 1331 return (m); 1332} /* zip_prep_query_packet */ 1333 1334 1335/* 1336 * zip_send_queries: this function send queries for the routing table entries that 1337 * need to know their zones. It scans the routing table for entries with unknown 1338 * zones and build Query packets accordingly. 1339 * Note: this is called on a per port basis. 1340 */ 1341 1342void zip_send_queries(ifID, RouterNet, RouterNode) 1343 register at_ifaddr_t *ifID; 1344 at_net_al RouterNet; /* we want to send the Zip Query to that router */ 1345 at_node RouterNode; 1346{ 1347 RT_entry *Entry = &RT_table[0]; 1348 register gbuf_t *m; 1349 register at_ddp_t *ddp; 1350 int status; 1351 short Query_index, EntryNumber = 0 ; 1352 register u_char port = ifID->ifPort; 1353 char *QueryBuff, *ZoneCount; 1354 short zip_sent = FALSE; 1355 1356newPacket: 1357 1358 if (!(m = zip_prep_query_packet(ifID, RouterNet, RouterNode))) { 1359 return; /* was return (ENOBUFS); */ 1360 } 1361 1362 ddp = (at_ddp_t *)(gbuf_rptr(m)); 1363 QueryBuff = (char *)ddp->data; 1364 1365 *QueryBuff++ = ZIP_QUERY; 1366 ZoneCount = QueryBuff; /* network count */ 1367 *ZoneCount = 0; 1368 QueryBuff++; 1369 Query_index = 2; 1370 1371 1372 while (EntryNumber < RT_maxentry) { 1373 1374 /* scan the table, and build the packet with the right entries: 1375 * - entry in use and on the right Port 1376 * - with unknwon zones and in an active state 1377 * - talking to the right router 1378 */ 1379 1380 if ((Query_index) > 2*254 +2) { 1381 1382 /* we need to send the packet now, but we can't have more than 256 1383 * requests for networks: the Netcount field is a 8bit in the zip query 1384 * packet format as defined in Inside Atalk 1385 */ 1386 1387 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT, 1388 ("zip_send_query: FULL query for %d nets on port#%d.(len=%d)\n", 1389 *ZoneCount, port, Query_index)); 1390 zip_sent = TRUE; 1391 1392 gbuf_winc(m,DDP_X_HDR_SIZE + Query_index); 1393 DDPLEN_ASSIGN(ddp, (DDP_X_HDR_SIZE + Query_index)); 1394 1395 if ((status = 1396 ddp_router_output(m, ifID, AT_ADDR, 1397 RouterNet, RouterNode, 0))) { 1398 dPrintf(D_M_ZIP, D_L_ERROR, 1399 ("zip_send_query: ddp_router_output returns =%d\n", status)); 1400 return; /* was return (status); */ 1401 } 1402 1403 goto newPacket; 1404 } 1405 1406 1407 if (((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) && 1408 (Entry->NetStop) && (Entry->NetPort == port) && 1409 (!RT_ALL_ZONES_KNOWN(Entry))){ 1410 1411 /* we're ready to had that to our list of stuff to send */ 1412 1413 if (Entry->NetStart) { /* extended net*/ 1414 1415 *QueryBuff++ = (Entry->NetStart & 0xFF00) >> 8; 1416 *QueryBuff++ = (Entry->NetStart & 0x00FF); 1417 1418 } 1419 else { 1420 *QueryBuff++ = (Entry->NetStop & 0xFF00) >> 8; 1421 *QueryBuff++ = (Entry->NetStop & 0x00FF); 1422 } 1423 1424 Query_index += 2; 1425 *ZoneCount += 1;/* bump the number of network requested */ 1426 1427 } 1428 1429 Entry++; 1430 EntryNumber++; 1431 1432 } 1433 1434 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT, 1435 ("zip_send_query: query for %d nets on port#%d.(len=%d)\n", 1436 *ZoneCount, port, Query_index)); 1437 1438 if (*ZoneCount) { /* non-full Query needs to be sent */ 1439 zip_sent = TRUE; 1440 gbuf_winc(m,DDP_X_HDR_SIZE + Query_index); 1441 DDPLEN_ASSIGN(ddp, (DDP_X_HDR_SIZE + Query_index)); 1442 1443 if ((status = 1444 ddp_router_output(m, ifID, AT_ADDR, 1445 RouterNet, RouterNode, 0))) { 1446 dPrintf(D_M_ZIP, D_L_ERROR, 1447 ("zip_send_query: ddp_router_output returns =%d\n", 1448 status)); 1449 return; /* was return (status); */ 1450 } 1451 } 1452 else 1453 gbuf_freem(m); 1454 1455 if (!zip_sent) /* we didn't need to send anything for that port */ 1456 ifID->ifZipNeedQueries = 0; 1457} /* zip_send_queries */ 1458 1459/* zip_reply_received: we recieved the reply to one of our query, update the 1460 * zone bitmap and stuffs with was we received. 1461 * we receive two types of replies: non extended and extended. 1462 * For extended replies, the network count is the Total of zones for that net. 1463 */ 1464int 1465zip_reply_received(m, ifID, reply_type) 1466 register gbuf_t *m; 1467 register at_ifaddr_t *ifID; 1468 int reply_type; 1469{ 1470 register at_nvestr_t *zname; 1471 RT_entry *Entry = &RT_table[0]; 1472 register at_ddp_t *ddp; 1473 at_net_al Network; 1474 u_short payload_len, result; 1475 u_char network_count; 1476 char *PacketPtr; 1477 1478 ddp = (at_ddp_t *)gbuf_rptr(m); 1479 1480 /* access the number of nets provided in the ZIP Reply */ 1481 1482 network_count = ntohs(*(u_char *)(gbuf_rptr(m) + DDP_X_HDR_SIZE + 1)); 1483 1484 PacketPtr = (char *)(gbuf_rptr(m) + DDP_X_HDR_SIZE + 2); 1485 1486 payload_len = DDPLEN_VALUE(ddp) - (DDP_X_HDR_SIZE + 2); 1487 1488 dPrintf(D_M_ZIP_LOW, D_L_INPUT, ("zip_reply_received from %d:%d type=%d netcount=%d\n", 1489 NET_VALUE(ddp->src_net), ddp->src_node, reply_type, network_count)); 1490 1491 1492 while (payload_len > 0 && network_count >0) { 1493 1494 Network = ntohs(*(at_net_al *)PacketPtr); 1495 PacketPtr += 2; 1496 zname = (at_nvestr_t *)PacketPtr; 1497 if (payload_len) 1498 payload_len = payload_len -(zname->len + 3); 1499 1500 if (zname->len <= 0) { /* not valid, we got a problem here... */ 1501 dPrintf(D_M_ZIP, D_L_WARNING, 1502 ("zip_reply_received: Problem zlen=0 for net=%d from %d:%d type=%d netcnt=%d\n", 1503 Network, NET_VALUE(ddp->src_net), ddp->src_node, reply_type, network_count)); 1504 payload_len =0; 1505 continue; 1506 } 1507 1508 1509 Entry = rt_blookup(Network); 1510 1511 if (Entry != NULL) { 1512 1513 if (Entry->EntryState >= RTE_STATE_SUSPECT) { 1514 1515 result = zt_add_zonename(zname); 1516 1517 if (result == ZT_MAXEDOUT) { 1518 1519 dPrintf(D_M_ZIP, D_L_ERROR, 1520 ("zip_reply_received: ZTable full from %d:%d on zone '%s'\n", 1521 NET_VALUE(ddp->src_net), ddp->src_node, zname->str)); 1522 ErrorZIPoverflow = 1; 1523 return(1); 1524 } 1525 1526 zt_set_zmap(result, Entry->ZoneBitMap); 1527 1528 RT_SET_ZONE_KNOWN(Entry); 1529 1530 } 1531 else { 1532 dPrintf(D_M_ZIP, D_L_INPUT, 1533 ("zip_reply_received: entry %d-%d not updated, cause state=%d\n", 1534 Entry->NetStart, Entry->NetStop, Entry->EntryState)); 1535 } 1536 } 1537 else { 1538 dPrintf(D_M_ZIP, D_L_WARNING, 1539 ("zip_reply_received: network %d not found in RT\n", Network)); 1540 } 1541 1542 1543 /* now bump the PacketPtr pointer */ 1544 PacketPtr += zname->len + 1; 1545 network_count--; 1546 } 1547 1548 if ((reply_type == ZIP_REPLY) && network_count > 0) { 1549#if DEBUG 1550 if (Entry) 1551 dPrintf(D_M_ZIP, D_L_WARNING, 1552 ("zip_reply_received: Problem decoding zone (after net:%d-%d)\n", 1553 Entry->NetStart, Entry->NetStop)); 1554#endif 1555 ifID->ifZipNeedQueries = 1; 1556 } 1557 else { 1558 ifID->ifZipNeedQueries = 0; 1559#if DEBUG 1560 if (Entry) 1561 dPrintf(D_M_ZIP_LOW, D_L_INFO, 1562 ("zip_reply_received: entry %d-%d all zones known\n", 1563 Entry->NetStart, Entry->NetStop)); 1564#endif 1565 } 1566 1567 return 0; 1568} 1569 1570/* 1571 * zip_reply_to_getmyzone: replies to ZIP GetMyZone received from the Net 1572 */ 1573 1574static void zip_reply_to_getmyzone (ifID, m) 1575 register at_ifaddr_t *ifID; 1576 register gbuf_t *m; 1577{ 1578 at_atp_t *atp; 1579 register at_ddp_t *ddp; 1580 register at_ddp_t *r_ddp; 1581 register at_atp_t *r_atp; 1582 register gbuf_t *rm; /* reply message */ 1583 register int size, Index, status; 1584 char *data_ptr; 1585 RT_entry *Entry; 1586 u_long ulongtmp; 1587 1588 size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + 1 + ifID->ifZoneName.len; 1589 /* space for two headers and the zone name */ 1590 if ((rm = gbuf_alloc(AT_WR_OFFSET+size, PRI_HI)) == NULL) { 1591 dPrintf(D_M_ZIP, D_L_WARNING, 1592 ("zip_reply_to_getmyzone: no buffer, port=%d\n", ifID->ifPort)); 1593 return; /* was return (ENOBUFS); */ 1594 } 1595 gbuf_rinc(rm,AT_WR_OFFSET); 1596 gbuf_wset(rm,size); 1597 r_ddp = (at_ddp_t *)(gbuf_rptr(rm)); 1598 r_atp = (at_atp_t *)r_ddp->data; 1599 1600 ddp = (at_ddp_t *)gbuf_rptr(m); 1601 if (gbuf_len(m) > DDP_X_HDR_SIZE) 1602 atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE); 1603 else 1604 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m))); 1605 1606 /* fill up the ddp header for reply */ 1607 DDPLEN_ASSIGN(r_ddp, size); 1608 r_ddp->hopcount = r_ddp->unused = 0; 1609 UAS_ASSIGN(r_ddp->checksum, 0); 1610 1611 NET_ASSIGN(r_ddp->src_net, ifID->ifThisNode.s_net); 1612 NET_NET(r_ddp->dst_net, ddp->src_net); 1613 1614 r_ddp->src_node = ifID->ifThisNode.s_node; 1615 r_ddp->dst_node = ddp->src_node; 1616 1617 r_ddp->dst_socket = ddp->src_socket; 1618 r_ddp->src_socket = ZIP_SOCKET; 1619 r_ddp->type = DDP_ATP; 1620 1621 /* fill up the atp header */ 1622 r_atp->cmd = ATP_CMD_TRESP; 1623 r_atp->xo = 0; 1624 r_atp->eom = 1; 1625 r_atp->sts = 0; 1626 r_atp->xo_relt = 0; 1627 r_atp->bitmap = 0; 1628 UAS_UAS(r_atp->tid, atp->tid); 1629 ulongtmp = 1; 1630 UAL_ASSIGN_HTON(r_atp->user_bytes, ulongtmp); /* no of zones */ 1631 1632 data_ptr = (char *)r_atp->data; 1633 1634 /* 1635 * fill up atp data part with the zone name if we can find it... 1636 */ 1637 1638 Entry = rt_blookup(NET_VALUE(ddp->src_net)); 1639 if (Entry != NULL && ((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) && 1640 RT_ALL_ZONES_KNOWN(Entry)) { /* this net is well known... */ 1641 1642 Index = zt_ent_zindex(Entry->ZoneBitMap) -1; 1643 1644 *data_ptr = ZT_table[Index].Zone.len; 1645 bcopy((caddr_t) &ZT_table[Index].Zone.str, (caddr_t) ++data_ptr, 1646 ZT_table[Index].Zone.len); 1647 1648 /* all set to send the packet back up */ 1649 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT, 1650 ("zip_reply_to_GMZ: ddp_router_output to %d:%d port %d\n", 1651 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, ifID->ifPort)); 1652 1653 if ((status = 1654 ddp_router_output(rm, ifID, AT_ADDR, 1655 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, 0))) { 1656 dPrintf(D_M_ZIP, D_L_ERROR, 1657 ("zip_reply_to_GMZ: ddp_r_output returns =%d\n", status)); 1658 return; /* was return (status); */ 1659 } 1660 } 1661 else 1662 gbuf_freem(rm); 1663} 1664 1665/* 1666 * zip_reply_to_getzonelist: replies to ZIP GetZoneList requested from the Net 1667 */ 1668 1669int 1670zip_reply_to_getzonelist (ifID, m) 1671 register at_ifaddr_t *ifID; 1672 register gbuf_t *m; 1673{ 1674 at_atp_t *atp; 1675 register at_ddp_t *ddp; 1676 register at_ddp_t *r_ddp; 1677 register at_atp_t *r_atp; 1678 register gbuf_t *rm; /* reply message */ 1679 register int size, status; 1680 register short Index=0, StartPoint, ZLength, PacketLen=0; 1681 u_long ulongtmp= 0; 1682 char *Reply; 1683 1684 ddp = (at_ddp_t *)gbuf_rptr(m); 1685 if (gbuf_len(m) > DDP_X_HDR_SIZE) 1686 atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE); 1687 else 1688 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m))); 1689 1690 1691 /* space for two headers and the zone name */ 1692 1693 if ((rm = gbuf_alloc(AT_WR_OFFSET+1024, PRI_HI)) == NULL) { 1694 return (ENOBUFS); 1695 } 1696 1697 gbuf_rinc(rm,AT_WR_OFFSET); 1698 gbuf_wset(rm,0); 1699 r_ddp = (at_ddp_t *)(gbuf_rptr(rm)); 1700 r_atp = (at_atp_t *)r_ddp->data; 1701 1702 /* fill up the ddp header for reply */ 1703 1704 r_ddp->hopcount = r_ddp->unused = 0; 1705 UAS_ASSIGN(r_ddp->checksum, 0); 1706 NET_ASSIGN(r_ddp->src_net, ifID->ifThisNode.s_net); 1707 NET_NET(r_ddp->dst_net, ddp->src_net); 1708 r_ddp->src_node = ifID->ifThisNode.s_node; 1709 r_ddp->dst_node = ddp->src_node; 1710 r_ddp->dst_socket = ddp->src_socket; 1711 r_ddp->src_socket = ZIP_SOCKET; 1712 r_ddp->type = DDP_ATP; 1713 1714 /* fill up the atp header */ 1715 1716 r_atp->cmd = ATP_CMD_TRESP; 1717 r_atp->xo = 0; 1718 r_atp->eom = 1; 1719 r_atp->sts = 0; 1720 r_atp->xo_relt = 0; 1721 r_atp->bitmap = 0; 1722 UAS_UAS(r_atp->tid, atp->tid); 1723 1724 Reply = (char *)r_atp->data; 1725 1726 /* get the start index from the ATP request */ 1727 1728 StartPoint = (UAL_VALUE_NTOH(atp->user_bytes) & 0xffff) -1; 1729 1730 /* find the next zone to send */ 1731 1732 while ((Index < ZT_maxentry) && StartPoint > 0) { 1733 if (ZT_table[Index].Zone.len) 1734 StartPoint--; 1735 Index++; 1736 } 1737 1738 1739 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT, ("zip_reply_to_GZL: Index=%d\n", Index)); 1740 /* 1741 * fill up atp data part with the zone name if we can find it... 1742 */ 1743 1744 while (Index < ZT_maxentry) { 1745 1746 ZLength = ZT_table[Index].Zone.len; 1747 1748 if (ZT_table[Index].ZoneCount && ZLength) { 1749 1750 1751 if (PacketLen + 8 + ZLength+1 > DDP_DATA_SIZE) /* packet full */ 1752 break; 1753 1754 *Reply++ = ZLength; 1755 bcopy((caddr_t) &ZT_table[Index].Zone.str, 1756 Reply, ZLength); 1757 Reply += ZLength; 1758 PacketLen += ZLength + 1; 1759 ulongtmp++; 1760 } 1761 Index++; 1762 } 1763 1764 if (Index >= ZT_maxentry) /* this is the end of the list */ 1765 1766 ulongtmp += 0x01000000; 1767 1768 1769 UAL_ASSIGN_HTON(r_atp->user_bytes, ulongtmp); /* # of zones and flag*/ 1770 1771 size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + PacketLen; 1772 gbuf_winc(rm,size); 1773 DDPLEN_ASSIGN(r_ddp, size); 1774 1775 /* all set to send the packet back up */ 1776 1777 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT, 1778 ("zip_r_GZL: send packet to %d:%d port %d atp_len =%d\n", 1779 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, ifID->ifPort, PacketLen)); 1780 1781 1782 if ((status= ddp_router_output(rm, ifID, AT_ADDR, 1783 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, 0))) { 1784 dPrintf(D_M_ZIP, D_L_ERROR, ("zip_reply_to_GZL: ddp_router_output returns=%d\n", 1785 status)); 1786 return (status); 1787 } 1788 return (0); 1789 1790} 1791 1792/* 1793 * zip_reply_to_getlocalzones: replies to ZIP GetLocalZones requested from the Net 1794 */ 1795 1796int zip_reply_to_getlocalzones (ifID, m) 1797 register at_ifaddr_t *ifID; 1798 register gbuf_t *m; 1799{ 1800 at_atp_t *atp; 1801 register at_ddp_t *ddp; 1802 register at_ddp_t *r_ddp; 1803 register at_atp_t *r_atp; 1804 register gbuf_t *rm; /* reply message */ 1805 int size, status; 1806 short Index, Index_wanted, ZLength; 1807 short i,j, packet_len; 1808 short zCount, ZoneCount, ZonesInPacket; 1809 unsigned char *zmap, last_flag = 0; 1810 RT_entry *Entry; 1811 char *Reply; 1812 1813 u_long ulongtmp = 0; 1814 1815 Index = Index_wanted = ZLength = i = j = packet_len = zCount = ZoneCount = 1816 ZonesInPacket = 0; 1817 1818 ddp = (at_ddp_t *)gbuf_rptr(m); 1819 if (gbuf_len(m) > DDP_X_HDR_SIZE) 1820 atp = (at_atp_t *)(gbuf_rptr(m) + DDP_X_HDR_SIZE); 1821 else 1822 atp = (at_atp_t *)(gbuf_rptr(gbuf_cont(m))); 1823 1824 /* space for two headers and the zone name */ 1825 1826 if ((rm = gbuf_alloc(AT_WR_OFFSET+1024, PRI_HI)) == NULL) { 1827 return (ENOBUFS); 1828 } 1829 1830 gbuf_rinc(rm,AT_WR_OFFSET); 1831 gbuf_wset(rm,0); 1832 r_ddp = (at_ddp_t *)(gbuf_rptr(rm)); 1833 r_atp = (at_atp_t *)r_ddp->data; 1834 1835 Reply = (char *)r_atp->data; 1836 1837 1838 /* get the start index from the ATP request */ 1839 1840 Index_wanted = (UAL_VALUE_NTOH(atp->user_bytes) & 0xffff) -1; 1841 1842 dPrintf(D_M_ZIP_LOW, D_L_INFO, 1843 ("zip_r_GLZ: for station %d:%d Index_wanted = %d\n", 1844 NET_VALUE(ddp->src_net), ddp->src_node, Index_wanted)); 1845 1846 Entry = rt_blookup(NET_VALUE(ddp->src_net)); 1847 1848 if (Entry != NULL && ((Entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) && 1849 RT_ALL_ZONES_KNOWN(Entry)) { /* this net is well known... */ 1850 1851 ZoneCount = zt_ent_zcount(Entry) ; 1852 1853 dPrintf(D_M_ZIP_LOW, D_L_INFO, 1854 ("zip_reply_GLZ: for %d:%d ZoneCount=%d\n", 1855 NET_VALUE(ddp->src_net), ddp->src_node, ZoneCount)); 1856 1857 zmap = &Entry->ZoneBitMap[0]; 1858 1859 /* 1860 * first of all, we want to find the "first next zone" in the bitmap, 1861 * to do so, we need to scan the bitmap and add the number of valid 1862 * zones we find until we reach the next zone to be sent in the reply 1863 */ 1864 1865 if (ZoneCount > Index_wanted) { 1866 1867 ZoneCount -= Index_wanted; 1868 1869 /* find the starting point in the bitmap according to index */ 1870 1871 for (i = 0; Index_wanted >= 0 && i < ZT_BYTES; i++) 1872 if (zmap[i]) { 1873 if (Index_wanted < 8) { 1874 /* how many zones in the bitmap byte */ 1875 for (j = 0, zCount =0; j < 8 ; j++) 1876 if ((zmap[i] << j) & 0x80) 1877 zCount++; 1878 if (Index_wanted < zCount) { 1879 for (j = 0 ; Index_wanted > 0 && j < 8 ; j++) 1880 if ((zmap[i] << j) & 0x80) 1881 Index_wanted--; 1882 break; 1883 } 1884 else 1885 Index_wanted -= zCount; 1886 } 1887 else 1888 for (j = 0 ; j < 8 ; j++) 1889 if ((zmap[i] << j) & 0x80) 1890 Index_wanted--; 1891 } 1892 1893 /* 1894 * now, we point to the begining of our next zones in the bitmap 1895 */ 1896 1897 while (i < ZT_BYTES) { 1898 1899 if (zmap[i]) { 1900 for (; j < 8 ; j++) 1901 if ((zmap[i] << j) & 0x80) { 1902 Index = i*8 + j; /* get the index in ZT */ 1903 1904 ZLength = ZT_table[Index].Zone.len; 1905 1906 if (ZT_table[Index].ZoneCount && ZLength) { 1907 if (packet_len + ATP_HDR_SIZE + ZLength + 1 > 1908 DDP_DATA_SIZE) 1909 goto FullPacket; 1910 1911 *Reply++ = ZLength; 1912 bcopy((caddr_t) &ZT_table[Index].Zone.str, 1913 Reply, ZLength); 1914 Reply += ZLength; 1915 packet_len += ZLength + 1; 1916 ZonesInPacket ++; 1917 dPrintf(D_M_ZIP_LOW, D_L_INFO, 1918 ("zip_reply_GLZ: add z#%d to packet (l=%d)\n", 1919 Index, packet_len)); 1920 } 1921 else { 1922 dPrintf(D_M_ZIP, D_L_WARNING, 1923 ("zip_reply_GLZ: no len for index=%d\n", 1924 Index)); 1925 } 1926 } 1927 } 1928 i++; 1929 j = 0; 1930 } 1931 } 1932 else /* set the "last flag" bit in the reply */ 1933 last_flag = 1; 1934 } 1935 else /* set the "last flag" bit in the reply */ 1936 last_flag = 1; 1937 1938FullPacket: 1939 1940 if (ZonesInPacket == ZoneCount) 1941 last_flag = 1; 1942 1943 1944 /* fill up the ddp header for reply */ 1945 1946 r_ddp->hopcount = r_ddp->unused = 0; 1947 UAS_ASSIGN(r_ddp->checksum, 0); 1948 1949 NET_ASSIGN(r_ddp->src_net, ifID->ifThisNode.s_net); 1950 NET_NET(r_ddp->dst_net, ddp->src_net); 1951 1952 r_ddp->src_node = ifID->ifThisNode.s_node; 1953 r_ddp->dst_node = ddp->src_node; 1954 1955 r_ddp->dst_socket = ddp->src_socket; 1956 r_ddp->src_socket = ZIP_SOCKET; 1957 r_ddp->type = DDP_ATP; 1958 1959 /* fill up the atp header */ 1960 r_atp->cmd = ATP_CMD_TRESP; 1961 r_atp->xo = 0; 1962 r_atp->eom = 1; 1963 r_atp->sts = 0; 1964 r_atp->xo_relt = 0; 1965 r_atp->bitmap = 0; 1966 UAS_UAS(r_atp->tid, atp->tid); 1967 ulongtmp = ((last_flag << 24) & 0xFF000000) + ZonesInPacket; /* # of zones and flag*/ 1968 UAL_ASSIGN_HTON(r_atp->user_bytes, ulongtmp); 1969 size = DDP_X_HDR_SIZE + ATP_HDR_SIZE + packet_len; 1970 gbuf_winc(rm,size); 1971 DDPLEN_ASSIGN(r_ddp, size); 1972 1973 /* all set to send the packet back up */ 1974 1975 dPrintf(D_M_ZIP_LOW, D_L_OUTPUT, 1976 ("zip_r_GLZ: send packet to %d:%d port %d atp_len =%d\n", 1977 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, ifID->ifPort, packet_len)); 1978 1979 if ((status= ddp_router_output(rm, ifID, AT_ADDR, 1980 NET_VALUE(r_ddp->dst_net), r_ddp->dst_node, 0))) { 1981 dPrintf(D_M_ZIP, D_L_ERROR, 1982 ("zip_reply_to_GLZ: ddp_router_output returns =%d\n", 1983 status)); 1984 return (status); 1985 } 1986 return (0); 1987} /* zip_reply_to_getlocalzones */ 1988 1989int regDefaultZone(ifID) 1990 at_ifaddr_t *ifID; 1991{ 1992 char data[ETHERNET_ADDR_LEN]; 1993 1994 if (!ifID) 1995 return(-1); 1996 1997 zt_get_zmcast(ifID, &ifID->ifZoneName, data); 1998 if (FDDI_OR_TOKENRING(ifID->aa_ifp->if_type)) 1999 ddp_bit_reverse((unsigned char *)data); 2000 bcopy((caddr_t)data, (caddr_t)&ifID->ZoneMcastAddr, ETHERNET_ADDR_LEN); 2001 (void)at_reg_mcast(ifID, (caddr_t)&ifID->ZoneMcastAddr); 2002 return(0); 2003} 2004