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