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