xref: /plan9/sys/src/9/ip/ethermedium.c (revision 3f69512988c55e1bb3bc10cc4fa9825ba0b07fec)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7 
8 #include "ip.h"
9 #include "ipv6.h"
10 
11 typedef struct Etherhdr Etherhdr;
12 struct Etherhdr
13 {
14 	uchar	d[6];
15 	uchar	s[6];
16 	uchar	t[2];
17 };
18 
19 static void	etherread4(void *a);
20 static void	etherread6(void *a);
21 static void	etherbind(Ipifc *ifc, int argc, char **argv);
22 static void	etherunbind(Ipifc *ifc);
23 static void	etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
24 static void	etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia);
25 static void	etherremmulti(Ipifc *ifc, uchar *a, uchar *ia);
26 static Block*	multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac);
27 static void	sendarp(Ipifc *ifc, Arpent *a);
28 static void	sendgarp(Ipifc *ifc, uchar*);
29 static int	multicastea(uchar *ea, uchar *ip);
30 static void	recvarpproc(void*);
31 static void	resolveaddr6(Ipifc *ifc, Arpent *a);
32 static void	etherpref2addr(uchar *pref, uchar *ea);
33 
34 Medium ethermedium =
35 {
36 .name=		"ether",
37 .hsize=		14,
38 .mintu=		60,
39 .maxtu=		1514,
40 .maclen=	6,
41 .bind=		etherbind,
42 .unbind=	etherunbind,
43 .bwrite=	etherbwrite,
44 .addmulti=	etheraddmulti,
45 .remmulti=	etherremmulti,
46 .ares=		arpenter,
47 .areg=		sendgarp,
48 .pref2addr=	etherpref2addr,
49 };
50 
51 Medium gbemedium =
52 {
53 .name=		"gbe",
54 .hsize=		14,
55 .mintu=		60,
56 .maxtu=		9014,
57 .maclen=	6,
58 .bind=		etherbind,
59 .unbind=	etherunbind,
60 .bwrite=	etherbwrite,
61 .addmulti=	etheraddmulti,
62 .remmulti=	etherremmulti,
63 .ares=		arpenter,
64 .areg=		sendgarp,
65 .pref2addr=	etherpref2addr,
66 };
67 
68 typedef struct	Etherrock Etherrock;
69 struct Etherrock
70 {
71 	Fs	*f;		/* file system we belong to */
72 	Proc	*arpp;		/* arp process */
73 	Proc	*read4p;	/* reading process (v4)*/
74 	Proc	*read6p;	/* reading process (v6)*/
75 	Chan	*mchan4;	/* Data channel for v4 */
76 	Chan	*achan;		/* Arp channel */
77 	Chan	*cchan4;	/* Control channel for v4 */
78 	Chan	*mchan6;	/* Data channel for v6 */
79 	Chan	*cchan6;	/* Control channel for v6 */
80 };
81 
82 /*
83  *  ethernet arp request
84  */
85 enum
86 {
87 	ETARP		= 0x0806,
88 	ETIP4		= 0x0800,
89 	ETIP6		= 0x86DD,
90 	ARPREQUEST	= 1,
91 	ARPREPLY	= 2,
92 };
93 
94 typedef struct Etherarp Etherarp;
95 struct Etherarp
96 {
97 	uchar	d[6];
98 	uchar	s[6];
99 	uchar	type[2];
100 	uchar	hrd[2];
101 	uchar	pro[2];
102 	uchar	hln;
103 	uchar	pln;
104 	uchar	op[2];
105 	uchar	sha[6];
106 	uchar	spa[4];
107 	uchar	tha[6];
108 	uchar	tpa[4];
109 };
110 
111 static char *nbmsg = "nonblocking";
112 
113 /*
114  *  called to bind an IP ifc to an ethernet device
115  *  called with ifc wlock'd
116  */
117 static void
118 etherbind(Ipifc *ifc, int argc, char **argv)
119 {
120 	Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6, *schan;
121 	char addr[Maxpath];	//char addr[2*KNAMELEN];
122 	char dir[Maxpath];	//char dir[2*KNAMELEN];
123 	char *buf;
124 	int n;
125 	char *ptr;
126 	Etherrock *er;
127 
128 	if(argc < 2)
129 		error(Ebadarg);
130 
131 	mchan4 = cchan4 = achan = mchan6 = cchan6 = nil;
132 	buf = nil;
133 	if(waserror()){
134 		if(mchan4 != nil)
135 			cclose(mchan4);
136 		if(cchan4 != nil)
137 			cclose(cchan4);
138 		if(achan != nil)
139 			cclose(achan);
140 		if(mchan6 != nil)
141 			cclose(mchan6);
142 		if(cchan6 != nil)
143 			cclose(cchan6);
144 		if(buf != nil)
145 			free(buf);
146 		nexterror();
147 	}
148 
149 	/*
150 	 *  open ip converstation
151 	 *
152 	 *  the dial will fail if the type is already open on
153 	 *  this device.
154 	 */
155 	snprint(addr, sizeof(addr), "%s!0x800", argv[2]);
156 	mchan4 = chandial(addr, nil, dir, &cchan4);
157 
158 	/*
159 	 *  make it non-blocking
160 	 */
161 	devtab[cchan4->type]->write(cchan4, nbmsg, strlen(nbmsg), 0);
162 
163 	/*
164 	 *  get mac address and speed
165 	 */
166 	snprint(addr, sizeof(addr), "%s/stats", dir);
167 	buf = smalloc(512);
168 	schan = namec(addr, Aopen, OREAD, 0);
169 	if(waserror()){
170 		cclose(schan);
171 		nexterror();
172 	}
173 	n = devtab[schan->type]->read(schan, buf, 511, 0);
174 	cclose(schan);
175 	poperror();
176 	buf[n] = 0;
177 
178 	ptr = strstr(buf, "addr: ");
179 	if(!ptr)
180 		error(Eio);
181 	ptr += 6;
182 	parsemac(ifc->mac, ptr, 6);
183 
184 	ptr = strstr(buf, "mbps: ");
185 	if(ptr){
186 		ptr += 6;
187 		ifc->mbps = atoi(ptr);
188 	} else
189 		ifc->mbps = 100;
190 
191 	/*
192  	 *  open arp conversation
193 	 */
194 	snprint(addr, sizeof(addr), "%s!0x806", argv[2]);
195 	achan = chandial(addr, nil, nil, nil);
196 
197 	/*
198 	 *  open ip conversation
199 	 *
200 	 *  the dial will fail if the type is already open on
201 	 *  this device.
202 	 */
203 	snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]);
204 	mchan6 = chandial(addr, nil, dir, &cchan6);
205 
206 	/*
207 	 *  make it non-blocking
208 	 */
209 	devtab[cchan6->type]->write(cchan6, nbmsg, strlen(nbmsg), 0);
210 
211 	er = smalloc(sizeof(*er));
212 	er->mchan4 = mchan4;
213 	er->cchan4 = cchan4;
214 	er->achan = achan;
215 	er->mchan6 = mchan6;
216 	er->cchan6 = cchan6;
217 	er->f = ifc->conv->p->f;
218 	ifc->arg = er;
219 
220 	free(buf);
221 	poperror();
222 
223 	kproc("etherread4", etherread4, ifc);
224 	kproc("recvarpproc", recvarpproc, ifc);
225 	kproc("etherread6", etherread6, ifc);
226 }
227 
228 /*
229  *  called with ifc wlock'd
230  */
231 static void
232 etherunbind(Ipifc *ifc)
233 {
234 	Etherrock *er = ifc->arg;
235 
236 	if(er->read4p)
237 		postnote(er->read4p, 1, "unbind", 0);
238 	if(er->read6p)
239 		postnote(er->read6p, 1, "unbind", 0);
240 	if(er->arpp)
241 		postnote(er->arpp, 1, "unbind", 0);
242 
243 	/* wait for readers to die */
244 	while(er->arpp != 0 || er->read4p != 0 || er->read6p != 0)
245 		tsleep(&up->sleep, return0, 0, 300);
246 
247 	if(er->mchan4 != nil)
248 		cclose(er->mchan4);
249 	if(er->achan != nil)
250 		cclose(er->achan);
251 	if(er->cchan4 != nil)
252 		cclose(er->cchan4);
253 	if(er->mchan6 != nil)
254 		cclose(er->mchan6);
255 	if(er->cchan6 != nil)
256 		cclose(er->cchan6);
257 
258 	free(er);
259 }
260 
261 /*
262  *  called by ipoput with a single block to write with ifc rlock'd
263  */
264 static void
265 etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
266 {
267 	Etherhdr *eh;
268 	Arpent *a;
269 	uchar mac[6];
270 	Etherrock *er = ifc->arg;
271 
272 	/* get mac address of destination */
273 	a = arpget(er->f->arp, bp, version, ifc, ip, mac);
274 	if(a){
275 		/* check for broadcast or multicast */
276 		bp = multicastarp(er->f, a, ifc->m, mac);
277 		if(bp==nil){
278 			switch(version){
279 			case V4:
280 				sendarp(ifc, a);
281 				break;
282 			case V6:
283 				resolveaddr6(ifc, a);
284 				break;
285 			default:
286 				panic("etherbwrite: version %d", version);
287 			}
288 			return;
289 		}
290 	}
291 
292 	/* make it a single block with space for the ether header */
293 	bp = padblock(bp, ifc->m->hsize);
294 	if(bp->next)
295 		bp = concatblock(bp);
296 	if(BLEN(bp) < ifc->mintu)
297 		bp = adjustblock(bp, ifc->mintu);
298 	eh = (Etherhdr*)bp->rp;
299 
300 	/* copy in mac addresses and ether type */
301 	memmove(eh->s, ifc->mac, sizeof(eh->s));
302 	memmove(eh->d, mac, sizeof(eh->d));
303 
304  	switch(version){
305 	case V4:
306 		eh->t[0] = 0x08;
307 		eh->t[1] = 0x00;
308 		devtab[er->mchan4->type]->bwrite(er->mchan4, bp, 0);
309 		break;
310 	case V6:
311 		eh->t[0] = 0x86;
312 		eh->t[1] = 0xDD;
313 		devtab[er->mchan6->type]->bwrite(er->mchan6, bp, 0);
314 		break;
315 	default:
316 		panic("etherbwrite2: version %d", version);
317 	}
318 	ifc->out++;
319 }
320 
321 
322 /*
323  *  process to read from the ethernet
324  */
325 static void
326 etherread4(void *a)
327 {
328 	Ipifc *ifc;
329 	Block *bp;
330 	Etherrock *er;
331 
332 	ifc = a;
333 	er = ifc->arg;
334 	er->read4p = up;	/* hide identity under a rock for unbind */
335 	if(waserror()){
336 		er->read4p = 0;
337 		pexit("hangup", 1);
338 	}
339 	for(;;){
340 		bp = devtab[er->mchan4->type]->bread(er->mchan4, ifc->maxtu, 0);
341 		if(!canrlock(ifc)){
342 			freeb(bp);
343 			continue;
344 		}
345 		if(waserror()){
346 			runlock(ifc);
347 			nexterror();
348 		}
349 		ifc->in++;
350 		bp->rp += ifc->m->hsize;
351 		if(ifc->lifc == nil)
352 			freeb(bp);
353 		else
354 			ipiput4(er->f, ifc, bp);
355 		runlock(ifc);
356 		poperror();
357 	}
358 }
359 
360 
361 /*
362  *  process to read from the ethernet, IPv6
363  */
364 static void
365 etherread6(void *a)
366 {
367 	Ipifc *ifc;
368 	Block *bp;
369 	Etherrock *er;
370 
371 	ifc = a;
372 	er = ifc->arg;
373 	er->read6p = up;	/* hide identity under a rock for unbind */
374 	if(waserror()){
375 		er->read6p = 0;
376 		pexit("hangup", 1);
377 	}
378 	for(;;){
379 		bp = devtab[er->mchan6->type]->bread(er->mchan6, ifc->maxtu, 0);
380 		if(!canrlock(ifc)){
381 			freeb(bp);
382 			continue;
383 		}
384 		if(waserror()){
385 			runlock(ifc);
386 			nexterror();
387 		}
388 		ifc->in++;
389 		bp->rp += ifc->m->hsize;
390 		if(ifc->lifc == nil)
391 			freeb(bp);
392 		else
393 			ipiput6(er->f, ifc, bp);
394 		runlock(ifc);
395 		poperror();
396 	}
397 }
398 
399 static void
400 etheraddmulti(Ipifc *ifc, uchar *a, uchar *)
401 {
402 	uchar mac[6];
403 	char buf[64];
404 	Etherrock *er = ifc->arg;
405 	int version;
406 
407 	version = multicastea(mac, a);
408 	sprint(buf, "addmulti %E", mac);
409 	switch(version){
410 	case V4:
411 		devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
412 		break;
413 	case V6:
414 		devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
415 		break;
416 	default:
417 		panic("etheraddmulti: version %d", version);
418 	}
419 }
420 
421 static void
422 etherremmulti(Ipifc *ifc, uchar *a, uchar *)
423 {
424 	uchar mac[6];
425 	char buf[64];
426 	Etherrock *er = ifc->arg;
427 	int version;
428 
429 	version = multicastea(mac, a);
430 	sprint(buf, "remmulti %E", mac);
431 	switch(version){
432 	case V4:
433 		devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
434 		break;
435 	case V6:
436 		devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
437 		break;
438 	default:
439 		panic("etherremmulti: version %d", version);
440 	}
441 }
442 
443 /*
444  *  send an ethernet arp
445  *  (only v4, v6 uses the neighbor discovery, rfc1970)
446  */
447 static void
448 sendarp(Ipifc *ifc, Arpent *a)
449 {
450 	int n;
451 	Block *bp;
452 	Etherarp *e;
453 	Etherrock *er = ifc->arg;
454 
455 	/* don't do anything if it's been less than a second since the last */
456 	if(NOW - a->time < 1000){
457 		arprelease(er->f->arp, a);
458 		return;
459 	}
460 
461 	/* remove all but the last message */
462 	while((bp = a->hold) != nil){
463 		if(bp == a->last)
464 			break;
465 		a->hold = bp->list;
466 		freeblist(bp);
467 	}
468 
469 	/* try to keep it around for a second more */
470 	a->time = NOW;
471 	arprelease(er->f->arp, a);
472 
473 	n = sizeof(Etherarp);
474 	if(n < a->type->mintu)
475 		n = a->type->mintu;
476 	bp = allocb(n);
477 	memset(bp->rp, 0, n);
478 	e = (Etherarp*)bp->rp;
479 	memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa));
480 	ipv4local(ifc, e->spa);
481 	memmove(e->sha, ifc->mac, sizeof(e->sha));
482 	memset(e->d, 0xff, sizeof(e->d));		/* ethernet broadcast */
483 	memmove(e->s, ifc->mac, sizeof(e->s));
484 
485 	hnputs(e->type, ETARP);
486 	hnputs(e->hrd, 1);
487 	hnputs(e->pro, ETIP4);
488 	e->hln = sizeof(e->sha);
489 	e->pln = sizeof(e->spa);
490 	hnputs(e->op, ARPREQUEST);
491 	bp->wp += n;
492 
493 	n = devtab[er->achan->type]->bwrite(er->achan, bp, 0);
494 	if(n < 0)
495 		print("arp: send: %r\n");
496 }
497 
498 static void
499 resolveaddr6(Ipifc *ifc, Arpent *a)
500 {
501 	int sflag;
502 	Block *bp;
503 	Etherrock *er = ifc->arg;
504 	uchar ipsrc[IPaddrlen];
505 
506 	/* don't do anything if it's been less than a second since the last */
507 	if(NOW - a->time < ReTransTimer){
508 		arprelease(er->f->arp, a);
509 		return;
510 	}
511 
512 	/* remove all but the last message */
513 	while((bp = a->hold) != nil){
514 		if(bp == a->last)
515 			break;
516 		a->hold = bp->list;
517 		freeblist(bp);
518 	}
519 
520 	/* try to keep it around for a second more */
521 	a->time = NOW;
522 	a->rxtat = NOW + ReTransTimer;
523 	if(a->rxtsrem <= 0) {
524 		arprelease(er->f->arp, a);
525 		return;
526 	}
527 
528 	a->rxtsrem--;
529 	arprelease(er->f->arp, a);
530 
531 	if(sflag = ipv6anylocal(ifc, ipsrc))
532 		icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
533 }
534 
535 /*
536  *  send a gratuitous arp to refresh arp caches
537  */
538 static void
539 sendgarp(Ipifc *ifc, uchar *ip)
540 {
541 	int n;
542 	Block *bp;
543 	Etherarp *e;
544 	Etherrock *er = ifc->arg;
545 
546 	/* don't arp for our initial non address */
547 	if(ipcmp(ip, IPnoaddr) == 0)
548 		return;
549 
550 	n = sizeof(Etherarp);
551 	if(n < ifc->m->mintu)
552 		n = ifc->m->mintu;
553 	bp = allocb(n);
554 	memset(bp->rp, 0, n);
555 	e = (Etherarp*)bp->rp;
556 	memmove(e->tpa, ip+IPv4off, sizeof(e->tpa));
557 	memmove(e->spa, ip+IPv4off, sizeof(e->spa));
558 	memmove(e->sha, ifc->mac, sizeof(e->sha));
559 	memset(e->d, 0xff, sizeof(e->d));		/* ethernet broadcast */
560 	memmove(e->s, ifc->mac, sizeof(e->s));
561 
562 	hnputs(e->type, ETARP);
563 	hnputs(e->hrd, 1);
564 	hnputs(e->pro, ETIP4);
565 	e->hln = sizeof(e->sha);
566 	e->pln = sizeof(e->spa);
567 	hnputs(e->op, ARPREQUEST);
568 	bp->wp += n;
569 
570 	n = devtab[er->achan->type]->bwrite(er->achan, bp, 0);
571 	if(n < 0)
572 		print("garp: send: %r\n");
573 }
574 
575 static void
576 recvarp(Ipifc *ifc)
577 {
578 	int n;
579 	Block *ebp, *rbp;
580 	Etherarp *e, *r;
581 	uchar ip[IPaddrlen];
582 	static uchar eprinted[4];
583 	Etherrock *er = ifc->arg;
584 
585 	ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxtu, 0);
586 	if(ebp == nil) {
587 		print("arp: rcv: %r\n");
588 		return;
589 	}
590 
591 	e = (Etherarp*)ebp->rp;
592 	switch(nhgets(e->op)) {
593 	default:
594 		break;
595 
596 	case ARPREPLY:
597 		/* check for machine using my ip address */
598 		v4tov6(ip, e->spa);
599 		if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
600 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
601 				print("arprep: 0x%E/0x%E also has ip addr %V\n",
602 					e->s, e->sha, e->spa);
603 				break;
604 			}
605 		}
606 
607 		arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0);
608 		break;
609 
610 	case ARPREQUEST:
611 		/* don't answer arps till we know who we are */
612 		if(ifc->lifc == 0)
613 			break;
614 
615 		/* check for machine using my ip or ether address */
616 		v4tov6(ip, e->spa);
617 		if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
618 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
619 				if (memcmp(eprinted, e->spa, sizeof(e->spa))){
620 					/* print only once */
621 					print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa);
622 					memmove(eprinted, e->spa, sizeof(e->spa));
623 				}
624 			}
625 		} else {
626 			if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){
627 				print("arpreq: %V also has ether addr %E\n", e->spa, e->sha);
628 				break;
629 			}
630 		}
631 
632 		/* refresh what we know about sender */
633 		arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1);
634 
635 		/* answer only requests for our address or systems we're proxying for */
636 		v4tov6(ip, e->tpa);
637 		if(!iplocalonifc(ifc, ip))
638 		if(!ipproxyifc(er->f, ifc, ip))
639 			break;
640 
641 		n = sizeof(Etherarp);
642 		if(n < ifc->mintu)
643 			n = ifc->mintu;
644 		rbp = allocb(n);
645 		r = (Etherarp*)rbp->rp;
646 		memset(r, 0, sizeof(Etherarp));
647 		hnputs(r->type, ETARP);
648 		hnputs(r->hrd, 1);
649 		hnputs(r->pro, ETIP4);
650 		r->hln = sizeof(r->sha);
651 		r->pln = sizeof(r->spa);
652 		hnputs(r->op, ARPREPLY);
653 		memmove(r->tha, e->sha, sizeof(r->tha));
654 		memmove(r->tpa, e->spa, sizeof(r->tpa));
655 		memmove(r->sha, ifc->mac, sizeof(r->sha));
656 		memmove(r->spa, e->tpa, sizeof(r->spa));
657 		memmove(r->d, e->sha, sizeof(r->d));
658 		memmove(r->s, ifc->mac, sizeof(r->s));
659 		rbp->wp += n;
660 
661 		n = devtab[er->achan->type]->bwrite(er->achan, rbp, 0);
662 		if(n < 0)
663 			print("arp: write: %r\n");
664 	}
665 	freeb(ebp);
666 }
667 
668 static void
669 recvarpproc(void *v)
670 {
671 	Ipifc *ifc = v;
672 	Etherrock *er = ifc->arg;
673 
674 	er->arpp = up;
675 	if(waserror()){
676 		er->arpp = 0;
677 		pexit("hangup", 1);
678 	}
679 	for(;;)
680 		recvarp(ifc);
681 }
682 
683 static int
684 multicastea(uchar *ea, uchar *ip)
685 {
686 	int x;
687 
688 	switch(x = ipismulticast(ip)){
689 	case V4:
690 		ea[0] = 0x01;
691 		ea[1] = 0x00;
692 		ea[2] = 0x5e;
693 		ea[3] = ip[13] & 0x7f;
694 		ea[4] = ip[14];
695 		ea[5] = ip[15];
696 		break;
697  	case V6:
698  		ea[0] = 0x33;
699  		ea[1] = 0x33;
700  		ea[2] = ip[12];
701 		ea[3] = ip[13];
702  		ea[4] = ip[14];
703  		ea[5] = ip[15];
704  		break;
705 	}
706 	return x;
707 }
708 
709 /*
710  *  fill in an arp entry for broadcast or multicast
711  *  addresses.  Return the first queued packet for the
712  *  IP address.
713  */
714 static Block*
715 multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac)
716 {
717 	/* is it broadcast? */
718 	switch(ipforme(f, a->ip)){
719 	case Runi:
720 		return nil;
721 	case Rbcast:
722 		memset(mac, 0xff, 6);
723 		return arpresolve(f->arp, a, medium, mac);
724 	default:
725 		break;
726 	}
727 
728 	/* if multicast, fill in mac */
729 	switch(multicastea(mac, a->ip)){
730 	case V4:
731 	case V6:
732 		return arpresolve(f->arp, a, medium, mac);
733 	}
734 
735 	/* let arp take care of it */
736 	return nil;
737 }
738 
739 void
740 ethermediumlink(void)
741 {
742 	addipmedium(&ethermedium);
743 	addipmedium(&gbemedium);
744 }
745 
746 
747 static void
748 etherpref2addr(uchar *pref, uchar *ea)
749 {
750 	pref[8]  = ea[0] | 0x2;
751 	pref[9]  = ea[1];
752 	pref[10] = ea[2];
753 	pref[11] = 0xFF;
754 	pref[12] = 0xFE;
755 	pref[13] = ea[3];
756 	pref[14] = ea[4];
757 	pref[15] = ea[5];
758 }
759