1 /* $NetBSD: process.c,v 1.17 2009/11/17 18:58:07 drochner Exp $ */ 2 3 /* 4 * Copyright (c) 1993-95 Mats O Jansson. 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 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 #ifndef lint 29 __RCSID("$NetBSD: process.c,v 1.17 2009/11/17 18:58:07 drochner Exp $"); 30 #endif 31 32 #include "os.h" 33 #include "cmp.h" 34 #include "common.h" 35 #include "dl.h" 36 #include "file.h" 37 #include "get.h" 38 #include "mopdef.h" 39 #include "nmadef.h" 40 #include "pf.h" 41 #include "print.h" 42 #include "put.h" 43 #include "rc.h" 44 45 extern u_char buf[]; 46 extern int DebugFlag; 47 extern char *MopdDir; 48 49 struct dllist dllist[MAXDL]; /* dump/load list */ 50 51 void mopNextLoad(const u_char *, const u_char *, u_char, int); 52 void mopProcessDL(FILE *, struct if_info *, const u_char *, int *, 53 const u_char *, const u_char *, int, u_short); 54 void mopProcessRC(FILE *, struct if_info *, const u_char *, int *, 55 const u_char *, const u_char *, int, u_short); 56 void mopProcessInfo(const u_char *, int *, u_short, struct dllist *, int); 57 void mopSendASV(const u_char *, const u_char *, struct if_info *, int); 58 void mopStartLoad(const u_char *, const u_char *, struct dllist *, int); 59 60 void 61 mopProcessInfo(const u_char *pkt, int *idx, u_short moplen, struct dllist *dl_rpr, 62 int trans) 63 { 64 u_short itype,tmps; 65 u_char ilen ,tmpc,device; 66 u_char uc1,uc2,uc3; 67 const u_char *ucp; 68 69 device = 0; 70 71 switch(trans) { 72 case TRANS_ETHER: 73 moplen = moplen + 16; 74 break; 75 case TRANS_8023: 76 moplen = moplen + 14; 77 break; 78 } 79 80 itype = mopGetShort(pkt,idx); 81 82 while (*idx < (int)(moplen)) { 83 ilen = mopGetChar(pkt,idx); 84 switch (itype) { 85 case 0: 86 tmpc = mopGetChar(pkt,idx); 87 *idx = *idx + tmpc; 88 break; 89 case MOP_K_INFO_VER: 90 uc1 = mopGetChar(pkt,idx); 91 uc2 = mopGetChar(pkt,idx); 92 uc3 = mopGetChar(pkt,idx); 93 break; 94 case MOP_K_INFO_MFCT: 95 tmps = mopGetShort(pkt,idx); 96 break; 97 case MOP_K_INFO_CNU: 98 ucp = pkt + *idx; *idx = *idx + 6; 99 break; 100 case MOP_K_INFO_RTM: 101 tmps = mopGetShort(pkt,idx); 102 break; 103 case MOP_K_INFO_CSZ: 104 tmps = mopGetShort(pkt,idx); 105 break; 106 case MOP_K_INFO_RSZ: 107 tmps = mopGetShort(pkt,idx); 108 break; 109 case MOP_K_INFO_HWA: 110 ucp = pkt + *idx; *idx = *idx + 6; 111 break; 112 case MOP_K_INFO_TIME: 113 ucp = pkt + *idx; *idx = *idx + 10; 114 break; 115 case MOP_K_INFO_SOFD: 116 device = mopGetChar(pkt,idx); 117 break; 118 case MOP_K_INFO_SFID: 119 tmpc = mopGetChar(pkt,idx); 120 ucp = pkt + *idx; *idx = *idx + tmpc; 121 break; 122 case MOP_K_INFO_PRTY: 123 tmpc = mopGetChar(pkt,idx); 124 break; 125 case MOP_K_INFO_DLTY: 126 tmpc = mopGetChar(pkt,idx); 127 break; 128 case MOP_K_INFO_DLBSZ: 129 tmps = mopGetShort(pkt,idx); 130 dl_rpr->dl_bsz = tmps; 131 break; 132 default: 133 if (((device = NMA_C_SOFD_LCS) || /* DECserver 100 */ 134 (device = NMA_C_SOFD_DS2) || /* DECserver 200 */ 135 (device = NMA_C_SOFD_DP2) || /* DECserver 250 */ 136 (device = NMA_C_SOFD_DS3)) && /* DECserver 300 */ 137 ((itype > 101) && (itype < 107))) 138 { 139 switch (itype) { 140 case 102: 141 ucp = pkt + *idx; 142 *idx = *idx + ilen; 143 break; 144 case 103: 145 ucp = pkt + *idx; 146 *idx = *idx + ilen; 147 break; 148 case 104: 149 tmps = mopGetShort(pkt,idx); 150 break; 151 case 105: 152 ucp = pkt + *idx; 153 *idx = *idx + ilen; 154 break; 155 case 106: 156 ucp = pkt + *idx; 157 *idx = *idx + ilen; 158 break; 159 }; 160 } else { 161 ucp = pkt + *idx; *idx = *idx + ilen; 162 }; 163 } 164 itype = mopGetShort(pkt,idx); 165 } 166 } 167 168 void 169 mopSendASV(const u_char *dst, const u_char *src, struct if_info *ii, int trans) 170 { 171 u_char pkt[200], *p; 172 int idx; 173 u_char mopcode = MOP_K_CODE_ASV; 174 u_short newlen = 0,ptype = MOP_K_PROTO_DL; 175 176 idx = 0; 177 mopPutHeader(pkt, &idx, dst, src, ptype, trans); 178 179 p = &pkt[idx]; 180 mopPutChar(pkt,&idx,mopcode); 181 182 mopPutLength(pkt, trans, idx); 183 newlen = mopGetLength(pkt, trans); 184 185 if ((DebugFlag == DEBUG_ONELINE)) { 186 mopPrintOneline(stdout, pkt, trans); 187 } 188 189 if ((DebugFlag >= DEBUG_HEADER)) { 190 mopPrintHeader(stdout, pkt, trans); 191 mopPrintMopHeader(stdout, pkt, trans); 192 } 193 194 if ((DebugFlag >= DEBUG_INFO)) { 195 mopDumpDL(stdout, pkt, trans); 196 } 197 198 if (pfWrite(ii->fd, pkt, idx, trans) != idx) { 199 if (DebugFlag) { 200 (void)fprintf(stderr, "error pfWrite()\n"); 201 } 202 } 203 } 204 205 #define MAX_ETH_PAYLOAD 1492 206 207 void 208 mopStartLoad(const u_char *dst, const u_char *src, struct dllist *dl_rpr, 209 int trans) 210 { 211 int len; 212 int i, slot; 213 u_char pkt[BUFSIZE], *p; 214 int idx; 215 u_char mopcode = MOP_K_CODE_MLD; 216 u_short newlen,ptype = MOP_K_PROTO_DL; 217 struct dllist *dle; 218 219 slot = -1; 220 221 /* Look if we have a non terminated load, if so, use it's slot */ 222 223 for (i = 0, dle = dllist; i < MAXDL; i++, dle++) { 224 if (dle->status != DL_STATUS_FREE) { 225 if (mopCmpEAddr(dle->eaddr, dst) == 0) { 226 slot = i; 227 } 228 } 229 } 230 231 /* If no slot yet, then find first free */ 232 233 if (slot == -1) { 234 for (i = 0, dle = dllist; i < MAXDL; i++, dle++) { 235 if (dle->status == DL_STATUS_FREE) { 236 if (slot == -1) { 237 slot = i; 238 memmove((char *)dle->eaddr, 239 (const char *)dst, 6); 240 } 241 } 242 } 243 } 244 245 /* If no slot yet, then return. No slot is free */ 246 247 if (slot == -1) 248 return; 249 250 /* Ok, save info from RPR */ 251 252 dllist[slot] = *dl_rpr; 253 dle = &dllist[slot]; 254 dle->status = DL_STATUS_READ_IMGHDR; 255 256 /* Get Load and Transfer Address. */ 257 258 GetFileInfo(dle); 259 260 dle->nloadaddr = dle->loadaddr; 261 dle->lseek = lseek(dle->ldfd, 0L, SEEK_CUR); 262 dle->a_lseek = 0; 263 264 dle->count = 0; 265 if (dle->dl_bsz >= MAX_ETH_PAYLOAD || dle->dl_bsz == 0) 266 dle->dl_bsz = MAX_ETH_PAYLOAD; 267 if (dle->dl_bsz == 1030) /* VS/uVAX 2000 needs this */ 268 dle->dl_bsz = 1000; 269 if (dle->dl_bsz == 0) /* Needed by "big" VAXen */ 270 dle->dl_bsz = MAX_ETH_PAYLOAD; 271 if (trans == TRANS_8023) 272 dle->dl_bsz = dle->dl_bsz - 8; 273 274 idx = 0; 275 mopPutHeader(pkt, &idx, dst, src, ptype, trans); 276 p = &pkt[idx]; 277 mopPutChar (pkt, &idx, mopcode); 278 279 mopPutChar (pkt, &idx, dle->count); 280 mopPutLong (pkt, &idx, dle->loadaddr); 281 282 len = mopFileRead(dle, &pkt[idx]); 283 284 dle->nloadaddr = dle->loadaddr + len; 285 idx = idx + len; 286 287 mopPutLength(pkt, trans, idx); 288 newlen = mopGetLength(pkt, trans); 289 290 if ((DebugFlag == DEBUG_ONELINE)) { 291 mopPrintOneline(stdout, pkt, trans); 292 } 293 294 if ((DebugFlag >= DEBUG_HEADER)) { 295 mopPrintHeader(stdout, pkt, trans); 296 mopPrintMopHeader(stdout, pkt, trans); 297 } 298 299 if ((DebugFlag >= DEBUG_INFO)) { 300 mopDumpDL(stdout, pkt, trans); 301 } 302 303 if (pfWrite(dle->ii->fd, pkt, idx, trans) != idx) { 304 if (DebugFlag) { 305 (void)fprintf(stderr, "error pfWrite()\n"); 306 } 307 } 308 309 dle->status = DL_STATUS_SENT_MLD; 310 } 311 312 void 313 mopNextLoad(const u_char *dst, const u_char *src, u_char new_count, int trans) 314 { 315 int len; 316 int i, slot; 317 u_char pkt[BUFSIZE], *p; 318 int idx, pindex; 319 char line[100]; 320 u_short newlen = 0,ptype = MOP_K_PROTO_DL; 321 u_char mopcode; 322 struct dllist *dle; 323 324 slot = -1; 325 326 for (i = 0, dle = dllist; i < MAXDL; i++, dle++) { 327 if (dle->status != DL_STATUS_FREE) { 328 if (mopCmpEAddr(dst, dle->eaddr) == 0) 329 slot = i; 330 } 331 } 332 333 /* If no slot yet, then return. No slot is free */ 334 335 if (slot == -1) 336 return; 337 338 dle = &dllist[slot]; 339 340 if ((new_count == ((dle->count+1) % 256))) { 341 dle->loadaddr = dllist[slot].nloadaddr; 342 dle->count = new_count; 343 } else if (new_count != (dle->count % 256)) { 344 return; 345 } 346 347 if (dle->status == DL_STATUS_SENT_PLT) { 348 close(dle->ldfd); 349 dle->ldfd = -1; 350 dle->status = DL_STATUS_FREE; 351 snprintf(line, sizeof(line), 352 "%x:%x:%x:%x:%x:%x Load completed", 353 dst[0],dst[1],dst[2],dst[3],dst[4],dst[5]); 354 syslog(LOG_INFO, "%s", line); 355 return; 356 } 357 358 dle->lseek = lseek(dle->ldfd, 0L, SEEK_CUR); 359 360 if (dle->dl_bsz >= MAX_ETH_PAYLOAD) 361 dle->dl_bsz = MAX_ETH_PAYLOAD; 362 363 idx = 0; 364 mopPutHeader(pkt, &idx, dst, src, ptype, trans); 365 p = &pkt[idx]; 366 mopcode = MOP_K_CODE_MLD; 367 pindex = idx; 368 mopPutChar (pkt,&idx, mopcode); 369 mopPutChar (pkt,&idx, dle->count); 370 mopPutLong (pkt,&idx, dle->loadaddr); 371 372 len = mopFileRead(dle, &pkt[idx]); 373 374 if (len > 0 ) { 375 376 dle->nloadaddr = dle->loadaddr + len; 377 idx = idx + len; 378 379 mopPutLength(pkt, trans, idx); 380 newlen = mopGetLength(pkt, trans); 381 382 } else { 383 if (len == 0) { 384 idx = pindex; 385 mopcode = MOP_K_CODE_PLT; 386 mopPutChar (pkt, &idx, mopcode); 387 mopPutChar (pkt, &idx, dle->count); 388 mopPutChar (pkt, &idx, MOP_K_PLTP_HSN); 389 mopPutChar (pkt, &idx, 3); 390 mopPutMulti(pkt, &idx, "ipc", 3); 391 mopPutChar (pkt, &idx, MOP_K_PLTP_HSA); 392 mopPutChar (pkt, &idx, 6); 393 mopPutMulti(pkt, &idx, src, 6); 394 mopPutChar (pkt, &idx, MOP_K_PLTP_HST); 395 mopPutTime (pkt, &idx, 0); 396 mopPutChar (pkt, &idx, 0); 397 mopPutLong (pkt, &idx, dle->xferaddr); 398 399 mopPutLength(pkt, trans, idx); 400 newlen = mopGetLength(pkt, trans); 401 402 dle->status = DL_STATUS_SENT_PLT; 403 } else { 404 dle->status = DL_STATUS_FREE; 405 return; 406 } 407 } 408 409 if ((DebugFlag == DEBUG_ONELINE)) { 410 mopPrintOneline(stdout, pkt, trans); 411 } 412 413 if ((DebugFlag >= DEBUG_HEADER)) { 414 mopPrintHeader(stdout, pkt, trans); 415 mopPrintMopHeader(stdout, pkt, trans); 416 } 417 418 if ((DebugFlag >= DEBUG_INFO)) { 419 mopDumpDL(stdout, pkt, trans); 420 } 421 422 if (pfWrite(dle->ii->fd, pkt, idx, trans) != idx) { 423 if (DebugFlag) { 424 (void)fprintf(stderr, "error pfWrite()\n"); 425 } 426 } 427 } 428 429 void 430 mopProcessDL(FILE *fd, struct if_info *ii, const u_char *pkt, int *idx, 431 const u_char *dst, const u_char *src, int trans, u_short len) 432 { 433 u_char tmpc; 434 u_short moplen; 435 u_char pfile[129], mopcode; 436 char filename[FILENAME_MAX]; 437 char line[100]; 438 int i,nfd,iindex; 439 struct dllist dl,*dl_rpr; 440 u_char rpr_pgty,load; 441 442 if ((DebugFlag == DEBUG_ONELINE)) { 443 mopPrintOneline(stdout, pkt, trans); 444 } 445 446 if ((DebugFlag >= DEBUG_HEADER)) { 447 mopPrintHeader(stdout, pkt, trans); 448 mopPrintMopHeader(stdout, pkt, trans); 449 } 450 451 if ((DebugFlag >= DEBUG_INFO)) { 452 mopDumpDL(stdout, pkt, trans); 453 } 454 455 moplen = mopGetLength(pkt, trans); 456 mopcode = mopGetChar(pkt,idx); 457 458 switch (mopcode) { 459 case MOP_K_CODE_MLT: 460 break; 461 case MOP_K_CODE_DCM: 462 break; 463 case MOP_K_CODE_MLD: 464 break; 465 case MOP_K_CODE_ASV: 466 break; 467 case MOP_K_CODE_RMD: 468 break; 469 case MOP_K_CODE_RPR: 470 471 tmpc = mopGetChar(pkt,idx); /* Device Type */ 472 473 tmpc = mopGetChar(pkt,idx); /* Format Version */ 474 if ((tmpc != MOP_K_RPR_FORMAT) && 475 (tmpc != MOP_K_RPR_FORMAT_V3)) { 476 (void)fprintf(stderr,"mopd: Unknown RPR Format (%d) from ",tmpc); 477 mopPrintHWA(stderr,src); 478 (void)fprintf(stderr,"\n"); 479 } 480 481 rpr_pgty = mopGetChar(pkt,idx); /* Program Type */ 482 483 tmpc = mopGetChar(pkt,idx); /* Software ID Len */ 484 if (tmpc > sizeof(pfile) - 1) 485 return; 486 for (i = 0; i < tmpc; i++) { 487 pfile[i] = mopGetChar(pkt,idx); 488 pfile[i+1] = '\0'; 489 } 490 491 if (tmpc == 0) { 492 /* In a normal implementation of a MOP Loader this */ 493 /* would cause a question to NML (DECnet) if this */ 494 /* node is known and if so what image to load. But */ 495 /* we don't have DECnet so we don't have anybody */ 496 /* to ask. My solution is to use the ethernet addr */ 497 /* as filename. Implementing a database would be */ 498 /* overkill. */ 499 snprintf(pfile, sizeof(pfile), 500 "%02x%02x%02x%02x%02x%02x%c", 501 src[0],src[1],src[2],src[3],src[4],src[5],0); 502 } 503 504 tmpc = mopGetChar(pkt,idx); /* Processor */ 505 506 iindex = *idx; 507 dl_rpr = &dl; 508 memset(dl_rpr, 0, sizeof(*dl_rpr)); 509 dl_rpr->ii = ii; 510 memmove((char *)(dl_rpr->eaddr), (const char *)src, 6); 511 mopProcessInfo(pkt,idx,moplen,dl_rpr,trans); 512 513 snprintf(filename, sizeof(filename), "%s/%s.SYS", 514 MopdDir, pfile); 515 if ((mopCmpEAddr(dst,dl_mcst) == 0)) { 516 if ((nfd = open(filename, O_RDONLY, 0)) != -1) { 517 close(nfd); 518 mopSendASV(src, ii->eaddr, ii, trans); 519 snprintf(line, sizeof(line), 520 "%x:%x:%x:%x:%x:%x (%d) Do you have %s? (Yes)", 521 src[0],src[1],src[2], 522 src[3],src[4],src[5],trans,pfile); 523 } else { 524 snprintf(line, sizeof(line), 525 "%x:%x:%x:%x:%x:%x (%d) Do you have %s? (No)", 526 src[0],src[1],src[2], 527 src[3],src[4],src[5],trans,pfile); 528 } 529 syslog(LOG_INFO, "%s", line); 530 } else { 531 if ((mopCmpEAddr(dst,ii->eaddr) == 0)) { 532 dl_rpr->ldfd = open(filename, O_RDONLY, 0); 533 mopStartLoad(src, ii->eaddr, dl_rpr, trans); 534 snprintf(line, sizeof(line), 535 "%x:%x:%x:%x:%x:%x Send me %s", 536 src[0],src[1],src[2], 537 src[3],src[4],src[5],pfile); 538 syslog(LOG_INFO, "%s", line); 539 } 540 } 541 542 break; 543 case MOP_K_CODE_RML: 544 545 load = mopGetChar(pkt,idx); /* Load Number */ 546 547 tmpc = mopGetChar(pkt,idx); /* Error */ 548 549 if ((mopCmpEAddr(dst,ii->eaddr) == 0)) { 550 mopNextLoad(src, ii->eaddr, load, trans); 551 } 552 553 break; 554 case MOP_K_CODE_RDS: 555 break; 556 case MOP_K_CODE_MDD: 557 break; 558 case MOP_K_CODE_CCP: 559 break; 560 case MOP_K_CODE_PLT: 561 break; 562 default: 563 break; 564 } 565 } 566 567 void 568 mopProcessRC(FILE *fd, struct if_info *ii, const u_char *pkt, int *idx, 569 const u_char *dst, const u_char *src, int trans, u_short len) 570 { 571 u_char tmpc; 572 u_short tmps, moplen = 0; 573 u_char mopcode; 574 struct dllist dl,*dl_rpr; 575 576 if ((DebugFlag == DEBUG_ONELINE)) { 577 mopPrintOneline(stdout, pkt, trans); 578 } 579 580 if ((DebugFlag >= DEBUG_HEADER)) { 581 mopPrintHeader(stdout, pkt, trans); 582 mopPrintMopHeader(stdout, pkt, trans); 583 } 584 585 if ((DebugFlag >= DEBUG_INFO)) { 586 mopDumpRC(stdout, pkt, trans); 587 } 588 589 moplen = mopGetLength(pkt, trans); 590 mopcode = mopGetChar(pkt,idx); 591 592 switch (mopcode) { 593 case MOP_K_CODE_RID: 594 break; 595 case MOP_K_CODE_BOT: 596 break; 597 case MOP_K_CODE_SID: 598 599 tmpc = mopGetChar(pkt,idx); /* Reserved */ 600 601 if ((DebugFlag >= DEBUG_INFO)) { 602 (void)fprintf(stderr, "Reserved : %02x\n",tmpc); 603 } 604 605 tmps = mopGetShort(pkt,idx); /* Receipt # */ 606 if ((DebugFlag >= DEBUG_INFO)) { 607 (void)fprintf(stderr, "Receipt Nbr : %04x\n",tmpc); 608 } 609 610 dl_rpr = &dl; 611 memset(dl_rpr, 0, sizeof(*dl_rpr)); 612 dl_rpr->ii = ii; 613 memmove((char *)(dl_rpr->eaddr), (const char *)src, 6); 614 mopProcessInfo(pkt,idx,moplen,dl_rpr,trans); 615 616 break; 617 case MOP_K_CODE_RQC: 618 break; 619 case MOP_K_CODE_CNT: 620 break; 621 case MOP_K_CODE_RVC: 622 break; 623 case MOP_K_CODE_RLC: 624 break; 625 case MOP_K_CODE_CCP: 626 break; 627 case MOP_K_CODE_CRA: 628 break; 629 default: 630 break; 631 } 632 } 633 634