1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * Copyright (c) 1996 Apple Computer, Inc. 30 * 31 * Created April 8, 1996 by Tuyen Nguyen 32 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX. 33 * 34 * File: zi.c 35 */ 36 37#ifdef AURP_SUPPORT 38 39#include <sys/errno.h> 40#include <sys/types.h> 41#include <sys/param.h> 42#include <machine/spl.h> 43#include <sys/systm.h> 44#include <sys/kernel.h> 45#include <sys/proc.h> 46#include <sys/filedesc.h> 47#include <sys/fcntl.h> 48#include <sys/mbuf.h> 49#include <sys/socket.h> 50#include <sys/socketvar.h> 51#include <net/if.h> 52#include <kern/assert.h> 53 54#include <netat/sysglue.h> 55#include <netat/appletalk.h> 56#include <netat/at_pcb.h> 57#include <netat/at_var.h> 58#include <netat/routing_tables.h> 59#include <netat/aurp.h> 60#include <netat/debug.h> 61 62static int AURPgetzi(int, unsigned char *, short *, gbuf_t *, int); 63static void AURPsetzi(unsigned char, gbuf_t *, short, short); 64 65/* */ 66void AURPsndZReq(state) 67 aurp_state_t *state; 68{ 69 gbuf_t *m; 70 int msize; 71 aurp_hdr_t *hdrp; 72 short *net, nets_cnt, net_sent=0, entry_num=0; 73 RT_entry *entry = RT_table; 74 75 if (!state->get_zi || (state->rcv_state == AURPSTATE_Unconnected)) 76 return; 77 78l_more: 79 msize = sizeof(aurp_hdr_t); 80 if ((m = (gbuf_t *)gbuf_alloc(msize+AURP_MaxPktSize, PRI_MED)) == 0) { 81 dPrintf(D_M_AURP, D_L_WARNING, ("AURPsndZReq: node=%d, out of mblk\n", 82 state->rem_node)); 83 return; 84 } 85 gbuf_wset(m,msize); 86 87 /* construct the ZI request packet */ 88 hdrp = (aurp_hdr_t *)gbuf_rptr(m); 89 hdrp->connection_id = state->rcv_connection_id; 90 hdrp->sequence_number = 0; 91 hdrp->command_code = AURPCMD_ZReq; 92 hdrp->flags = 0; 93 *(short *)(hdrp+1) = AURPSUBCODE_ZoneInfo1; 94 gbuf_winc(m,sizeof(short)); 95 96 net = (short *)gbuf_wptr(m); 97 nets_cnt = 0; 98 99 while (entry_num < RT_maxentry) { 100 /* 101 * scan the router table, and build the ZI request packet 102 * with the right entries, i.e., 103 * - entry in use and not of the net_port 104 * - with no zones and in an active state 105 * - talking to the right router 106 */ 107 if ( (entry->NetPort == net_port) && entry->NetStop && 108 ((entry->EntryState & 0x0F) >= RTE_STATE_SUSPECT) && 109 (!RT_ALL_ZONES_KNOWN(entry)) ) { 110 *net++ = (entry->NetStart) ? entry->NetStart : entry->NetStop; 111 nets_cnt++; 112 } 113 114 if (nets_cnt >= 640) { 115 /* query only 640 networks per packet */ 116 dPrintf(D_M_AURP, D_L_INFO, ("AURPsndZReq: node=%d\n", 117 state->rem_node)); 118 gbuf_winc(m,(nets_cnt * sizeof(short))); 119 AURPsend(m, AUD_AURP, state->rem_node); 120 net_sent = 1; 121 goto l_more; 122 } 123 124 entry_num++; 125 entry++; 126 } 127 128 if (nets_cnt) { 129 dPrintf(D_M_AURP, D_L_INFO, ("AURPsndZReq: node=%d\n", 130 state->rem_node)); 131 gbuf_winc(m,(nets_cnt * sizeof(short))); 132 AURPsend(m, AUD_AURP, state->rem_node); 133 net_sent = 1; 134 } else 135 gbuf_freeb(m); 136 137 if (!net_sent) 138 state->get_zi = 0; 139} 140 141/* */ 142void AURPsndZRsp(state, dat_m, flag) 143 aurp_state_t *state; 144 gbuf_t *dat_m; 145 int flag; 146{ 147 short len; 148 int msize, next_entry = 0; 149 gbuf_t *m; 150 aurp_hdr_t *hdrp; 151 152 if ((state->snd_state == AURPSTATE_Unconnected) || (dat_m == 0)) 153 return; 154 msize = sizeof(aurp_hdr_t); 155 156 do { 157 if ((m = (gbuf_t *)gbuf_alloc(msize+AURP_MaxPktSize, PRI_MED)) == 0) { 158 dPrintf(D_M_AURP, D_L_WARNING, ("AURPsndZRsp: node=%d, out of mblk\n", 159 state->rem_node)); 160 return; 161 } 162 gbuf_wset(m,msize); 163 164 /* construct the ZI response packet */ 165 hdrp = (aurp_hdr_t *)gbuf_rptr(m); 166 hdrp->connection_id = state->snd_connection_id; 167 hdrp->sequence_number = 0; 168 hdrp->command_code = AURPCMD_ZRsp; 169 hdrp->flags = 0; 170 171 /* get zone info of the local networks */ 172 next_entry = AURPgetzi(next_entry, gbuf_wptr(m), &len, dat_m, flag); 173 gbuf_winc(m,len); 174 175 /* send the packet */ 176 dPrintf(D_M_AURP, D_L_INFO, ("AURPsndZRsp: len=%d\n", len)); 177 AURPsend(m, AUD_AURP, state->rem_node); 178 179 } while (next_entry); 180 181 gbuf_freem(dat_m); 182} 183 184/* */ 185void AURPsndGZN(state, dat_m) 186 aurp_state_t *state; 187 gbuf_t *dat_m; 188{ 189 short zname_len; 190 int msize; 191 gbuf_t *m; 192 aurp_hdr_t *hdrp; 193 194 if (state->snd_state == AURPSTATE_Unconnected) 195 return; 196 197 msize = sizeof(aurp_hdr_t); 198 if ((m = (gbuf_t *)gbuf_alloc(msize+AURP_MaxPktSize, PRI_MED)) == 0) { 199 dPrintf(D_M_AURP, D_L_WARNING, ("AURPsndGZN: node=%d, out of mblk\n", 200 state->rem_node)); 201 return; 202 } 203 gbuf_wset(m,msize); 204 205 /* construct the GZN response packet */ 206 hdrp = (aurp_hdr_t *)gbuf_rptr(m); 207 hdrp->connection_id = state->snd_connection_id; 208 hdrp->sequence_number = 0; 209 hdrp->command_code = AURPCMD_ZRsp; 210 hdrp->flags = 0; 211 *(short *)(gbuf_wptr(m)) = AURPSUBCODE_GetZoneNets; 212 gbuf_winc(m,sizeof(short)); 213 zname_len = gbuf_len(dat_m); 214 bcopy(gbuf_rptr(dat_m), gbuf_wptr(m), zname_len); 215 gbuf_winc(m,zname_len); 216 *(short *)(gbuf_wptr(m)) = -1; /* number of tuples - proto not supported */ 217 gbuf_winc(m,sizeof(short)); 218 219 /* send the packet */ 220 dPrintf(D_M_AURP, D_L_INFO, ("AURPsndGZN: count=%d\n", -1)); 221 AURPsend(m, AUD_AURP, state->rem_node); 222} 223 224/* */ 225void AURPsndGDZL(state, dat_m) 226 aurp_state_t *state; 227 gbuf_t *dat_m; 228{ 229 int msize; 230 gbuf_t *m; 231 aurp_hdr_t *hdrp; 232 233 if (state->snd_state == AURPSTATE_Unconnected) 234 return; 235 236 msize = sizeof(aurp_hdr_t); 237 if ((m = (gbuf_t *)gbuf_alloc(msize+AURP_MaxPktSize, PRI_MED)) == 0) { 238 dPrintf(D_M_AURP, D_L_WARNING, ("AURPsndGDZL: node=%d, out of mblk\n", 239 state->rem_node)); 240 return; 241 } 242 gbuf_wset(m,msize); 243 244 /* construct the GDZL response packet */ 245 hdrp = (aurp_hdr_t *)gbuf_rptr(m); 246 hdrp->connection_id = state->snd_connection_id; 247 hdrp->sequence_number = 0; 248 hdrp->command_code = AURPCMD_ZRsp; 249 hdrp->flags = 0; 250 *(short *)(gbuf_wptr(m)) = AURPSUBCODE_GetDomainZoneList; 251 gbuf_winc(m,sizeof(short)); 252 *(short *)(gbuf_wptr(m)) = -1; /* start index - proto not supported */ 253 gbuf_winc(m,sizeof(short)); 254 255 /* send the packet */ 256 dPrintf(D_M_AURP, D_L_INFO, ("AURPsndGDZL: index=%d\n", -1)); 257 AURPsend(m, AUD_AURP, state->rem_node); 258} 259 260/* */ 261void AURPrcvZReq(state, m) 262 aurp_state_t *state; 263 gbuf_t *m; 264{ 265 short sub_code; 266 aurp_hdr_t *hdrp = (aurp_hdr_t *)gbuf_rptr(m); 267 268 /* make sure we're in a valid state to accept it */ 269 if (state->snd_state == AURPSTATE_Unconnected) { 270 dPrintf(D_M_AURP, D_L_WARNING, ("AURPrcvZReq: unexpected response\n")); 271 gbuf_freem(m); 272 return; 273 } 274 275 /* check for the correct connection id */ 276 if (hdrp->connection_id != state->snd_connection_id) { 277 dPrintf(D_M_AURP, D_L_WARNING, 278 ("AURPrcvZReq: invalid connection id, r=%d, m=%d\n", 279 hdrp->connection_id, state->snd_connection_id)); 280 gbuf_freem(m); 281 return; 282 } 283 284 gbuf_rinc(m,sizeof(*hdrp)); 285 sub_code = *(short *)gbuf_rptr(m); 286 gbuf_rinc(m,sizeof(short)); 287 288 dPrintf(D_M_AURP, D_L_INFO, ("AURPrcvZReq: len=%ld\n", gbuf_len(m))); 289 290 switch (sub_code) { 291 case AURPSUBCODE_ZoneInfo1: 292 AURPsndZRsp(state, m, 0); 293 return; 294 295 case AURPSUBCODE_GetZoneNets: 296 AURPsndGZN(state, m); 297 break; 298 299 case AURPSUBCODE_GetDomainZoneList: 300 AURPsndGDZL(state, m); 301 break; 302 } 303 304 gbuf_freem(m); 305} 306 307/* */ 308void AURPrcvZRsp(state, m) 309 aurp_state_t *state; 310 gbuf_t *m; 311{ 312 short sub_code, tuples_cnt; 313 aurp_hdr_t *hdrp = (aurp_hdr_t *)gbuf_rptr(m); 314 315 /* make sure we're in a valid state to accept it */ 316 if (state->rcv_state == AURPSTATE_Unconnected) { 317 dPrintf(D_M_AURP, D_L_WARNING, ("AURPrcvZRsp: unexpected response\n")); 318 gbuf_freem(m); 319 return; 320 } 321 322 /* check for the correct connection id */ 323 if (hdrp->connection_id != state->rcv_connection_id) { 324 dPrintf(D_M_AURP, D_L_WARNING, 325 ("AURPrcvZRsp: invalid connection id, r=%d, m=%d\n", 326 hdrp->connection_id, state->rcv_connection_id)); 327 gbuf_freem(m); 328 return; 329 } 330 331 gbuf_rinc(m,sizeof(*hdrp)); 332 sub_code = *(short *)gbuf_rptr(m); 333 gbuf_rinc(m,sizeof(short)); 334 335 dPrintf(D_M_AURP, D_L_INFO, ("AURPrcvZRsp: len=%ld\n", gbuf_len(m))); 336 337 switch (sub_code) { 338 case AURPSUBCODE_ZoneInfo1: 339 case AURPSUBCODE_ZoneInfo2: 340 tuples_cnt = *(short *)gbuf_rptr(m); 341 gbuf_rinc(m,sizeof(short)); 342 AURPsetzi(state->rem_node, m, sub_code, tuples_cnt); 343 break; 344 345 case AURPSUBCODE_GetZoneNets: 346 break; 347 348 case AURPSUBCODE_GetDomainZoneList: 349 break; 350 } 351 352 gbuf_freem(m); 353} 354 355/* */ 356static int 357AURPgetzi(next_entry, buf, len, dat_m, flag) 358 int next_entry; 359 unsigned char *buf; 360 short *len; 361 gbuf_t *dat_m; 362 int flag; 363{ 364 static int i_sav=ZT_BYTES-1, j_sav=0, idx_sav=-1; 365 unsigned char ev, zname_len, *zmap, *zname_base, *zname_sav, *tuples_ptr; 366 unsigned short net_num, *net, zname_offset; 367 short *sub_codep, *tuples_cntp, tuples_cnt, dat_len; 368 int i, j, idx, nets_cnt; 369 RT_entry *entry; 370 371 /* 372 * XXX CHS June-98: The compiler complains that some of these 373 * XXX variables may be used before they're set. I don't think 374 * XXX that's actually the case, but to check, I'll assign them 375 * XXX with some test value, and add asserts to check them at 376 * XXX run-time. The asserts won't be compiled in for production. 377 */ 378 zname_sav = tuples_ptr = (unsigned char *) 0xdeadbeef; /* XXX */ 379 net = (unsigned short *) 0xdeadbeef; /* XXX */ 380 net_num = 0xdead; /* XXX */ 381 nets_cnt = 0xfeedface; /* XXX */ 382 383 sub_codep = (short *)buf; 384 buf += sizeof(short); 385 tuples_cntp = (short *)buf; 386 buf += sizeof(short); 387 *len = sizeof(short) + sizeof(short); 388 zname_base = buf + sizeof(short); 389 dat_len = 0; 390 391 /* set the subcode in the ZI response packet */ 392 *sub_codep = next_entry ? AURPSUBCODE_ZoneInfo2 : AURPSUBCODE_ZoneInfo1; 393 394 switch (flag) { 395 case 0: /* zone info in response to ZI request */ 396 net = (unsigned short *)gbuf_rptr(dat_m); 397 nets_cnt = (gbuf_len(dat_m))/2; 398 break; 399 case 1: /* zone info in response to Ack of RI response */ 400 tuples_ptr = gbuf_rptr(dat_m); 401 nets_cnt = (gbuf_len(dat_m))/3; 402 next_entry = 0; 403 break; 404 case 2: /* zone info in response to Ack of RI update */ 405 tuples_ptr = gbuf_rptr(dat_m); 406 nets_cnt = (gbuf_len(dat_m))/4; 407 next_entry = 0; 408 break; 409 } 410 411 /* 412 * for each network, find all the zones that it belongs to 413 */ 414 assert(nets_cnt != 0xfeedface); /* XXX */ 415 for (tuples_cnt=0; next_entry < nets_cnt; next_entry++) { 416 switch(flag) { 417 case 0: 418 assert(net != 0xdeadbeef); /* XXX */ 419 net_num = net[next_entry]; 420 break; 421 case 1: 422 assert(tuples_ptr != 0xdeadbeef); /* XXX */ 423 net_num = *(unsigned short *)tuples_ptr; 424 tuples_ptr += 3; 425 gbuf_rinc(dat_m,3); 426 if (tuples_ptr[-1] & 0x80) { 427 tuples_ptr += 3; 428 gbuf_rinc(dat_m,3); 429 next_entry++; 430 } 431 break; 432 case 2: 433 if (gbuf_len(dat_m) <= 0) { 434 next_entry = nets_cnt; 435 goto l_done; 436 } 437 assert(tuples_ptr != 0xdeadbeef); /* XXX */ 438 ev = *tuples_ptr++; 439 net_num = *(unsigned short *)tuples_ptr; 440 tuples_ptr += 3; 441 gbuf_rinc(dat_m,4); 442 if (tuples_ptr[-1] & 0x80) { 443 tuples_ptr += 2; 444 gbuf_rinc(dat_m,2); 445 } 446 if (ev != AURPEV_NetAdded) 447 continue; 448 break; 449 } 450 451 /* 452 * find the RT entry associated with the network 453 */ 454 assert(net_num != 0xdead); /* XXX */ 455 if ((entry = rt_blookup(net_num)) == 0) { 456 dPrintf(D_M_AURP, D_L_WARNING, ("AURPgetzi: invalid net, %d\n", 457 net_num)); 458 continue; 459 } 460 if ( ((entry->EntryState & 0x0F) < RTE_STATE_SUSPECT) || 461 !RT_ALL_ZONES_KNOWN(entry) || 462 (entry->AURPFlag & AURP_NetHiden) ) { 463 dPrintf(D_M_AURP_LOW, D_L_INFO, ("AURPgetzi: zombie net, net=%d\n", 464 net_num)); 465 continue; 466 } 467 468 if (entry->NetStart == 0) { 469 if ((idx = zt_ent_zindex(entry->ZoneBitMap)) == 0) 470 continue; 471 idx--; /* index in the zone table */ 472 zname_len = ZT_table[idx].Zone.len; 473 if (zname_len) { 474 assert(net_num != 0xdead); /* XXX */ 475 *(unsigned short *)buf = net_num; 476 buf += sizeof(short); 477 if (idx == idx_sav) { 478 /* use the optimized format */ 479 assert(zname_sav != 0xdeadbeef); /* XXX */ 480 zname_offset = zname_sav - zname_base; 481 *(unsigned short *)buf = (0x8000 | zname_offset); 482 buf += sizeof(short); 483 dat_len += 4; 484 } else { 485 /* use the long format */ 486 zname_sav = buf; 487 *buf++ = zname_len; 488 bcopy(ZT_table[idx].Zone.str, buf, zname_len); 489 buf += zname_len; 490 dat_len += (3 + zname_len); 491 } 492 tuples_cnt++; 493 idx_sav = idx; 494 } 495 496 } else { 497 zmap = entry->ZoneBitMap; 498 for (i=i_sav; i >=0; i--) { 499 if (!zmap[i]) 500 continue; 501 502 for (j=j_sav; j < 8; j++) { 503 if (!((zmap[i] << j) & 0x80)) 504 continue; 505 506 idx = i*8 + j; /* index in the zone table */ 507 zname_len = ZT_table[idx].Zone.len; 508 if (zname_len) { 509 if ((dat_len+3+zname_len) > AURP_MaxPktSize) { 510 i_sav = i; 511 j_sav = j; 512 goto l_done; 513 } 514 515 assert(net_num != 0xdead); /* XXX */ 516 *(unsigned short *)buf = net_num; 517 buf += sizeof(short); 518 if (idx == idx_sav) { 519 /* use the optimized format */ 520 assert(zname_sav != 0xdeadbeef);/*XXX*/ 521 zname_offset = zname_sav - zname_base; 522 *(unsigned short *)buf = (0x8000 | zname_offset); 523 buf += sizeof(short); 524 dat_len += 4; 525 } else { 526 /* use the long format */ 527 zname_sav = buf; 528 *buf++ = zname_len; 529 bcopy(ZT_table[idx].Zone.str, buf, zname_len); 530 buf += zname_len; 531 dat_len += (3 + zname_len); 532 } 533 tuples_cnt++; 534 idx_sav = idx; 535 } 536 } 537 } 538 } 539 if ((dat_len+3+32) > AURP_MaxPktSize) { 540 next_entry++; 541 break; 542 } 543 } 544 i_sav = ZT_BYTES-1; 545 j_sav = 0; 546 547l_done: 548 *len += dat_len; 549 if (next_entry == nets_cnt) 550 next_entry = 0; 551 552 /* set the subcode in the ZI response packet */ 553 if (next_entry) 554 *sub_codep = AURPSUBCODE_ZoneInfo2; 555 556 /* set the tuples count in the ZI response packet */ 557 *tuples_cntp = tuples_cnt; 558 559 idx_sav = -1; 560 return next_entry; 561} 562 563/* */ 564static void 565AURPsetzi(node, m, sub_code, tuples_cnt) 566 unsigned char node; 567 gbuf_t *m; 568 short sub_code; 569 short tuples_cnt; 570{ 571 int rc, tuple_fmt; 572 unsigned short net_num, zname_offset; 573 unsigned char *buf = gbuf_rptr(m), *zname_base; 574 RT_entry *entry; 575 at_nvestr_t *zname; 576 577 /* compute the base of the zone names of the optimized tuples */ 578 zname_base = buf + sizeof(short); 579 580 /* process all tuples */ 581 while (tuples_cnt-- > 0) { 582 net_num = *(unsigned short *)buf; 583 buf += sizeof(short); 584 if (*buf & 0x80) { 585 /* optimized-format tuple */ 586 zname_offset = (*(unsigned short *)buf) & 0x7fff; 587 buf += sizeof(short); 588 zname = (at_nvestr_t *)(zname_base + zname_offset); 589 tuple_fmt = 0; 590 dPrintf(D_M_AURP_LOW, D_L_INFO, 591 ("AURPsetzi: optimized fmt, net=%d. zlen=%d, zoffset=%d\n ", 592 net_num, zname->len, zname_offset)); 593 } else { 594 /* long-format tuple */ 595 zname = (at_nvestr_t *)buf; 596 tuple_fmt = 1; 597 dPrintf(D_M_AURP_LOW, D_L_INFO, 598 ("AURPsetzi: long fmt, net=%d, zlen=%d\n ", 599 net_num, zname->len)); 600 } 601 602 /* 603 * find the RT entry associated with the specified network 604 */ 605 if ((entry = rt_blookup(net_num)) == 0) { 606 dPrintf(D_M_AURP, D_L_WARNING, 607 ("AURPsetzi: invalid net, net=%d\n", net_num)); 608 } else { /* entry found */ 609 if (entry->EntryState >= RTE_STATE_SUSPECT) { 610 if ((rc = zt_add_zonename(zname)) == ZT_MAXEDOUT) { 611 dPrintf(D_M_AURP, D_L_WARNING, 612 ("AURPsetzi: ZT_table full\n")); 613 } else { 614 zt_set_zmap(rc, entry->ZoneBitMap); 615 RT_SET_ZONE_KNOWN(entry); 616 } 617 } 618 } 619 if (tuple_fmt) 620 buf += zname->len+1; 621 } 622} 623 624#endif /* AURP_SUPPORT */ 625