vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

arp.c (11314B)


      1 #include "u.h"
      2 #include "lib.h"
      3 #include "mem.h"
      4 #include "dat.h"
      5 #include "fns.h"
      6 #include "error.h"
      7 
      8 #include "ip.h"
      9 #include "ipv6.h"
     10 
     11 /*
     12  *  address resolution tables
     13  */
     14 enum
     15 {
     16 	NHASH		= (1<<6),
     17 	NCACHE		= 256,
     18 
     19 	AOK		= 1,
     20 	AWAIT		= 2,
     21 };
     22 
     23 char *arpstate[] =
     24 {
     25 	"UNUSED",
     26 	"OK",
     27 	"WAIT",
     28 };
     29 
     30 /*
     31  *  one per Fs
     32  */
     33 struct Arp
     34 {
     35 	QLock	qlock;
     36 	Fs	*f;
     37 	Arpent	*hash[NHASH];
     38 	Arpent	cache[NCACHE];
     39 	Arpent	*rxmt;
     40 	Proc	*rxmitp;	/* neib sol re-transmit proc */
     41 	Rendez	rxmtq;
     42 	Block 	*dropf, *dropl;
     43 };
     44 
     45 char *Ebadarp = "bad arp";
     46 
     47 #define haship(s) ((ulong)((s)[IPaddrlen-1])%NHASH)
     48 
     49 int 	ReTransTimer = RETRANS_TIMER;
     50 
     51 static void 	rxmitproc(void *v);
     52 
     53 void
     54 arpinit(Fs *f)
     55 {
     56 	f->arp = smalloc(sizeof(Arp));
     57 	f->arp->f = f;
     58 	f->arp->rxmt = nil;
     59 	f->arp->dropf = f->arp->dropl = nil;
     60 	kproc("rxmitproc", rxmitproc, f->arp);
     61 }
     62 
     63 /*
     64  *  create a new arp entry for an ip address.
     65  */
     66 static Arpent*
     67 newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt)
     68 {
     69 	uint t;
     70 	Block *next, *xp;
     71 	Arpent *a, *e, *f, **l;
     72 	Medium *m = ifc->m;
     73 	int empty;
     74 
     75 	/* find oldest entry */
     76 	e = &arp->cache[NCACHE];
     77 	a = arp->cache;
     78 	t = a->utime;
     79 	for(f = a; f < e; f++){
     80 		if(f->utime < t){
     81 			t = f->utime;
     82 			a = f;
     83 		}
     84 	}
     85 
     86 	/* dump waiting packets */
     87 	xp = a->hold;
     88 	a->hold = nil;
     89 
     90 	if(isv4(a->ip)){
     91 		while(xp){
     92 			next = xp->list;
     93 			freeblist(xp);
     94 			xp = next;
     95 		}
     96 	}
     97 	else { /* queue icmp unreachable for rxmitproc later on, w/o arp lock */
     98 		if(xp){
     99 			if(arp->dropl == nil) 
    100 				arp->dropf = xp;
    101 			else
    102 				arp->dropl->list = xp;
    103 
    104 			for(next = xp->list; next; next = next->list)
    105 				xp = next;
    106 			arp->dropl = xp;
    107 			wakeup(&arp->rxmtq);
    108 		}
    109 	}
    110 
    111 	/* take out of current chain */
    112 	l = &arp->hash[haship(a->ip)];
    113 	for(f = *l; f; f = f->hash){
    114 		if(f == a){
    115 			*l = a->hash;
    116 			break;
    117 		}
    118 		l = &f->hash;
    119 	}
    120 
    121 	/* insert into new chain */
    122 	l = &arp->hash[haship(ip)];
    123 	a->hash = *l;
    124 	*l = a;
    125 
    126 	memmove(a->ip, ip, sizeof(a->ip));
    127 	a->utime = NOW;
    128 	a->ctime = 0;
    129 	a->type = m;
    130 
    131 	a->rtime = NOW + ReTransTimer;
    132 	a->rxtsrem = MAX_MULTICAST_SOLICIT;
    133 	a->ifc = ifc;
    134 	a->ifcid = ifc->ifcid;
    135 
    136 	/* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */
    137 	if(!ipismulticast(a->ip) && addrxt){
    138 		l = &arp->rxmt;
    139 		empty = (*l==nil);
    140 
    141 		for(f = *l; f; f = f->nextrxt){
    142 			if(f == a){
    143 				*l = a->nextrxt;
    144 				break;
    145 			}
    146 			l = &f->nextrxt;
    147 		}
    148 		for(f = *l; f; f = f->nextrxt){
    149 			l = &f->nextrxt;
    150 		}
    151 		*l = a;
    152 		if(empty) 
    153 			wakeup(&arp->rxmtq);
    154 	}
    155 
    156 	a->nextrxt = nil;
    157 
    158 	return a;
    159 }
    160 
    161 /* called with arp qlocked */
    162 
    163 void
    164 cleanarpent(Arp *arp, Arpent *a)
    165 {
    166 	Arpent *f, **l;
    167 
    168 	a->utime = 0;
    169 	a->ctime = 0;
    170 	a->type = 0;
    171 	a->state = 0;
    172 	
    173 	/* take out of current chain */
    174 	l = &arp->hash[haship(a->ip)];
    175 	for(f = *l; f; f = f->hash){
    176 		if(f == a){
    177 			*l = a->hash;
    178 			break;
    179 		}
    180 		l = &f->hash;
    181 	}
    182 
    183 	/* take out of re-transmit chain */
    184 	l = &arp->rxmt;
    185 	for(f = *l; f; f = f->nextrxt){
    186 		if(f == a){
    187 			*l = a->nextrxt;
    188 			break;
    189 		}
    190 		l = &f->nextrxt;
    191 	}
    192 	a->nextrxt = nil;
    193 	a->hash = nil;
    194 	a->hold = nil;
    195 	a->last = nil;
    196 	a->ifc = nil;
    197 }
    198 
    199 /*
    200  *  fill in the media address if we have it.  Otherwise return an
    201  *  Arpent that represents the state of the address resolution FSM
    202  *  for ip.  Add the packet to be sent onto the list of packets
    203  *  waiting for ip->mac to be resolved.
    204  */
    205 Arpent*
    206 arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac)
    207 {
    208 	int hash;
    209 	Arpent *a;
    210 	Medium *type = ifc->m;
    211 	uchar v6ip[IPaddrlen];
    212 
    213 	if(version == V4){
    214 		v4tov6(v6ip, ip);
    215 		ip = v6ip;
    216 	}
    217 
    218 	QLOCK(arp);
    219 	hash = haship(ip);
    220 	for(a = arp->hash[hash]; a; a = a->hash){
    221 		if(memcmp(ip, a->ip, sizeof(a->ip)) == 0)
    222 		if(type == a->type)
    223 			break;
    224 	}
    225 
    226 	if(a == nil){
    227 		a = newarp6(arp, ip, ifc, (version != V4));
    228 		a->state = AWAIT;
    229 	}
    230 	a->utime = NOW;
    231 	if(a->state == AWAIT){
    232 		if(bp != nil){
    233 			if(a->hold)
    234 				a->last->list = bp;
    235 			else
    236 				a->hold = bp;
    237 			a->last = bp;
    238 			bp->list = nil; 
    239 		}
    240 		return a;		/* return with arp qlocked */
    241 	}
    242 
    243 	memmove(mac, a->mac, a->type->maclen);
    244 
    245 	/* remove old entries */
    246 	if(NOW - a->ctime > 15*60*1000)
    247 		cleanarpent(arp, a);
    248 
    249 	QUNLOCK(arp);
    250 	return nil;
    251 }
    252 
    253 /*
    254  * called with arp locked
    255  */
    256 void
    257 arprelease(Arp *arp, Arpent* ae)
    258 {
    259 	QUNLOCK(arp);
    260 }
    261 
    262 /*
    263  * Copy out the mac address from the Arpent.  Return the
    264  * block waiting to get sent to this mac address.
    265  *
    266  * called with arp locked
    267  */
    268 Block*
    269 arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac)
    270 {
    271 	Block *bp;
    272 	Arpent *f, **l;
    273 
    274 	if(!isv4(a->ip)){
    275 		l = &arp->rxmt;
    276 		for(f = *l; f; f = f->nextrxt){
    277 			if(f == a){
    278 				*l = a->nextrxt;
    279 				break;
    280 			}
    281 			l = &f->nextrxt;
    282 		}
    283 	}
    284 
    285 	memmove(a->mac, mac, type->maclen);
    286 	a->type = type;
    287 	a->state = AOK;
    288 	a->utime = NOW;
    289 	bp = a->hold;
    290 	a->hold = nil;
    291 	QUNLOCK(arp);
    292 
    293 	return bp;
    294 }
    295 
    296 void
    297 arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
    298 {
    299 	Arp *arp;
    300 	Route *r;
    301 	Arpent *a, *f, **l;
    302 	Ipifc *ifc;
    303 	Medium *type;
    304 	Block *bp, *next;
    305 	uchar v6ip[IPaddrlen];
    306 
    307 	arp = fs->arp;
    308 
    309 	if(n != 6){
    310 //		print("arp: len = %d\n", n);
    311 		return;
    312 	}
    313 
    314 	switch(version){
    315 	case V4:
    316 		r = v4lookup(fs, ip, nil);
    317 		v4tov6(v6ip, ip);
    318 		ip = v6ip;
    319 		break;
    320 	case V6:
    321 		r = v6lookup(fs, ip, nil);
    322 		break;
    323 	default:
    324 		panic("arpenter: version %d", version);
    325 		return;	/* to supress warnings */
    326 	}
    327 
    328 	if(r == nil){
    329 //		print("arp: no route for entry\n");
    330 		return;
    331 	}
    332 
    333 	ifc = r->ifc;
    334 	type = ifc->m;
    335 
    336 	QLOCK(arp);
    337 	for(a = arp->hash[haship(ip)]; a; a = a->hash){
    338 		if(a->type != type || (a->state != AWAIT && a->state != AOK))
    339 			continue;
    340 
    341 		if(ipcmp(a->ip, ip) == 0){
    342 			a->state = AOK;
    343 			memmove(a->mac, mac, type->maclen);
    344 
    345 			if(version == V6){
    346 				/* take out of re-transmit chain */
    347 				l = &arp->rxmt;
    348 				for(f = *l; f; f = f->nextrxt){
    349 					if(f == a){
    350 						*l = a->nextrxt;
    351 						break;
    352 					}
    353 					l = &f->nextrxt;
    354 				}
    355 			}
    356 
    357 			a->ifc = ifc;
    358 			a->ifcid = ifc->ifcid;
    359 			bp = a->hold;
    360 			a->hold = nil;
    361 			if(version == V4)
    362 				ip += IPv4off;
    363 			a->utime = NOW;
    364 			a->ctime = a->utime;
    365 			QUNLOCK(arp);
    366 
    367 			while(bp){
    368 				next = bp->list;
    369 				if(ifc != nil){
    370 					if(waserror()){
    371 						RUNLOCK(ifc);
    372 						nexterror();
    373 					}
    374 					RLOCK(ifc);
    375 					if(ifc->m != nil)
    376 						ifc->m->bwrite(ifc, bp, version, ip);
    377 					else
    378 						freeb(bp);
    379 					RUNLOCK(ifc);
    380 					poperror();
    381 				} else
    382 					freeb(bp);
    383 				bp = next;
    384 			}
    385 			return;
    386 		}
    387 	}
    388 
    389 	if(refresh == 0){
    390 		a = newarp6(arp, ip, ifc, 0);
    391 		a->state = AOK;
    392 		a->type = type;
    393 		a->ctime = NOW;
    394 		memmove(a->mac, mac, type->maclen);
    395 	}
    396 
    397 	QUNLOCK(arp);
    398 }
    399 
    400 int
    401 arpwrite(Fs *fs, char *s, int len)
    402 {
    403 	int n;
    404 	Route *r;
    405 	Arp *arp;
    406 	Block *bp;
    407 	Arpent *a, *fl, **l;
    408 	Medium *m;
    409 	char *f[4], buf[256];
    410 	uchar ip[IPaddrlen], mac[MAClen];
    411 
    412 	arp = fs->arp;
    413 
    414 	if(len == 0)
    415 		error(Ebadarp);
    416 	if(len >= sizeof(buf))
    417 		len = sizeof(buf)-1;
    418 	strncpy(buf, s, len);
    419 	buf[len] = 0;
    420 	if(len > 0 && buf[len-1] == '\n')
    421 		buf[len-1] = 0;
    422 
    423 	n = getfields(buf, f, 4, 1, " ");
    424 	if(strcmp(f[0], "flush") == 0){
    425 		QLOCK(arp);
    426 		for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
    427 			memset(a->ip, 0, sizeof(a->ip));
    428 			memset(a->mac, 0, sizeof(a->mac));
    429 			a->hash = nil;
    430 			a->state = 0;
    431 			a->utime = 0;
    432 			while(a->hold != nil){
    433 				bp = a->hold->list;
    434 				freeblist(a->hold);
    435 				a->hold = bp;
    436 			}
    437 		}
    438 		memset(arp->hash, 0, sizeof(arp->hash));
    439 		/* clear all pkts on these lists (rxmt, dropf/l) */
    440 		arp->rxmt = nil;
    441 		arp->dropf = nil;
    442 		arp->dropl = nil;
    443 		QUNLOCK(arp);
    444 	} else if(strcmp(f[0], "add") == 0){
    445 		switch(n){
    446 		default:
    447 			error(Ebadarg);
    448 		case 3:
    449 			if (parseip(ip, f[1]) == -1)
    450 				error(Ebadip);
    451 			if(isv4(ip))
    452 				r = v4lookup(fs, ip+IPv4off, nil);
    453 			else
    454 				r = v6lookup(fs, ip, nil);
    455 			if(r == nil)
    456 				error("Destination unreachable");
    457 			m = r->ifc->m;
    458 			n = parsemac(mac, f[2], m->maclen);
    459 			break;
    460 		case 4:
    461 			m = ipfindmedium(f[1]);
    462 			if(m == nil)
    463 				error(Ebadarp);
    464 			if (parseip(ip, f[2]) == -1)
    465 				error(Ebadip);
    466 			n = parsemac(mac, f[3], m->maclen);
    467 			break;
    468 		}
    469 
    470 		if(m->ares == nil)
    471 			error(Ebadarp);
    472 
    473 		m->ares(fs, V6, ip, mac, n, 0);
    474 	} else if(strcmp(f[0], "del") == 0){
    475 		if(n != 2)
    476 			error(Ebadarg);
    477 
    478 		if (parseip(ip, f[1]) == -1)
    479 			error(Ebadip);
    480 		QLOCK(arp);
    481 
    482 		l = &arp->hash[haship(ip)];
    483 		for(a = *l; a; a = a->hash){
    484 			if(memcmp(ip, a->ip, sizeof(a->ip)) == 0){
    485 				*l = a->hash;
    486 				break;
    487 			}
    488 			l = &a->hash;
    489 		}
    490 	
    491 		if(a){
    492 			/* take out of re-transmit chain */
    493 			l = &arp->rxmt;
    494 			for(fl = *l; fl; fl = fl->nextrxt){
    495 				if(fl == a){
    496 					*l = a->nextrxt;
    497 					break;
    498 				}
    499 				l = &fl->nextrxt;
    500 			}
    501 
    502 			a->nextrxt = nil;
    503 			a->hash = nil;
    504 			a->hold = nil;
    505 			a->last = nil;
    506 			a->ifc = nil;
    507 			memset(a->ip, 0, sizeof(a->ip));
    508 			memset(a->mac, 0, sizeof(a->mac));
    509 		}
    510 		QUNLOCK(arp);
    511 	} else
    512 		error(Ebadarp);
    513 
    514 	return len;
    515 }
    516 
    517 enum
    518 {
    519 	Alinelen=	90,
    520 };
    521 
    522 char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n";
    523 
    524 static void
    525 convmac(char *p, uchar *mac, int n)
    526 {
    527 	while(n-- > 0)
    528 		p += sprint(p, "%2.2ux", *mac++);
    529 }
    530 
    531 int
    532 arpread(Arp *arp, char *p, ulong offset, int len)
    533 {
    534 	Arpent *a;
    535 	int n;
    536 	char mac[2*MAClen+1];
    537 
    538 	if(offset % Alinelen)
    539 		return 0;
    540 
    541 	offset = offset/Alinelen;
    542 	len = len/Alinelen;
    543 
    544 	n = 0;
    545 	for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){
    546 		if(a->state == 0)
    547 			continue;
    548 		if(offset > 0){
    549 			offset--;
    550 			continue;
    551 		}
    552 		len--;
    553 		QLOCK(arp);
    554 		convmac(mac, a->mac, a->type->maclen);
    555 		n += sprint(p+n, aformat, a->type->name, arpstate[a->state], a->ip, mac);
    556 		QUNLOCK(arp);
    557 	}
    558 
    559 	return n;
    560 }
    561 
    562 extern int
    563 rxmitsols(Arp *arp)
    564 {
    565 	uint sflag;
    566 	Block *next, *xp;
    567 	Arpent *a, *b, **l;
    568 	Fs *f;
    569 	uchar ipsrc[IPaddrlen];
    570 	Ipifc *ifc = nil;
    571 	long nrxt;
    572 
    573 	QLOCK(arp);
    574 	f = arp->f;
    575 
    576 	a = arp->rxmt;
    577 	if(a==nil){
    578 		nrxt = 0;
    579 		goto dodrops; 		/* return nrxt; */
    580 	}
    581 	nrxt = a->rtime - NOW;
    582 	if(nrxt > 3*ReTransTimer/4) 
    583 		goto dodrops; 		/* return nrxt; */
    584 
    585 	for(; a; a = a->nextrxt){
    586 		ifc = a->ifc;
    587 		assert(ifc != nil);
    588 		if((a->rxtsrem <= 0) || !(CANRLOCK(ifc)) || (a->ifcid != ifc->ifcid)){
    589 			xp = a->hold;
    590 			a->hold = nil;
    591 
    592 			if(xp){
    593 				if(arp->dropl == nil) 
    594 					arp->dropf = xp;
    595 				else
    596 					arp->dropl->list = xp;
    597 			}
    598 
    599 			cleanarpent(arp, a);
    600 		}
    601 		else
    602 			break;
    603 	}
    604 	if(a == nil)
    605 		goto dodrops;
    606 
    607 
    608 	QUNLOCK(arp);	/* for icmpns */
    609 	if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC) 
    610 		icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac); 
    611 
    612 	RUNLOCK(ifc);
    613 	QLOCK(arp);
    614 
    615 	/* put to the end of re-transmit chain */
    616 	l = &arp->rxmt;
    617 	for(b = *l; b; b = b->nextrxt){
    618 		if(b == a){
    619 			*l = a->nextrxt;
    620 			break;
    621 		}
    622 		l = &b->nextrxt;
    623 	}
    624 	for(b = *l; b; b = b->nextrxt){
    625 		l = &b->nextrxt;
    626 	}
    627 	*l = a;
    628 	a->rxtsrem--;
    629 	a->nextrxt = nil;
    630 	a->rtime = NOW + ReTransTimer;
    631 
    632 	a = arp->rxmt;
    633 	if(a==nil)
    634 		nrxt = 0;
    635 	else 
    636 		nrxt = a->rtime - NOW;
    637 
    638 dodrops:
    639 	xp = arp->dropf;
    640 	arp->dropf = nil;
    641 	arp->dropl = nil;
    642 	QUNLOCK(arp);
    643 
    644 	for(; xp; xp = next){
    645 		next = xp->list;
    646 		icmphostunr(f, ifc, xp, Icmp6_adr_unreach, 1);
    647 	}
    648 
    649 	return nrxt;
    650 
    651 }
    652 
    653 static int
    654 rxready(void *v)
    655 {
    656 	Arp *arp = (Arp *) v;
    657 	int x;
    658 
    659 	x = ((arp->rxmt != nil) || (arp->dropf != nil));
    660 
    661 	return x;
    662 }
    663 
    664 static void
    665 rxmitproc(void *v)
    666 {
    667 	Arp *arp = v;
    668 	long wakeupat;
    669 
    670 	arp->rxmitp = up;
    671 	//print("arp rxmitproc started\n");
    672 	if(waserror()){
    673 		arp->rxmitp = 0;
    674 		pexit("hangup", 1);
    675 	}
    676 	for(;;){
    677 		wakeupat = rxmitsols(arp);
    678 		if(wakeupat == 0) 
    679 			sleep(&arp->rxmtq, rxready, v); 
    680 		else if(wakeupat > ReTransTimer/4) 
    681 			tsleep(&arp->rxmtq, return0, 0, wakeupat); 
    682 	}
    683 }
    684