henesyinit from p9fd787fda5 years agoHistory
1454 lines · 27.1 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <ip.h>#include "dhcp.h" int	noconfig;int	debug;int	dodhcp;int	nip;int	myifc;int	plan9 = 1;Ipifc	*ifc; // possible verbsenum{	Vadd,	Vremove,	Vunbind}; struct {	// locally generated	char	*type;	char	*dev;	char	mpoint[32];	int	cfd;			// ifc control channel	int	dfd;			// ifc data channel (for ppp)	char	*cputype;	uchar	hwa[32];		// hardware address	int	hwatype;	int	hwalen;	uchar	cid[32];	int	cidlen;	char	*baud; 	// learned info	uchar	gaddr[IPaddrlen];	uchar	laddr[IPaddrlen];	uchar	mask[IPaddrlen];	uchar	raddr[IPaddrlen];	uchar	dns[2*IPaddrlen];	uchar	fs[2*IPaddrlen];	uchar	auth[2*IPaddrlen];	uchar	ntp[IPaddrlen];	int	mtu; 	// dhcp specific	int	state;	int	fd;	ulong	xid;	ulong	starttime;	char	sname[64];	char	hostname[32];	char	domainname[64];	uchar	server[IPaddrlen];	/* server IP address */	ulong	offered;		/* offered lease time */	ulong	lease;			/* lease time */	ulong	resend;			/* number of resends for current state */	ulong	timeout;		/* time to timeout - seconds */} conf; void	adddefroute(char*, uchar*);void	binddevice(void);void	controldevice(void);void	bootprequest(void);void	dhcprecv(void);void	dhcpsend(int);int	dhcptimer(void);void	dhcpquery(int, int);void	dhcpwatch(int);int	getndb(void);int	ipconfig(void);void	lookforip(char*);uchar	*optadd(uchar*, int, void*, int);uchar	*optaddbyte(uchar*, int, int);uchar	*optaddulong(uchar*, int, ulong);uchar	*optaddaddr(uchar*, int, uchar*);uchar	*optaddstr(uchar*, int, char*);uchar	*optaddvec(uchar*, int, uchar*, int);uchar	*optget(uchar*, int, int*);int	optgetbyte(uchar*, int);ulong	optgetulong(uchar*, int);int	optgetaddr(uchar*, int, uchar*);int	optgetaddrs(uchar*, int, uchar*, int);int	optgetstr(uchar*, int, char*, int);int	optgetvec(uchar*, int, uchar*, int);void	mkclientid(void);int	nipifcs(char*);int	openlisten(void);int	parseoptions(uchar *p, int n);Bootp	*parsebootp(uchar*, int);void	putndb(void);void	tweakservers(void);void	writendb(char*, int, int);void	usage(void);int	validip(uchar*);int	parseverb(char*);void	doadd(int);void	doremove(void);void	dounbind(void); char optmagic[4] = { 0x63, 0x82, 0x53, 0x63 }; #define DEBUG if(debug)print typedef struct Ctl Ctl;struct Ctl{	Ctl	*next;	char	*ctl;};Ctl *firstctl, **ctll; voidusage(void){	fprint(2, "usage: %s [-ndDrG] [-x netmtpt] [-m mtu] [-b baud] [-g gateway] [-h hostname] [-c control-string]* type device [verb] [localaddr [mask [remoteaddr [fsaddr [authaddr]]]]]\n", argv0);	exits("usage");} voidmain(int argc, char **argv){	char *p;	int retry, verb;	Ctl *cp; 	srand(truerand());	fmtinstall('E', eipfmt);	fmtinstall('I', eipfmt);	fmtinstall('M', eipfmt);	fmtinstall('V', eipfmt); 	setnetmtpt(conf.mpoint, sizeof(conf.mpoint), nil);	conf.cputype = getenv("cputype");	if(conf.cputype == nil)		conf.cputype = "386"; 	retry = 0;	ctll = &firstctl; 	ARGBEGIN {	case 'c':		p = ARGF();		if(p == nil)			usage();		cp = malloc(sizeof(*cp));		if(cp == nil)			sysfatal("%r");		*ctll = cp;		ctll = &cp->next;		cp->next = nil;		cp->ctl = p;		break;	case 'D':		debug = 1;		break;	case 'd':		dodhcp = 1;		break;	case 'h':		p = ARGF();		if(p == nil)			usage();		snprint(conf.hostname, sizeof(conf.hostname), "%s", p);		break;	case 'n':		noconfig = 1;		break;	case 'm':		p = ARGF();		if(p == nil)			usage();		conf.mtu = atoi(p);		break;	case 'x':		p = ARGF();		if(p == nil)			usage();		setnetmtpt(conf.mpoint, sizeof(conf.mpoint), p);		break;	case 'g':		p = ARGF();		if(p == nil)			usage();		parseip(conf.gaddr, p);		break;	case 'b':		p = ARGF();		if(p == nil)			usage();		conf.baud = p;		break;	case 'r':		retry = 1;		break;	case 'G':		plan9 = 0;		break;	} ARGEND; 	// get medium, default is ether	switch(argc){	default:		conf.dev = argv[1];		conf.type = argv[0];		argc -= 2;		argv += 2;		break;	case 1:		conf.type = argv[0];		if(strcmp(conf.type, "ether") == 0)			conf.dev = "/net/ether0";		else if(strcmp(conf.type, "ppp") == 0)			conf.dev = "/dev/eia0";		else			usage();		argc -= 1;		argv += 1;		break;	case 0:		conf.type = "ether";		conf.dev = "/net/ether0";		break;	} 	// get verb, default is "add"	verb = Vadd;	if(argc > 0){		verb = parseverb(argv[0]);		if(verb >= 0){			argc--;			argv++;		} else			verb = Vadd;	} 	// get addresses	switch(argc){	case 5:		parseip(conf.auth, argv[4]);		/* fall through */	case 4:		parseip(conf.fs, argv[3]);		/* fall through */	case 3:		parseip(conf.raddr, argv[2]);		/* fall through */	case 2:		parseipmask(conf.mask, argv[1]);		/* fall through */	case 1:		parseip(conf.laddr, argv[0]);		break;	} 	switch(verb){	case Vadd:		doadd(retry);		break;	case Vremove:		doremove();		break;	case Vunbind:		dounbind();		break;	} 	exits(0);} voiddoadd(int retry){	int tries; 	// get number of preexisting interfaces	nip = nipifcs(conf.mpoint); 	// get ipifc into name space and condition device for ip	if(!noconfig){		lookforip(conf.mpoint);		controldevice();		binddevice();	} 	if(!validip(conf.laddr) && strcmp(conf.type, "ppp") != 0)		dodhcp = 1; 	// run dhcp if we need something	if(dodhcp){		mkclientid();		for(tries = 0; tries < 6; tries++){			dhcpquery(!noconfig, Sselecting);			if(conf.state == Sbound)				break;			sleep(1000);		}	} 	if(!validip(conf.laddr)){		if(retry && dodhcp && !noconfig){			fprint(2, "%s: couldn't determine ip address, retrying\n", argv0);			dhcpwatch(1);			return;		} else {			fprint(2, "%s: no success with DHCP\n", argv0);			exits("failed");		}	} 	if(!noconfig){		if(ipconfig() < 0)			sysfatal("can't start ip");		if(dodhcp && conf.lease != Lforever)			dhcpwatch(0);	} 	// leave everything we've learned somewhere other procs can find it	if(nip == 0){		putndb();		tweakservers();	}} voiddoremove(void){	char file[128];	int cfd;	Ipifc *nifc;	Iplifc *lifc; 	if(!validip(conf.laddr)){		fprint(2, "%s: remove requires an address\n", argv0);		exits("usage");	} 	ifc = readipifc(conf.mpoint, ifc, -1);	for(nifc = ifc; nifc != nil; nifc = nifc->next){		if(strcmp(nifc->dev, conf.dev) != 0)			continue;		for(lifc = nifc->lifc; lifc != nil; lifc = lifc->next){			if(ipcmp(conf.laddr, lifc->ip) != 0)				continue;			if(validip(conf.mask) && ipcmp(conf.mask, lifc->mask) != 0)				continue;			if(validip(conf.raddr) && ipcmp(conf.raddr, lifc->net) != 0)				continue; 			snprint(file, sizeof(file), "%s/ipifc/%d/ctl", conf.mpoint, nifc->index);			cfd = open(file, ORDWR);			if(cfd < 0){				fprint(2, "%s: can't open %s: %r\n", argv0, conf.mpoint);				continue;			}			if(fprint(cfd, "remove %I %I", lifc->ip, lifc->mask) < 0)				fprint(2, "%s: can't remove %I %I from %s: %r\n", argv0,					lifc->ip, lifc->mask, file);		}	}} voiddounbind(void){	Ipifc *nifc;	char file[128];	int cfd; 	ifc = readipifc(conf.mpoint, ifc, -1);	for(nifc = ifc; nifc != nil; nifc = nifc->next){		if(strcmp(nifc->dev, conf.dev) == 0){			snprint(file, sizeof(file), "%s/ipifc/%d/ctl", conf.mpoint, nifc->index);			cfd = open(file, ORDWR);			if(cfd < 0){				fprint(2, "%s: can't open %s: %r\n", argv0, conf.mpoint);				break;			}			if(fprint(cfd, "unbind") < 0)				fprint(2, "%s: can't unbind from %s: %r\n", argv0, file);			break;		}	}} // set the default routevoidadddefroute(char *mpoint, uchar *gaddr){	char buf[256];	int cfd; 	sprint(buf, "%s/iproute", mpoint);	cfd = open(buf, ORDWR);	if(cfd < 0)		return;	fprint(cfd, "add 0 0 %I", gaddr);	close(cfd);} // create a client idvoidmkclientid(void){	if(strcmp(conf.type, "ether") == 0)	if(myetheraddr(conf.hwa, conf.dev) == 0){		conf.hwalen = 6;		conf.hwatype = 1;		conf.cid[0] = conf.hwatype;		memmove(&conf.cid[1], conf.hwa, conf.hwalen);		conf.cidlen = conf.hwalen+1;	} else {		conf.hwatype = -1;		snprint((char*)conf.cid, sizeof(conf.cid), "plan9_%ld.%d", lrand(), getpid());		conf.cidlen = strlen((char*)conf.cid);	}} // bind ip into the namespacevoidlookforip(char *net){	char proto[64]; 	snprint(proto, sizeof(proto), "%s/ipifc", net);	if(access(proto, 0) == 0)		return;	sysfatal("no ip stack bound onto %s", net);} // send some ctls to a devicevoidcontroldevice(void){	char ctlfile[256];	int fd;	Ctl *cp; 	if(firstctl == nil)		return; 	if(strcmp(conf.type, "ether") == 0)		snprint(ctlfile, sizeof(ctlfile), "%s/clone", conf.dev);	else		return; 	fd = open(ctlfile, ORDWR);	if(fd < 0)		sysfatal("can't open %s", ctlfile); 	for(cp = firstctl; cp != nil; cp = cp->next){		if(write(fd, cp->ctl, strlen(cp->ctl)) < 0)			sysfatal("ctl message %s: %r", cp->ctl);		seek(fd, 0, 0);	}} // bind an ip stack to a device, leave the control channel openvoidbinddevice(void){	char buf[256];	int ac, pid;	char *av[12];	Waitmsg *w; 	if(strcmp(conf.type, "ppp") == 0){		// ppp does the binding 		// start with an empty config file		if(nip == 0)			writendb("", 0, 0); 		switch(pid = rfork(RFPROC|RFFDG|RFMEM)){		case -1:			sysfatal("can't start ppp: %r");			break;		case 0:			ac = 0;			av[ac++] = "ppp";			av[ac++] = "-uf";			av[ac++] = "-p";			av[ac++] = conf.dev;			av[ac++] = "-x";			av[ac++] = conf.mpoint;			if(conf.baud != nil){				av[ac++] = "-b";				av[ac++] = conf.baud;			}			av[ac] = 0;			exec("/bin/ip/ppp", av);			exec("/ppp", av);			sysfatal("execing /ppp: %r");		default:			break;		} 		// wait for ppp to finish connecting and configuring

Lines 1–500 of 1454.