1 /* 2 * ipxcp.c - PPP IPX Control Protocol. 3 * 4 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 18 * 3. The name "Carnegie Mellon University" must not be used to 19 * endorse or promote products derived from this software without 20 * prior written permission. For permission or any legal 21 * details, please contact 22 * Office of Technology Transfer 23 * Carnegie Mellon University 24 * 5000 Forbes Avenue 25 * Pittsburgh, PA 15213-3890 26 * (412) 268-4387, fax: (412) 268-7395 27 * tech-transfer (at) andrew.cmu.edu 28 * 29 * 4. Redistributions of any form whatsoever must retain the following 30 * acknowledgment: 31 * "This product includes software developed by Computing Services 32 * at Carnegie Mellon University (http://www.cmu.edu/computing/)." 33 * 34 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO 35 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 36 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 37 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 38 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 39 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 40 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 41 */ 42 43 #ifdef IPX_CHANGE 44 45 #define RCSID "$Id: ipxcp.c,v 1.23 2004/11/13 02:28:15 paulus Exp $" 46 47 /* 48 * TODO: 49 */ 50 51 #include <stdio.h> 52 #include <string.h> 53 #include <unistd.h> 54 #include <ctype.h> 55 #include <sys/types.h> 56 #include <sys/socket.h> 57 #include <netinet/in.h> 58 59 #include "pppd.h" 60 #include "fsm.h" 61 #include "ipxcp.h" 62 #include "pathnames.h" 63 #include "magic.h" 64 65 static const char rcsid[] = RCSID; 66 67 /* global vars */ 68 ipxcp_options ipxcp_wantoptions[NUM_PPP]; /* Options that we want to request */ 69 ipxcp_options ipxcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ 70 ipxcp_options ipxcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ 71 ipxcp_options ipxcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ 72 73 #define wo (&ipxcp_wantoptions[0]) 74 #define ao (&ipxcp_allowoptions[0]) 75 #define go (&ipxcp_gotoptions[0]) 76 #define ho (&ipxcp_hisoptions[0]) 77 78 /* 79 * Callbacks for fsm code. (CI = Configuration Information) 80 */ 81 static void ipxcp_resetci __P((fsm *)); /* Reset our CI */ 82 static int ipxcp_cilen __P((fsm *)); /* Return length of our CI */ 83 static void ipxcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */ 84 static int ipxcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */ 85 static int ipxcp_nakci __P((fsm *, u_char *, int, int));/* Peer nak'd our CI */ 86 static int ipxcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */ 87 static int ipxcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */ 88 static void ipxcp_up __P((fsm *)); /* We're UP */ 89 static void ipxcp_down __P((fsm *)); /* We're DOWN */ 90 static void ipxcp_finished __P((fsm *)); /* Don't need lower layer */ 91 static void ipxcp_script __P((fsm *, char *)); /* Run an up/down script */ 92 93 fsm ipxcp_fsm[NUM_PPP]; /* IPXCP fsm structure */ 94 95 static fsm_callbacks ipxcp_callbacks = { /* IPXCP callback routines */ 96 ipxcp_resetci, /* Reset our Configuration Information */ 97 ipxcp_cilen, /* Length of our Configuration Information */ 98 ipxcp_addci, /* Add our Configuration Information */ 99 ipxcp_ackci, /* ACK our Configuration Information */ 100 ipxcp_nakci, /* NAK our Configuration Information */ 101 ipxcp_rejci, /* Reject our Configuration Information */ 102 ipxcp_reqci, /* Request peer's Configuration Information */ 103 ipxcp_up, /* Called when fsm reaches OPENED state */ 104 ipxcp_down, /* Called when fsm leaves OPENED state */ 105 NULL, /* Called when we want the lower layer up */ 106 ipxcp_finished, /* Called when we want the lower layer down */ 107 NULL, /* Called when Protocol-Reject received */ 108 NULL, /* Retransmission is necessary */ 109 NULL, /* Called to handle protocol-specific codes */ 110 "IPXCP" /* String name of protocol */ 111 }; 112 113 /* 114 * Command-line options. 115 */ 116 static int setipxnode __P((char **)); 117 static void printipxnode __P((option_t *, 118 void (*)(void *, char *, ...), void *)); 119 static int setipxname __P((char **)); 120 121 static option_t ipxcp_option_list[] = { 122 { "ipx", o_bool, &ipxcp_protent.enabled_flag, 123 "Enable IPXCP (and IPX)", OPT_PRIO | 1 }, 124 { "+ipx", o_bool, &ipxcp_protent.enabled_flag, 125 "Enable IPXCP (and IPX)", OPT_PRIOSUB | OPT_ALIAS | 1 }, 126 { "noipx", o_bool, &ipxcp_protent.enabled_flag, 127 "Disable IPXCP (and IPX)", OPT_PRIOSUB }, 128 { "-ipx", o_bool, &ipxcp_protent.enabled_flag, 129 "Disable IPXCP (and IPX)", OPT_PRIOSUB | OPT_ALIAS }, 130 131 { "ipx-network", o_uint32, &ipxcp_wantoptions[0].our_network, 132 "Set our IPX network number", OPT_PRIO, &ipxcp_wantoptions[0].neg_nn }, 133 134 { "ipxcp-accept-network", o_bool, &ipxcp_wantoptions[0].accept_network, 135 "Accept peer IPX network number", 1, 136 &ipxcp_allowoptions[0].accept_network }, 137 138 { "ipx-node", o_special, (void *)setipxnode, 139 "Set IPX node number", OPT_A2PRINTER, (void *)printipxnode }, 140 141 { "ipxcp-accept-local", o_bool, &ipxcp_wantoptions[0].accept_local, 142 "Accept our IPX address", 1, 143 &ipxcp_allowoptions[0].accept_local }, 144 145 { "ipxcp-accept-remote", o_bool, &ipxcp_wantoptions[0].accept_remote, 146 "Accept peer's IPX address", 1, 147 &ipxcp_allowoptions[0].accept_remote }, 148 149 { "ipx-routing", o_int, &ipxcp_wantoptions[0].router, 150 "Set IPX routing proto number", OPT_PRIO, 151 &ipxcp_wantoptions[0].neg_router }, 152 153 { "ipx-router-name", o_special, setipxname, 154 "Set IPX router name", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, 155 &ipxcp_wantoptions[0].name }, 156 157 { "ipxcp-restart", o_int, &ipxcp_fsm[0].timeouttime, 158 "Set timeout for IPXCP", OPT_PRIO }, 159 { "ipxcp-max-terminate", o_int, &ipxcp_fsm[0].maxtermtransmits, 160 "Set max #xmits for IPXCP term-reqs", OPT_PRIO }, 161 { "ipxcp-max-configure", o_int, &ipxcp_fsm[0].maxconfreqtransmits, 162 "Set max #xmits for IPXCP conf-reqs", OPT_PRIO }, 163 { "ipxcp-max-failure", o_int, &ipxcp_fsm[0].maxnakloops, 164 "Set max #conf-naks for IPXCP", OPT_PRIO }, 165 166 { NULL } 167 }; 168 169 /* 170 * Protocol entry points. 171 */ 172 173 static void ipxcp_init __P((int)); 174 static void ipxcp_open __P((int)); 175 static void ipxcp_close __P((int, char *)); 176 static void ipxcp_lowerup __P((int)); 177 static void ipxcp_lowerdown __P((int)); 178 static void ipxcp_input __P((int, u_char *, int)); 179 static void ipxcp_protrej __P((int)); 180 static int ipxcp_printpkt __P((u_char *, int, 181 void (*) __P((void *, char *, ...)), void *)); 182 183 struct protent ipxcp_protent = { 184 PPP_IPXCP, 185 ipxcp_init, 186 ipxcp_input, 187 ipxcp_protrej, 188 ipxcp_lowerup, 189 ipxcp_lowerdown, 190 ipxcp_open, 191 ipxcp_close, 192 ipxcp_printpkt, 193 NULL, 194 0, 195 "IPXCP", 196 "IPX", 197 ipxcp_option_list, 198 NULL, 199 NULL, 200 NULL 201 }; 202 203 /* 204 * Lengths of configuration options. 205 */ 206 207 #define CILEN_VOID 2 208 #define CILEN_COMPLETE 2 /* length of complete option */ 209 #define CILEN_NETN 6 /* network number length option */ 210 #define CILEN_NODEN 8 /* node number length option */ 211 #define CILEN_PROTOCOL 4 /* Minimum length of routing protocol */ 212 #define CILEN_NAME 3 /* Minimum length of router name */ 213 #define CILEN_COMPRESS 4 /* Minimum length of compression protocol */ 214 215 #define CODENAME(x) ((x) == CONFACK ? "ACK" : \ 216 (x) == CONFNAK ? "NAK" : "REJ") 217 218 static int ipxcp_is_up; 219 220 static char *ipx_ntoa __P((u_int32_t)); 221 222 /* Used in printing the node number */ 223 #define NODE(base) base[0], base[1], base[2], base[3], base[4], base[5] 224 225 /* Used to generate the proper bit mask */ 226 #define BIT(num) (1 << (num)) 227 228 /* 229 * Convert from internal to external notation 230 */ 231 232 static short int 233 to_external(internal) 234 short int internal; 235 { 236 short int external; 237 238 if (internal & BIT(IPX_NONE) ) 239 external = IPX_NONE; 240 else 241 external = RIP_SAP; 242 243 return external; 244 } 245 246 /* 247 * Make a string representation of a network IP address. 248 */ 249 250 static char * 251 ipx_ntoa(ipxaddr) 252 u_int32_t ipxaddr; 253 { 254 static char b[64]; 255 slprintf(b, sizeof(b), "%x", ipxaddr); 256 return b; 257 } 258 259 260 static u_char * 261 setipxnodevalue(src,dst) 262 u_char *src, *dst; 263 { 264 int indx; 265 int item; 266 267 for (;;) { 268 if (!isxdigit (*src)) 269 break; 270 271 for (indx = 0; indx < 5; ++indx) { 272 dst[indx] <<= 4; 273 dst[indx] |= (dst[indx + 1] >> 4) & 0x0F; 274 } 275 276 item = toupper (*src) - '0'; 277 if (item > 9) 278 item -= 7; 279 280 dst[5] = (dst[5] << 4) | item; 281 ++src; 282 } 283 return src; 284 } 285 286 static int ipx_prio_our, ipx_prio_his; 287 288 static int 289 setipxnode(argv) 290 char **argv; 291 { 292 char *end; 293 int have_his = 0; 294 u_char our_node[6]; 295 u_char his_node[6]; 296 297 memset (our_node, 0, 6); 298 memset (his_node, 0, 6); 299 300 end = setipxnodevalue (*argv, our_node); 301 if (*end == ':') { 302 have_his = 1; 303 end = setipxnodevalue (++end, his_node); 304 } 305 306 if (*end == '\0') { 307 ipxcp_wantoptions[0].neg_node = 1; 308 if (option_priority >= ipx_prio_our) { 309 memcpy(&ipxcp_wantoptions[0].our_node[0], our_node, 6); 310 ipx_prio_our = option_priority; 311 } 312 if (have_his && option_priority >= ipx_prio_his) { 313 memcpy(&ipxcp_wantoptions[0].his_node[0], his_node, 6); 314 ipx_prio_his = option_priority; 315 } 316 return 1; 317 } 318 319 option_error("invalid parameter '%s' for ipx-node option", *argv); 320 return 0; 321 } 322 323 static void 324 printipxnode(opt, printer, arg) 325 option_t *opt; 326 void (*printer) __P((void *, char *, ...)); 327 void *arg; 328 { 329 unsigned char *p; 330 331 p = ipxcp_wantoptions[0].our_node; 332 if (ipx_prio_our) 333 printer(arg, "%.2x%.2x%.2x%.2x%.2x%.2x", 334 p[0], p[1], p[2], p[3], p[4], p[5]); 335 printer(arg, ":"); 336 p = ipxcp_wantoptions[0].his_node; 337 if (ipx_prio_his) 338 printer(arg, "%.2x%.2x%.2x%.2x%.2x%.2x", 339 p[0], p[1], p[2], p[3], p[4], p[5]); 340 } 341 342 static int 343 setipxname (argv) 344 char **argv; 345 { 346 char *dest = ipxcp_wantoptions[0].name; 347 char *src = *argv; 348 int count; 349 char ch; 350 351 ipxcp_wantoptions[0].neg_name = 1; 352 ipxcp_allowoptions[0].neg_name = 1; 353 memset (dest, '\0', sizeof (ipxcp_wantoptions[0].name)); 354 355 count = 0; 356 while (*src) { 357 ch = *src++; 358 if (! isalnum (ch) && ch != '_') { 359 option_error("IPX router name must be alphanumeric or _"); 360 return 0; 361 } 362 363 if (count >= sizeof (ipxcp_wantoptions[0].name) - 1) { 364 option_error("IPX router name is limited to %d characters", 365 sizeof (ipxcp_wantoptions[0].name) - 1); 366 return 0; 367 } 368 369 dest[count++] = toupper (ch); 370 } 371 dest[count] = 0; 372 373 return 1; 374 } 375 376 /* 377 * ipxcp_init - Initialize IPXCP. 378 */ 379 static void 380 ipxcp_init(unit) 381 int unit; 382 { 383 fsm *f = &ipxcp_fsm[unit]; 384 385 f->unit = unit; 386 f->protocol = PPP_IPXCP; 387 f->callbacks = &ipxcp_callbacks; 388 fsm_init(&ipxcp_fsm[unit]); 389 390 memset (wo->name, 0, sizeof (wo->name)); 391 memset (wo->our_node, 0, sizeof (wo->our_node)); 392 memset (wo->his_node, 0, sizeof (wo->his_node)); 393 394 wo->neg_nn = 1; 395 wo->neg_complete = 1; 396 wo->network = 0; 397 398 ao->neg_node = 1; 399 ao->neg_nn = 1; 400 ao->neg_name = 1; 401 ao->neg_complete = 1; 402 ao->neg_router = 1; 403 404 ao->accept_local = 0; 405 ao->accept_remote = 0; 406 ao->accept_network = 0; 407 408 wo->tried_rip = 0; 409 wo->tried_nlsp = 0; 410 } 411 412 /* 413 * Copy the node number 414 */ 415 416 static void 417 copy_node (src, dst) 418 u_char *src, *dst; 419 { 420 memcpy (dst, src, sizeof (ipxcp_wantoptions[0].our_node)); 421 } 422 423 /* 424 * Compare node numbers 425 */ 426 427 static int 428 compare_node (src, dst) 429 u_char *src, *dst; 430 { 431 return memcmp (dst, src, sizeof (ipxcp_wantoptions[0].our_node)) == 0; 432 } 433 434 /* 435 * Is the node number zero? 436 */ 437 438 static int 439 zero_node (node) 440 u_char *node; 441 { 442 int indx; 443 for (indx = 0; indx < sizeof (ipxcp_wantoptions[0].our_node); ++indx) 444 if (node [indx] != 0) 445 return 0; 446 return 1; 447 } 448 449 /* 450 * Increment the node number 451 */ 452 453 static void 454 inc_node (node) 455 u_char *node; 456 { 457 u_char *outp; 458 u_int32_t magic_num; 459 460 outp = node; 461 magic_num = magic(); 462 *outp++ = '\0'; 463 *outp++ = '\0'; 464 PUTLONG (magic_num, outp); 465 } 466 467 /* 468 * ipxcp_open - IPXCP is allowed to come up. 469 */ 470 static void 471 ipxcp_open(unit) 472 int unit; 473 { 474 fsm_open(&ipxcp_fsm[unit]); 475 } 476 477 /* 478 * ipxcp_close - Take IPXCP down. 479 */ 480 static void 481 ipxcp_close(unit, reason) 482 int unit; 483 char *reason; 484 { 485 fsm_close(&ipxcp_fsm[unit], reason); 486 } 487 488 489 /* 490 * ipxcp_lowerup - The lower layer is up. 491 */ 492 static void 493 ipxcp_lowerup(unit) 494 int unit; 495 { 496 fsm_lowerup(&ipxcp_fsm[unit]); 497 } 498 499 500 /* 501 * ipxcp_lowerdown - The lower layer is down. 502 */ 503 static void 504 ipxcp_lowerdown(unit) 505 int unit; 506 { 507 fsm_lowerdown(&ipxcp_fsm[unit]); 508 } 509 510 511 /* 512 * ipxcp_input - Input IPXCP packet. 513 */ 514 static void 515 ipxcp_input(unit, p, len) 516 int unit; 517 u_char *p; 518 int len; 519 { 520 fsm_input(&ipxcp_fsm[unit], p, len); 521 } 522 523 524 /* 525 * ipxcp_protrej - A Protocol-Reject was received for IPXCP. 526 * 527 * Pretend the lower layer went down, so we shut up. 528 */ 529 static void 530 ipxcp_protrej(unit) 531 int unit; 532 { 533 fsm_lowerdown(&ipxcp_fsm[unit]); 534 } 535 536 537 /* 538 * ipxcp_resetci - Reset our CI. 539 */ 540 static void 541 ipxcp_resetci(f) 542 fsm *f; 543 { 544 wo->req_node = wo->neg_node && ao->neg_node; 545 wo->req_nn = wo->neg_nn && ao->neg_nn; 546 547 if (wo->our_network == 0) { 548 wo->neg_node = 1; 549 ao->accept_network = 1; 550 } 551 /* 552 * If our node number is zero then change it. 553 */ 554 if (zero_node (wo->our_node)) { 555 inc_node (wo->our_node); 556 ao->accept_local = 1; 557 wo->neg_node = 1; 558 } 559 /* 560 * If his node number is zero then change it. 561 */ 562 if (zero_node (wo->his_node)) { 563 inc_node (wo->his_node); 564 ao->accept_remote = 1; 565 } 566 /* 567 * If no routing agent was specified then we do RIP/SAP according to the 568 * RFC documents. If you have specified something then OK. Otherwise, we 569 * do RIP/SAP. 570 */ 571 if (ao->router == 0) { 572 ao->router |= BIT(RIP_SAP); 573 wo->router |= BIT(RIP_SAP); 574 } 575 576 /* Always specify a routing protocol unless it was REJected. */ 577 wo->neg_router = 1; 578 /* 579 * Start with these default values 580 */ 581 *go = *wo; 582 } 583 584 /* 585 * ipxcp_cilen - Return length of our CI. 586 */ 587 588 static int 589 ipxcp_cilen(f) 590 fsm *f; 591 { 592 int len; 593 594 len = go->neg_nn ? CILEN_NETN : 0; 595 len += go->neg_node ? CILEN_NODEN : 0; 596 len += go->neg_name ? CILEN_NAME + strlen (go->name) - 1 : 0; 597 598 /* RFC says that defaults should not be included. */ 599 if (go->neg_router && to_external(go->router) != RIP_SAP) 600 len += CILEN_PROTOCOL; 601 602 return (len); 603 } 604 605 606 /* 607 * ipxcp_addci - Add our desired CIs to a packet. 608 */ 609 static void 610 ipxcp_addci(f, ucp, lenp) 611 fsm *f; 612 u_char *ucp; 613 int *lenp; 614 { 615 /* 616 * Add the options to the record. 617 */ 618 if (go->neg_nn) { 619 PUTCHAR (IPX_NETWORK_NUMBER, ucp); 620 PUTCHAR (CILEN_NETN, ucp); 621 PUTLONG (go->our_network, ucp); 622 } 623 624 if (go->neg_node) { 625 int indx; 626 PUTCHAR (IPX_NODE_NUMBER, ucp); 627 PUTCHAR (CILEN_NODEN, ucp); 628 for (indx = 0; indx < sizeof (go->our_node); ++indx) 629 PUTCHAR (go->our_node[indx], ucp); 630 } 631 632 if (go->neg_name) { 633 int cilen = strlen (go->name); 634 int indx; 635 PUTCHAR (IPX_ROUTER_NAME, ucp); 636 PUTCHAR (CILEN_NAME + cilen - 1, ucp); 637 for (indx = 0; indx < cilen; ++indx) 638 PUTCHAR (go->name [indx], ucp); 639 } 640 641 if (go->neg_router) { 642 short external = to_external (go->router); 643 if (external != RIP_SAP) { 644 PUTCHAR (IPX_ROUTER_PROTOCOL, ucp); 645 PUTCHAR (CILEN_PROTOCOL, ucp); 646 PUTSHORT (external, ucp); 647 } 648 } 649 } 650 651 /* 652 * ipxcp_ackci - Ack our CIs. 653 * 654 * Returns: 655 * 0 - Ack was bad. 656 * 1 - Ack was good. 657 */ 658 static int 659 ipxcp_ackci(f, p, len) 660 fsm *f; 661 u_char *p; 662 int len; 663 { 664 u_short cilen, citype, cishort; 665 u_char cichar; 666 u_int32_t cilong; 667 668 #define ACKCIVOID(opt, neg) \ 669 if (neg) { \ 670 if ((len -= CILEN_VOID) < 0) \ 671 break; \ 672 GETCHAR(citype, p); \ 673 GETCHAR(cilen, p); \ 674 if (cilen != CILEN_VOID || \ 675 citype != opt) \ 676 break; \ 677 } 678 679 #define ACKCICOMPLETE(opt,neg) ACKCIVOID(opt, neg) 680 681 #define ACKCICHARS(opt, neg, val, cnt) \ 682 if (neg) { \ 683 int indx, count = cnt; \ 684 len -= (count + 2); \ 685 if (len < 0) \ 686 break; \ 687 GETCHAR(citype, p); \ 688 GETCHAR(cilen, p); \ 689 if (cilen != (count + 2) || \ 690 citype != opt) \ 691 break; \ 692 for (indx = 0; indx < count; ++indx) {\ 693 GETCHAR(cichar, p); \ 694 if (cichar != ((u_char *) &val)[indx]) \ 695 break; \ 696 }\ 697 if (indx != count) \ 698 break; \ 699 } 700 701 #define ACKCINODE(opt,neg,val) ACKCICHARS(opt,neg,val,sizeof(val)) 702 #define ACKCINAME(opt,neg,val) ACKCICHARS(opt,neg,val,strlen(val)) 703 704 #define ACKCINETWORK(opt, neg, val) \ 705 if (neg) { \ 706 if ((len -= CILEN_NETN) < 0) \ 707 break; \ 708 GETCHAR(citype, p); \ 709 GETCHAR(cilen, p); \ 710 if (cilen != CILEN_NETN || \ 711 citype != opt) \ 712 break; \ 713 GETLONG(cilong, p); \ 714 if (cilong != val) \ 715 break; \ 716 } 717 718 #define ACKCIPROTO(opt, neg, val) \ 719 if (neg) { \ 720 if (len < 2) \ 721 break; \ 722 GETCHAR(citype, p); \ 723 GETCHAR(cilen, p); \ 724 if (cilen != CILEN_PROTOCOL || citype != opt) \ 725 break; \ 726 len -= cilen; \ 727 if (len < 0) \ 728 break; \ 729 GETSHORT(cishort, p); \ 730 if (cishort != to_external (val) || cishort == RIP_SAP) \ 731 break; \ 732 } 733 /* 734 * Process the ACK frame in the order in which the frame was assembled 735 */ 736 do { 737 ACKCINETWORK (IPX_NETWORK_NUMBER, go->neg_nn, go->our_network); 738 ACKCINODE (IPX_NODE_NUMBER, go->neg_node, go->our_node); 739 ACKCINAME (IPX_ROUTER_NAME, go->neg_name, go->name); 740 if (len > 0) 741 ACKCIPROTO (IPX_ROUTER_PROTOCOL, go->neg_router, go->router); 742 /* 743 * This is the end of the record. 744 */ 745 if (len == 0) 746 return (1); 747 } while (0); 748 /* 749 * The frame is invalid 750 */ 751 IPXCPDEBUG(("ipxcp_ackci: received bad Ack!")); 752 return (0); 753 } 754 755 /* 756 * ipxcp_nakci - Peer has sent a NAK for some of our CIs. 757 * This should not modify any state if the Nak is bad 758 * or if IPXCP is in the OPENED state. 759 * 760 * Returns: 761 * 0 - Nak was bad. 762 * 1 - Nak was good. 763 */ 764 765 static int 766 ipxcp_nakci(f, p, len, treat_as_reject) 767 fsm *f; 768 u_char *p; 769 int len; 770 int treat_as_reject; 771 { 772 u_char citype, cilen, *next; 773 u_short s; 774 u_int32_t l; 775 ipxcp_options no; /* options we've seen Naks for */ 776 ipxcp_options try; /* options to request next time */ 777 778 BZERO(&no, sizeof(no)); 779 try = *go; 780 781 while (len >= CILEN_VOID) { 782 GETCHAR (citype, p); 783 GETCHAR (cilen, p); 784 len -= cilen; 785 if (cilen < CILEN_VOID || len < 0) 786 goto bad; 787 next = &p [cilen - CILEN_VOID]; 788 789 switch (citype) { 790 case IPX_NETWORK_NUMBER: 791 if (!go->neg_nn || no.neg_nn || (cilen != CILEN_NETN)) 792 goto bad; 793 no.neg_nn = 1; 794 795 GETLONG(l, p); 796 if (treat_as_reject) 797 try.neg_nn = 0; 798 else if (l && ao->accept_network) 799 try.our_network = l; 800 break; 801 802 case IPX_NODE_NUMBER: 803 if (!go->neg_node || no.neg_node || (cilen != CILEN_NODEN)) 804 goto bad; 805 no.neg_node = 1; 806 807 if (treat_as_reject) 808 try.neg_node = 0; 809 else if (!zero_node (p) && ao->accept_local && 810 ! compare_node (p, ho->his_node)) 811 copy_node (p, try.our_node); 812 break; 813 814 /* This has never been sent. Ignore the NAK frame */ 815 case IPX_COMPRESSION_PROTOCOL: 816 goto bad; 817 818 case IPX_ROUTER_PROTOCOL: 819 if (!go->neg_router || (cilen < CILEN_PROTOCOL)) 820 goto bad; 821 822 GETSHORT (s, p); 823 if (s > 15) /* This is just bad, but ignore for now. */ 824 break; 825 826 s = BIT(s); 827 if (no.router & s) /* duplicate NAKs are always bad */ 828 goto bad; 829 830 if (no.router == 0) /* Reset on first NAK only */ 831 try.router = 0; 832 833 no.router |= s; 834 try.router |= s; 835 try.neg_router = 1; 836 break; 837 838 /* These, according to the RFC, must never be NAKed. */ 839 case IPX_ROUTER_NAME: 840 case IPX_COMPLETE: 841 goto bad; 842 843 /* These are for options which we have not seen. */ 844 default: 845 break; 846 } 847 p = next; 848 } 849 850 /* 851 * Do not permit the peer to force a router protocol which we do not 852 * support. However, default to the condition that will accept "NONE". 853 */ 854 try.router &= (ao->router | BIT(IPX_NONE)); 855 if (try.router == 0 && ao->router != 0) 856 try.router = BIT(IPX_NONE); 857 858 if (try.router != 0) 859 try.neg_router = 1; 860 861 /* 862 * OK, the Nak is good. Now we can update state. 863 * If there are any options left, we ignore them. 864 */ 865 if (f->state != OPENED) 866 *go = try; 867 868 return 1; 869 870 bad: 871 IPXCPDEBUG(("ipxcp_nakci: received bad Nak!")); 872 return 0; 873 } 874 875 /* 876 * ipxcp_rejci - Reject some of our CIs. 877 */ 878 static int 879 ipxcp_rejci(f, p, len) 880 fsm *f; 881 u_char *p; 882 int len; 883 { 884 u_short cilen, citype, cishort; 885 u_char cichar; 886 u_int32_t cilong; 887 ipxcp_options try; /* options to request next time */ 888 889 #define REJCINETWORK(opt, neg, val) \ 890 if (neg && p[0] == opt) { \ 891 if ((len -= CILEN_NETN) < 0) \ 892 break; \ 893 GETCHAR(citype, p); \ 894 GETCHAR(cilen, p); \ 895 if (cilen != CILEN_NETN || \ 896 citype != opt) \ 897 break; \ 898 GETLONG(cilong, p); \ 899 if (cilong != val) \ 900 break; \ 901 neg = 0; \ 902 } 903 904 #define REJCICHARS(opt, neg, val, cnt) \ 905 if (neg && p[0] == opt) { \ 906 int indx, count = cnt; \ 907 len -= (count + 2); \ 908 if (len < 0) \ 909 break; \ 910 GETCHAR(citype, p); \ 911 GETCHAR(cilen, p); \ 912 if (cilen != (count + 2) || \ 913 citype != opt) \ 914 break; \ 915 for (indx = 0; indx < count; ++indx) {\ 916 GETCHAR(cichar, p); \ 917 if (cichar != ((u_char *) &val)[indx]) \ 918 break; \ 919 }\ 920 if (indx != count) \ 921 break; \ 922 neg = 0; \ 923 } 924 925 #define REJCINODE(opt,neg,val) REJCICHARS(opt,neg,val,sizeof(val)) 926 #define REJCINAME(opt,neg,val) REJCICHARS(opt,neg,val,strlen(val)) 927 928 #define REJCIVOID(opt, neg) \ 929 if (neg && p[0] == opt) { \ 930 if ((len -= CILEN_VOID) < 0) \ 931 break; \ 932 GETCHAR(citype, p); \ 933 GETCHAR(cilen, p); \ 934 if (cilen != CILEN_VOID || citype != opt) \ 935 break; \ 936 neg = 0; \ 937 } 938 939 /* a reject for RIP/SAP is invalid since we don't send it and you can't 940 reject something which is not sent. (You can NAK, but you can't REJ.) */ 941 #define REJCIPROTO(opt, neg, val, bit) \ 942 if (neg && p[0] == opt) { \ 943 if ((len -= CILEN_PROTOCOL) < 0) \ 944 break; \ 945 GETCHAR(citype, p); \ 946 GETCHAR(cilen, p); \ 947 if (cilen != CILEN_PROTOCOL) \ 948 break; \ 949 GETSHORT(cishort, p); \ 950 if (cishort != to_external (val) || cishort == RIP_SAP) \ 951 break; \ 952 neg = 0; \ 953 } 954 /* 955 * Any Rejected CIs must be in exactly the same order that we sent. 956 * Check packet length and CI length at each step. 957 * If we find any deviations, then this packet is bad. 958 */ 959 try = *go; 960 961 do { 962 REJCINETWORK (IPX_NETWORK_NUMBER, try.neg_nn, try.our_network); 963 REJCINODE (IPX_NODE_NUMBER, try.neg_node, try.our_node); 964 REJCINAME (IPX_ROUTER_NAME, try.neg_name, try.name); 965 REJCIPROTO (IPX_ROUTER_PROTOCOL, try.neg_router, try.router, 0); 966 /* 967 * This is the end of the record. 968 */ 969 if (len == 0) { 970 if (f->state != OPENED) 971 *go = try; 972 return (1); 973 } 974 } while (0); 975 /* 976 * The frame is invalid at this point. 977 */ 978 IPXCPDEBUG(("ipxcp_rejci: received bad Reject!")); 979 return 0; 980 } 981 982 /* 983 * ipxcp_reqci - Check the peer's requested CIs and send appropriate response. 984 * 985 * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified 986 * appropriately. If reject_if_disagree is non-zero, doesn't return 987 * CONFNAK; returns CONFREJ if it can't return CONFACK. 988 */ 989 static int 990 ipxcp_reqci(f, inp, len, reject_if_disagree) 991 fsm *f; 992 u_char *inp; /* Requested CIs */ 993 int *len; /* Length of requested CIs */ 994 int reject_if_disagree; 995 { 996 u_char *cip, *next; /* Pointer to current and next CIs */ 997 u_short cilen, citype; /* Parsed len, type */ 998 u_short cishort; /* Parsed short value */ 999 u_int32_t cinetwork; /* Parsed address values */ 1000 int rc = CONFACK; /* Final packet return code */ 1001 int orc; /* Individual option return code */ 1002 u_char *p; /* Pointer to next char to parse */ 1003 u_char *ucp = inp; /* Pointer to current output char */ 1004 int l = *len; /* Length left */ 1005 1006 /* 1007 * Reset all his options. 1008 */ 1009 BZERO(ho, sizeof(*ho)); 1010 1011 /* 1012 * Process all his options. 1013 */ 1014 next = inp; 1015 while (l) { 1016 orc = CONFACK; /* Assume success */ 1017 cip = p = next; /* Remember begining of CI */ 1018 if (l < 2 || /* Not enough data for CI header or */ 1019 p[1] < 2 || /* CI length too small or */ 1020 p[1] > l) { /* CI length too big? */ 1021 IPXCPDEBUG(("ipxcp_reqci: bad CI length!")); 1022 orc = CONFREJ; /* Reject bad CI */ 1023 cilen = l; /* Reject till end of packet */ 1024 l = 0; /* Don't loop again */ 1025 goto endswitch; 1026 } 1027 GETCHAR(citype, p); /* Parse CI type */ 1028 GETCHAR(cilen, p); /* Parse CI length */ 1029 l -= cilen; /* Adjust remaining length */ 1030 next += cilen; /* Step to next CI */ 1031 1032 switch (citype) { /* Check CI type */ 1033 /* 1034 * The network number must match. Choose the larger of the two. 1035 */ 1036 case IPX_NETWORK_NUMBER: 1037 /* if we wont negotiate the network number or the length is wrong 1038 then reject the option */ 1039 if ( !ao->neg_nn || cilen != CILEN_NETN ) { 1040 orc = CONFREJ; 1041 break; 1042 } 1043 GETLONG(cinetwork, p); 1044 1045 /* If the network numbers match then acknowledge them. */ 1046 if (cinetwork != 0) { 1047 ho->his_network = cinetwork; 1048 ho->neg_nn = 1; 1049 if (wo->our_network == cinetwork) 1050 break; 1051 /* 1052 * If the network number is not given or we don't accept their change or 1053 * the network number is too small then NAK it. 1054 */ 1055 if (! ao->accept_network || cinetwork < wo->our_network) { 1056 DECPTR (sizeof (u_int32_t), p); 1057 PUTLONG (wo->our_network, p); 1058 orc = CONFNAK; 1059 } 1060 break; 1061 } 1062 /* 1063 * The peer sent '0' for the network. Give it ours if we have one. 1064 */ 1065 if (go->our_network != 0) { 1066 DECPTR (sizeof (u_int32_t), p); 1067 PUTLONG (wo->our_network, p); 1068 orc = CONFNAK; 1069 /* 1070 * We don't have one. Reject the value. 1071 */ 1072 } else 1073 orc = CONFREJ; 1074 1075 break; 1076 /* 1077 * The node number is required 1078 */ 1079 case IPX_NODE_NUMBER: 1080 /* if we wont negotiate the node number or the length is wrong 1081 then reject the option */ 1082 if ( cilen != CILEN_NODEN ) { 1083 orc = CONFREJ; 1084 break; 1085 } 1086 1087 copy_node (p, ho->his_node); 1088 ho->neg_node = 1; 1089 /* 1090 * If the remote does not have a number and we do then NAK it with the value 1091 * which we have for it. (We never have a default value of zero.) 1092 */ 1093 if (zero_node (ho->his_node)) { 1094 orc = CONFNAK; 1095 copy_node (wo->his_node, p); 1096 INCPTR (sizeof (wo->his_node), p); 1097 break; 1098 } 1099 /* 1100 * If you have given me the expected network node number then I'll accept 1101 * it now. 1102 */ 1103 if (compare_node (wo->his_node, ho->his_node)) { 1104 orc = CONFACK; 1105 ho->neg_node = 1; 1106 INCPTR (sizeof (wo->his_node), p); 1107 break; 1108 } 1109 /* 1110 * If his node number is the same as ours then ask him to try the next 1111 * value. 1112 */ 1113 if (compare_node (ho->his_node, go->our_node)) { 1114 inc_node (ho->his_node); 1115 orc = CONFNAK; 1116 copy_node (ho->his_node, p); 1117 INCPTR (sizeof (wo->his_node), p); 1118 break; 1119 } 1120 /* 1121 * If we don't accept a new value then NAK it. 1122 */ 1123 if (! ao->accept_remote) { 1124 copy_node (wo->his_node, p); 1125 INCPTR (sizeof (wo->his_node), p); 1126 orc = CONFNAK; 1127 break; 1128 } 1129 orc = CONFACK; 1130 ho->neg_node = 1; 1131 INCPTR (sizeof (wo->his_node), p); 1132 break; 1133 /* 1134 * Compression is not desired at this time. It is always rejected. 1135 */ 1136 case IPX_COMPRESSION_PROTOCOL: 1137 orc = CONFREJ; 1138 break; 1139 /* 1140 * The routing protocol is a bitmask of various types. Any combination 1141 * of the values RIP_SAP and NLSP are permissible. 'IPX_NONE' for no 1142 * routing protocol must be specified only once. 1143 */ 1144 case IPX_ROUTER_PROTOCOL: 1145 if ( !ao->neg_router || cilen < CILEN_PROTOCOL ) { 1146 orc = CONFREJ; 1147 break; 1148 } 1149 1150 GETSHORT (cishort, p); 1151 1152 if (wo->neg_router == 0) { 1153 wo->neg_router = 1; 1154 wo->router = BIT(IPX_NONE); 1155 } 1156 1157 if ((cishort == IPX_NONE && ho->router != 0) || 1158 (ho->router & BIT(IPX_NONE))) { 1159 orc = CONFREJ; 1160 break; 1161 } 1162 1163 cishort = BIT(cishort); 1164 if (ho->router & cishort) { 1165 orc = CONFREJ; 1166 break; 1167 } 1168 1169 ho->router |= cishort; 1170 ho->neg_router = 1; 1171 1172 /* Finally do not allow a router protocol which we do not 1173 support. */ 1174 1175 if ((cishort & (ao->router | BIT(IPX_NONE))) == 0) { 1176 int protocol; 1177 1178 if (cishort == BIT(NLSP) && 1179 (ao->router & BIT(RIP_SAP)) && 1180 !wo->tried_rip) { 1181 protocol = RIP_SAP; 1182 wo->tried_rip = 1; 1183 } else 1184 protocol = IPX_NONE; 1185 1186 DECPTR (sizeof (u_int16_t), p); 1187 PUTSHORT (protocol, p); 1188 orc = CONFNAK; 1189 } 1190 break; 1191 /* 1192 * The router name is advisorary. Just accept it if it is not too large. 1193 */ 1194 case IPX_ROUTER_NAME: 1195 if (cilen >= CILEN_NAME) { 1196 int name_size = cilen - CILEN_NAME; 1197 if (name_size > sizeof (ho->name)) 1198 name_size = sizeof (ho->name) - 1; 1199 memset (ho->name, 0, sizeof (ho->name)); 1200 memcpy (ho->name, p, name_size); 1201 ho->name [name_size] = '\0'; 1202 ho->neg_name = 1; 1203 orc = CONFACK; 1204 break; 1205 } 1206 orc = CONFREJ; 1207 break; 1208 /* 1209 * This is advisorary. 1210 */ 1211 case IPX_COMPLETE: 1212 if (cilen != CILEN_COMPLETE) 1213 orc = CONFREJ; 1214 else { 1215 ho->neg_complete = 1; 1216 orc = CONFACK; 1217 } 1218 break; 1219 /* 1220 * All other entries are not known at this time. 1221 */ 1222 default: 1223 orc = CONFREJ; 1224 break; 1225 } 1226 endswitch: 1227 if (orc == CONFACK && /* Good CI */ 1228 rc != CONFACK) /* but prior CI wasnt? */ 1229 continue; /* Don't send this one */ 1230 1231 if (orc == CONFNAK) { /* Nak this CI? */ 1232 if (reject_if_disagree) /* Getting fed up with sending NAKs? */ 1233 orc = CONFREJ; /* Get tough if so */ 1234 if (rc == CONFREJ) /* Rejecting prior CI? */ 1235 continue; /* Don't send this one */ 1236 if (rc == CONFACK) { /* Ack'd all prior CIs? */ 1237 rc = CONFNAK; /* Not anymore... */ 1238 ucp = inp; /* Backup */ 1239 } 1240 } 1241 1242 if (orc == CONFREJ && /* Reject this CI */ 1243 rc != CONFREJ) { /* but no prior ones? */ 1244 rc = CONFREJ; 1245 ucp = inp; /* Backup */ 1246 } 1247 1248 /* Need to move CI? */ 1249 if (ucp != cip) 1250 BCOPY(cip, ucp, cilen); /* Move it */ 1251 1252 /* Update output pointer */ 1253 INCPTR(cilen, ucp); 1254 } 1255 1256 /* 1257 * If we aren't rejecting this packet, and we want to negotiate 1258 * their address, and they didn't send their address, then we 1259 * send a NAK with a IPX_NODE_NUMBER option appended. We assume the 1260 * input buffer is long enough that we can append the extra 1261 * option safely. 1262 */ 1263 1264 if (rc != CONFREJ && !ho->neg_node && 1265 wo->req_nn && !reject_if_disagree) { 1266 if (rc == CONFACK) { 1267 rc = CONFNAK; 1268 wo->req_nn = 0; /* don't ask again */ 1269 ucp = inp; /* reset pointer */ 1270 } 1271 1272 if (zero_node (wo->his_node)) 1273 inc_node (wo->his_node); 1274 1275 PUTCHAR (IPX_NODE_NUMBER, ucp); 1276 PUTCHAR (CILEN_NODEN, ucp); 1277 copy_node (wo->his_node, ucp); 1278 INCPTR (sizeof (wo->his_node), ucp); 1279 } 1280 1281 *len = ucp - inp; /* Compute output length */ 1282 IPXCPDEBUG(("ipxcp: returning Configure-%s", CODENAME(rc))); 1283 return (rc); /* Return final code */ 1284 } 1285 1286 /* 1287 * ipxcp_up - IPXCP has come UP. 1288 * 1289 * Configure the IP network interface appropriately and bring it up. 1290 */ 1291 1292 static void 1293 ipxcp_up(f) 1294 fsm *f; 1295 { 1296 int unit = f->unit; 1297 1298 IPXCPDEBUG(("ipxcp: up")); 1299 1300 /* The default router protocol is RIP/SAP. */ 1301 if (ho->router == 0) 1302 ho->router = BIT(RIP_SAP); 1303 1304 if (go->router == 0) 1305 go->router = BIT(RIP_SAP); 1306 1307 /* Fetch the network number */ 1308 if (!ho->neg_nn) 1309 ho->his_network = wo->his_network; 1310 1311 if (!ho->neg_node) 1312 copy_node (wo->his_node, ho->his_node); 1313 1314 if (!wo->neg_node && !go->neg_node) 1315 copy_node (wo->our_node, go->our_node); 1316 1317 if (zero_node (go->our_node)) { 1318 static char errmsg[] = "Could not determine local IPX node address"; 1319 if (debug) 1320 error(errmsg); 1321 ipxcp_close(f->unit, errmsg); 1322 return; 1323 } 1324 1325 go->network = go->our_network; 1326 if (ho->his_network != 0 && ho->his_network > go->network) 1327 go->network = ho->his_network; 1328 1329 if (go->network == 0) { 1330 static char errmsg[] = "Can not determine network number"; 1331 if (debug) 1332 error(errmsg); 1333 ipxcp_close (unit, errmsg); 1334 return; 1335 } 1336 1337 /* bring the interface up */ 1338 if (!sifup(unit)) { 1339 if (debug) 1340 warn("sifup failed (IPX)"); 1341 ipxcp_close(unit, "Interface configuration failed"); 1342 return; 1343 } 1344 ipxcp_is_up = 1; 1345 1346 /* set the network number for IPX */ 1347 if (!sipxfaddr(unit, go->network, go->our_node)) { 1348 if (debug) 1349 warn("sipxfaddr failed"); 1350 ipxcp_close(unit, "Interface configuration failed"); 1351 return; 1352 } 1353 1354 np_up(f->unit, PPP_IPX); 1355 1356 /* 1357 * Execute the ipx-up script, like this: 1358 * /etc/ppp/ipx-up interface tty speed local-IPX remote-IPX 1359 */ 1360 1361 ipxcp_script (f, _PATH_IPXUP); 1362 } 1363 1364 /* 1365 * ipxcp_down - IPXCP has gone DOWN. 1366 * 1367 * Take the IP network interface down, clear its addresses 1368 * and delete routes through it. 1369 */ 1370 1371 static void 1372 ipxcp_down(f) 1373 fsm *f; 1374 { 1375 IPXCPDEBUG(("ipxcp: down")); 1376 1377 if (!ipxcp_is_up) 1378 return; 1379 ipxcp_is_up = 0; 1380 np_down(f->unit, PPP_IPX); 1381 cipxfaddr(f->unit); 1382 sifnpmode(f->unit, PPP_IPX, NPMODE_DROP); 1383 sifdown(f->unit); 1384 ipxcp_script (f, _PATH_IPXDOWN); 1385 } 1386 1387 1388 /* 1389 * ipxcp_finished - possibly shut down the lower layers. 1390 */ 1391 static void 1392 ipxcp_finished(f) 1393 fsm *f; 1394 { 1395 np_finished(f->unit, PPP_IPX); 1396 } 1397 1398 1399 /* 1400 * ipxcp_script - Execute a script with arguments 1401 * interface-name tty-name speed local-IPX remote-IPX networks. 1402 */ 1403 static void 1404 ipxcp_script(f, script) 1405 fsm *f; 1406 char *script; 1407 { 1408 char strspeed[32], strlocal[32], strremote[32]; 1409 char strnetwork[32], strpid[32]; 1410 char *argv[14], strproto_lcl[32], strproto_rmt[32]; 1411 1412 slprintf(strpid, sizeof(strpid), "%d", getpid()); 1413 slprintf(strspeed, sizeof(strspeed),"%d", baud_rate); 1414 1415 strproto_lcl[0] = '\0'; 1416 if (go->neg_router && ((go->router & BIT(IPX_NONE)) == 0)) { 1417 if (go->router & BIT(RIP_SAP)) 1418 strlcpy (strproto_lcl, "RIP ", sizeof(strproto_lcl)); 1419 if (go->router & BIT(NLSP)) 1420 strlcat (strproto_lcl, "NLSP ", sizeof(strproto_lcl)); 1421 } 1422 1423 if (strproto_lcl[0] == '\0') 1424 strlcpy (strproto_lcl, "NONE ", sizeof(strproto_lcl)); 1425 1426 strproto_lcl[strlen (strproto_lcl)-1] = '\0'; 1427 1428 strproto_rmt[0] = '\0'; 1429 if (ho->neg_router && ((ho->router & BIT(IPX_NONE)) == 0)) { 1430 if (ho->router & BIT(RIP_SAP)) 1431 strlcpy (strproto_rmt, "RIP ", sizeof(strproto_rmt)); 1432 if (ho->router & BIT(NLSP)) 1433 strlcat (strproto_rmt, "NLSP ", sizeof(strproto_rmt)); 1434 } 1435 1436 if (strproto_rmt[0] == '\0') 1437 strlcpy (strproto_rmt, "NONE ", sizeof(strproto_rmt)); 1438 1439 strproto_rmt[strlen (strproto_rmt)-1] = '\0'; 1440 1441 strlcpy (strnetwork, ipx_ntoa (go->network), sizeof(strnetwork)); 1442 1443 slprintf (strlocal, sizeof(strlocal), "%0.6B", go->our_node); 1444 1445 slprintf (strremote, sizeof(strremote), "%0.6B", ho->his_node); 1446 1447 argv[0] = script; 1448 argv[1] = ifname; 1449 argv[2] = devnam; 1450 argv[3] = strspeed; 1451 argv[4] = strnetwork; 1452 argv[5] = strlocal; 1453 argv[6] = strremote; 1454 argv[7] = strproto_lcl; 1455 argv[8] = strproto_rmt; 1456 argv[9] = go->name; 1457 argv[10] = ho->name; 1458 argv[11] = ipparam; 1459 argv[12] = strpid; 1460 argv[13] = NULL; 1461 run_program(script, argv, 0, NULL, NULL); 1462 } 1463 1464 /* 1465 * ipxcp_printpkt - print the contents of an IPXCP packet. 1466 */ 1467 static char *ipxcp_codenames[] = { 1468 "ConfReq", "ConfAck", "ConfNak", "ConfRej", 1469 "TermReq", "TermAck", "CodeRej" 1470 }; 1471 1472 static int 1473 ipxcp_printpkt(p, plen, printer, arg) 1474 u_char *p; 1475 int plen; 1476 void (*printer) __P((void *, char *, ...)); 1477 void *arg; 1478 { 1479 int code, id, len, olen; 1480 u_char *pstart, *optend; 1481 u_short cishort; 1482 u_int32_t cilong; 1483 1484 if (plen < HEADERLEN) 1485 return 0; 1486 pstart = p; 1487 GETCHAR(code, p); 1488 GETCHAR(id, p); 1489 GETSHORT(len, p); 1490 if (len < HEADERLEN || len > plen) 1491 return 0; 1492 1493 if (code >= 1 && code <= sizeof(ipxcp_codenames) / sizeof(char *)) 1494 printer(arg, " %s", ipxcp_codenames[code-1]); 1495 else 1496 printer(arg, " code=0x%x", code); 1497 printer(arg, " id=0x%x", id); 1498 len -= HEADERLEN; 1499 switch (code) { 1500 case CONFREQ: 1501 case CONFACK: 1502 case CONFNAK: 1503 case CONFREJ: 1504 /* print option list */ 1505 while (len >= 2) { 1506 GETCHAR(code, p); 1507 GETCHAR(olen, p); 1508 p -= 2; 1509 if (olen < CILEN_VOID || olen > len) { 1510 break; 1511 } 1512 printer(arg, " <"); 1513 len -= olen; 1514 optend = p + olen; 1515 switch (code) { 1516 case IPX_NETWORK_NUMBER: 1517 if (olen == CILEN_NETN) { 1518 p += 2; 1519 GETLONG(cilong, p); 1520 printer (arg, "network %s", ipx_ntoa (cilong)); 1521 } 1522 break; 1523 case IPX_NODE_NUMBER: 1524 if (olen == CILEN_NODEN) { 1525 p += 2; 1526 printer (arg, "node "); 1527 while (p < optend) { 1528 GETCHAR(code, p); 1529 printer(arg, "%.2x", (int) (unsigned int) (unsigned char) code); 1530 } 1531 } 1532 break; 1533 case IPX_COMPRESSION_PROTOCOL: 1534 if (olen == CILEN_COMPRESS) { 1535 p += 2; 1536 GETSHORT (cishort, p); 1537 printer (arg, "compression %d", (int) cishort); 1538 } 1539 break; 1540 case IPX_ROUTER_PROTOCOL: 1541 if (olen == CILEN_PROTOCOL) { 1542 p += 2; 1543 GETSHORT (cishort, p); 1544 printer (arg, "router proto %d", (int) cishort); 1545 } 1546 break; 1547 case IPX_ROUTER_NAME: 1548 if (olen >= CILEN_NAME) { 1549 p += 2; 1550 printer (arg, "router name \""); 1551 while (p < optend) { 1552 GETCHAR(code, p); 1553 if (code >= 0x20 && code <= 0x7E) 1554 printer (arg, "%c", (int) (unsigned int) (unsigned char) code); 1555 else 1556 printer (arg, " \\%.2x", (int) (unsigned int) (unsigned char) code); 1557 } 1558 printer (arg, "\""); 1559 } 1560 break; 1561 case IPX_COMPLETE: 1562 if (olen == CILEN_COMPLETE) { 1563 p += 2; 1564 printer (arg, "complete"); 1565 } 1566 break; 1567 default: 1568 break; 1569 } 1570 1571 while (p < optend) { 1572 GETCHAR(code, p); 1573 printer(arg, " %.2x", (int) (unsigned int) (unsigned char) code); 1574 } 1575 printer(arg, ">"); 1576 } 1577 break; 1578 1579 case TERMACK: 1580 case TERMREQ: 1581 if (len > 0 && *p >= ' ' && *p < 0x7f) { 1582 printer(arg, " "); 1583 print_string(p, len, printer, arg); 1584 p += len; 1585 len = 0; 1586 } 1587 break; 1588 } 1589 1590 /* print the rest of the bytes in the packet */ 1591 for (; len > 0; --len) { 1592 GETCHAR(code, p); 1593 printer(arg, " %.2x", (int) (unsigned int) (unsigned char) code); 1594 } 1595 1596 return p - pstart; 1597 } 1598 #endif /* ifdef IPX_CHANGE */ 1599