xref: /netbsd/usr.sbin/mopd/mopd/process.c (revision 6550d01e)
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