/*
 * NAME
 *  dpconfig - configure dp interaces into the system
 * SYNOPSIS:
 *	dpconfig [ -va ] dpinterface [ attach ] [ detach ] [ plumb ] [ unplumb ]
 *
 * Open dp psuedo device
 * Issue ioctl's to attach or detach individual ppa's.
 */

#include	<stdio.h>
#include	<ctype.h>
#include	<malloc.h>

#include	<sys/types.h>
#include	<sys/sockio.h>
#include	<sys/stropts.h>
#include	<sys/dlpi.h>

#include	<sys/socket.h>
#include	<net/if.h>

#include	"ppp.h"
#include	"dpio.h"
#include	"dpconf.h"

extern	char	*optarg;
extern	int	optind;

char IP_DEV[] = "/dev/ip";
char IP_MOD[] = "ip";

char dev[32];

int verbose,
    all,
    attach,
    detach,
    plumb,
    unplumb;

struct cmdopts {
    char *opt;
    int *flag;
};

struct cmdopts cmdopts[] = {
    { "attach",  &attach  },
    { "detach",  &detach  },
    { "plumb",   &plumb   },
    { "unplumb", &unplumb },
    0
};

char *argv0;

main(argc, argv)
int	argc;
char	*argv[];
{
    extern int optind;
    int dpmux,
	ppa,
	cmd;
    char *cmdstr;
    int c;
    char *iname, *i, *d, *opt;
    struct cmdopts *co;

    argv0 = *argv;
    
    while ((c = getopt(argc, argv, "va")) != -1)
	switch (c) {
	 case 'v':
	    verbose++;
	    break;
	 case 'a':
	    all++;
	    break;
	 default:
	    usage(argv0);
	    break;
	}

    argv += optind;
    argc -= optind;

    if (argc == 0)
	usage(argv0);

    argc--;
    iname = *argv++;
    (void)strcpy(dev, "/dev/");
    i = iname;
    d = dev + strlen(dev);
    while (!isdigit(*i))
	*d++ = *i++;
    *d = '\0';

    ppa = atoi(i);

    while (argc-- > 0) {
	opt  = *argv++;
	for (co = cmdopts ; co->opt ; co++)
	    if (strcmp(co->opt, opt) == 0) {
		*(co->flag) = 1;
		break;
	    }
	if (!co->opt) {
	    fprintf(stderr, "%s: %s: unrecognized flag\n", argv0, opt);
	    usage(argv0);
	}
    }


    if ((dpmux = open(dev, 2)) < 0)
	syserr(dev);

    if (all) {
	ppa = -1;
	if (attach)
	    usage(argv0);
    }

    if (attach) {
	doattach(dpmux, DPIOCIFATTACH, ppa, "ioctl(DPIOCIFATTACH)");
    }

    if (plumb)
	doplumb(dpmux, iname, ppa);
    if (unplumb)
	dounplumb(dpmux, iname, ppa);

    if (detach) {
	doattach(dpmux, DPIOCIFDETACH, ppa, "ioctl(DPIOCIFDETACH)");
    }
}

doattach(dpmux, cmd, ppa, cmdstr)
int dpmux,
    cmd,
    ppa;
char *cmdstr;
{
    if (strioctl(dpmux, cmd, -1, sizeof(int), (caddr_t)&ppa) < 0)
	syserr(cmdstr);
}

char *muxfn(proto, interface)
char *proto,
     *interface;
{
    char *muxbuf, *muxf;

    muxbuf = malloc(strlen(proto) + 1 + strlen(interface) + 1);
    (void)sprintf(muxbuf, "%s.%s", proto, interface);

    muxf = expand_dir_file("$DPMUX_DIR", muxbuf); 

    (void)free(muxbuf);

    return muxf;
}

doplumb(dpmux, iname, ppa)
int dpmux;
char *iname;
int ppa;
{
    int ipmux,
	muxid;
    char *muxf;
    FILE *muxfp;
    struct ifreq ifr;

    if ((ipmux = open(IP_DEV, 2)) < 0)
	syserr(IP_DEV);

    if (ioctl(dpmux, I_PUSH, IP_MOD) < 0)
	syserr("ioctl(I_PUSH, \"ip\")");

    if (ioctl(dpmux, IF_UNITSEL, (caddr_t)&ppa) < 0) 
	syserr("ioctl(IF_UNITSEL)");

    if ((muxid = ioctl(ipmux, I_PLINK, dpmux)) < 0)
	syserr("ioctl(I_PLINK)");

    if (verbose)
	printf("%s: plumb: muxid = %d\n", argv0, muxid);

    muxf = muxfn("ip", iname);
    if (!(muxfp = fopen(muxf, "w")))
	syserr(muxf);
    (void)fprintf(muxfp, "%d\n", muxid);
    (void)fclose(muxfp);
    (void)free(muxf);

    (void)close(ipmux);
}

dounplumb(dpmux, iname, ppa)
int dpmux;
char *iname;
int ppa;
{
    int ipmux,
	muxid;
    char *muxf;
    FILE *muxfp;
    struct ifreq ifr;


    muxf = muxfn("ip", iname);
    if (!(muxfp = fopen(muxf, "r")))
	syserr(muxf);
    (void)fscanf(muxfp, "%d", &muxid);
    (void)fclose(muxfp);

    if (verbose)
	printf("%s: unplumb: muxid = %d\n", argv0, muxid);

    if ((ipmux = open(IP_DEV, 2)) < 0)
	syserr(IP_DEV);

    if (ioctl(ipmux, I_PUNLINK, muxid) < 0)
	syserr("ioctl(I_PUNLINK)");

    (void)unlink(muxf);

    (void)close(ipmux);
    (void)free(muxf);
}

usage(av0)
char	*av0;
{
    (void) fprintf(stderr, "%s:  ", av0);
    (void) fprintf(stderr,
    "%s [ -va ] dpinterface [ attach | detach ] [ plumb | unplumb ]\n",
		   av0);
    (void) exit(1);
}

syserr(s)
char	*s;
{
	(void) perror(s);
	exit(1);
}

strioctl(fd, cmd, timout, len, dp)
int	fd;
int	cmd;
int	timout;
int	len;
char	*dp;
{
	struct	strioctl	sioc;
	int	rc;

	sioc.ic_cmd = cmd;
	sioc.ic_timout = timout;
	sioc.ic_len = len;
	sioc.ic_dp = dp;
	rc = ioctl(fd, I_STR, &sioc);

	if (rc < 0)
		return (rc);
	else
		return (sioc.ic_len);
}
