Ejemplo n.º 1
0
static void
setifipdst(const char *addr, int dummy __unused, int s,
    const struct afswtch *afp)
{
	const struct afswtch *inet;

	inet = af_getbyname("inet");
	if (inet == NULL)
		return;
	inet->af_getaddr(addr, DSTADDR);
	clearaddr = 0;
	newaddr = 0;
}
Ejemplo n.º 2
0
/*
 * Print the status of the interface.  If an address family was
 * specified, show only it; otherwise, show them all.
 */
static void
status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
	struct ifaddrs *ifa)
{
	struct ifaddrs *ift;
	int allfamilies, s;
	struct ifstat ifs;

	if (afp == NULL) {
		allfamilies = 1;
		ifr.ifr_addr.sa_family = AF_LOCAL;
	} else {
		allfamilies = 0;
		ifr.ifr_addr.sa_family =
		    afp->af_af == AF_LINK ? AF_LOCAL : afp->af_af;
	}
	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));

	s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
	if (s < 0)
		err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);

	printf("%s: ", name);
	printb("flags", ifa->ifa_flags, IFFBITS);
	if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1)
		printf(" metric %d", ifr.ifr_metric);
	if (ioctl(s, SIOCGIFMTU, &ifr) != -1)
		printf(" mtu %d", ifr.ifr_mtu);
	putchar('\n');

	for (;;) {
		if ((descr = reallocf(descr, descrlen)) != NULL) {
			ifr.ifr_buffer.buffer = descr;
			ifr.ifr_buffer.length = descrlen;
			if (ioctl(s, SIOCGIFDESCR, &ifr) == 0) {
				if (ifr.ifr_buffer.buffer == descr) {
					if (strlen(descr) > 0)
						printf("\tdescription: %s\n",
						    descr);
				} else if (ifr.ifr_buffer.length > descrlen) {
					descrlen = ifr.ifr_buffer.length;
					continue;
				}
			}
		} else
			warn("unable to allocate memory for interface"
			    "description");
		break;
	}

	if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
		if (ifr.ifr_curcap != 0) {
			printb("\toptions", ifr.ifr_curcap, IFCAPBITS);
			putchar('\n');
		}
		if (supmedia && ifr.ifr_reqcap != 0) {
			printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
			putchar('\n');
		}
	}

	tunnel_status(s);

	for (ift = ifa; ift != NULL; ift = ift->ifa_next) {
		if (ift->ifa_addr == NULL)
			continue;
		if (strcmp(ifa->ifa_name, ift->ifa_name) != 0)
			continue;
		if (allfamilies) {
			const struct afswtch *p;
			p = af_getbyfamily(ift->ifa_addr->sa_family);
			if (p != NULL && p->af_status != NULL)
				p->af_status(s, ift);
		} else if (afp->af_af == ift->ifa_addr->sa_family)
			afp->af_status(s, ift);
	}
#if 0
	if (allfamilies || afp->af_af == AF_LINK) {
		const struct afswtch *lafp;

		/*
		 * Hack; the link level address is received separately
		 * from the routing information so any address is not
		 * handled above.  Cobble together an entry and invoke
		 * the status method specially.
		 */
		lafp = af_getbyname("lladdr");
		if (lafp != NULL) {
			info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
			lafp->af_status(s, &info);
		}
	}
#endif
	if (allfamilies)
		af_other_status(s);
	else if (afp->af_other_status != NULL)
		afp->af_other_status(s);

	strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
	if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) 
		printf("%s", ifs.ascii);

	close(s);
	return;
}
Ejemplo n.º 3
0
static int
ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp)
{
	const struct afswtch *afp, *nafp;
	const struct cmd *p;
	struct callback *cb;
	int s;

	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
	afp = uafp != NULL ? uafp : af_getbyname("inet");
top:
	ifr.ifr_addr.sa_family =
		afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
		AF_LOCAL : afp->af_af;

	if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0 &&
	    (uafp != NULL || errno != EPROTONOSUPPORT ||
	     (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0))
		err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);

	while (argc > 0) {
		p = cmd_lookup(*argv, iscreate);
		if (iscreate && p == NULL) {
			/*
			 * Push the clone create callback so the new
			 * device is created and can be used for any
			 * remaining arguments.
			 */
			cb = callbacks;
			if (cb == NULL)
				errx(1, "internal error, no callback");
			callbacks = cb->cb_next;
			cb->cb_func(s, cb->cb_arg);
			iscreate = 0;
			/*
			 * Handle any address family spec that
			 * immediately follows and potentially
			 * recreate the socket.
			 */
			nafp = af_getbyname(*argv);
			if (nafp != NULL) {
				argc--, argv++;
				if (nafp != afp) {
					close(s);
					afp = nafp;
					goto top;
				}
			}
			/*
			 * Look for a normal parameter.
			 */
			continue;
		}
		if (p == NULL) {
			/*
			 * Not a recognized command, choose between setting
			 * the interface address and the dst address.
			 */
			p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd);
		}
		if (p->c_u.c_func || p->c_u.c_func2) {
			if (p->c_parameter == NEXTARG) {
				if (argv[1] == NULL)
					errx(1, "'%s' requires argument",
					    p->c_name);
				p->c_u.c_func(argv[1], 0, s, afp);
				argc--, argv++;
			} else if (p->c_parameter == OPTARG) {
				p->c_u.c_func(argv[1], 0, s, afp);
				if (argv[1] != NULL)
					argc--, argv++;
			} else if (p->c_parameter == NEXTARG2) {
				if (argc < 3)
					errx(1, "'%s' requires 2 arguments",
					    p->c_name);
				p->c_u.c_func2(argv[1], argv[2], s, afp);
				argc -= 2, argv += 2;
			} else
				p->c_u.c_func(*argv, p->c_parameter, s, afp);
		}
		argc--, argv++;
	}

	/*
	 * Do any post argument processing required by the address family.
	 */
	if (afp->af_postproc != NULL)
		afp->af_postproc(s, afp);
	/*
	 * Do deferred callbacks registered while processing
	 * command-line arguments.
	 */
	for (cb = callbacks; cb != NULL; cb = cb->cb_next)
		cb->cb_func(s, cb->cb_arg);
	/*
	 * Do deferred operations.
	 */
	if (clearaddr) {
		if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
			warnx("interface %s cannot change %s addresses!",
			      name, afp->af_name);
			clearaddr = 0;
		}
	}
	if (clearaddr) {
		int ret;
		strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
		ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
		if (ret < 0) {
			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
				/* means no previous address for interface */
			} else
				Perror("ioctl (SIOCDIFADDR)");
		}
	}
	if (newaddr) {
		if (afp->af_addreq == NULL || afp->af_aifaddr == 0) {
			warnx("interface %s cannot change %s addresses!",
			      name, afp->af_name);
			newaddr = 0;
		}
	}
	if (newaddr && (setaddr || setmask)) {
		strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
		if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
			Perror("ioctl (SIOCAIFADDR)");
	}

	close(s);
	return(0);
}
Ejemplo n.º 4
0
int
main(int argc, char *argv[])
#endif
{
	int c, all, namesonly, downonly, uponly;
	const struct afswtch *afp = NULL;
	int ifindex;
	struct ifaddrs *ifap, *ifa;
	struct ifreq paifr;
	const struct sockaddr_dl *sdl;
	char options[1024], *cp;
	const char *ifname;
#ifdef __rtems__
	struct ifconfig_option *p;
#else
	struct option *p;
#endif
	size_t iflen;
#ifdef __rtems__
	struct getopt_data getopt_reent;
#define optind getopt_reent.optind
#define optarg getopt_reent.optarg
#define opterr getopt_reent.opterr
#define optopt getopt_reent.optopt
#endif

	all = downonly = uponly = namesonly = noload = verbose = 0;

	/* Parse leading line options */
	strlcpy(options, "adklmnuv", sizeof(options));
	for (p = opts; p != NULL; p = p->next)
		strlcat(options, p->opt, sizeof(options));
#ifdef __rtems__
	memset(&getopt_reent, 0, sizeof(getopt_data));
	while ((c = getopt_r(argc, argv, options, &getopt_reent)) != -1) {
#else
	while ((c = getopt(argc, argv, options)) != -1) {
#endif
		switch (c) {
		case 'a':	/* scan all interfaces */
			all++;
			break;
		case 'd':	/* restrict scan to "down" interfaces */
			downonly++;
			break;
		case 'k':
			printkeys++;
			break;
		case 'l':	/* scan interface names only */
			namesonly++;
			break;
		case 'm':	/* show media choices in status */
			supmedia = 1;
			break;
		case 'n':	/* suppress module loading */
			noload++;
			break;
		case 'u':	/* restrict scan to "up" interfaces */
			uponly++;
			break;
		case 'v':
			verbose++;
			break;
		default:
			for (p = opts; p != NULL; p = p->next)
				if (p->opt[0] == c) {
					p->cb(optarg);
					break;
				}
			if (p == NULL)
				usage();
			break;
		}
	}
	argc -= optind;
	argv += optind;

	/* -l cannot be used with -a or -m */
	if (namesonly && (all || supmedia))
		usage();

	/* nonsense.. */
	if (uponly && downonly)
		usage();

	/* no arguments is equivalent to '-a' */
	if (!namesonly && argc < 1)
		all = 1;

	/* -a and -l allow an address family arg to limit the output */
	if (all || namesonly) {
		if (argc > 1)
			usage();

		ifname = NULL;
		ifindex = 0;
		if (argc == 1) {
			afp = af_getbyname(*argv);
			if (afp == NULL)
				usage();
			if (afp->af_name != NULL)
				argc--, argv++;
			/* leave with afp non-zero */
		}
	} else {
		/* not listing, need an argument */
		if (argc < 1)
			usage();

		ifname = *argv;
		argc--, argv++;

		/* check and maybe load support for this interface */
		ifmaybeload(ifname);

		ifindex = if_nametoindex(ifname);
		if (ifindex == 0) {
			/*
			 * NOTE:  We must special-case the `create' command
			 * right here as we would otherwise fail when trying
			 * to find the interface.
			 */
			if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
			    strcmp(argv[0], "plumb") == 0)) {
				iflen = strlcpy(name, ifname, sizeof(name));
				if (iflen >= sizeof(name))
					errx(1, "%s: cloning name too long",
					    ifname);
				ifconfig(argc, argv, 1, NULL);
				exit(0);
			}
			/*
			 * NOTE:  We have to special-case the `-vnet' command
			 * right here as we would otherwise fail when trying
			 * to find the interface as it lives in another vnet.
			 */
			if (argc > 0 && (strcmp(argv[0], "-vnet") == 0)) {
				iflen = strlcpy(name, ifname, sizeof(name));
				if (iflen >= sizeof(name))
					errx(1, "%s: interface name too long",
					    ifname);
				ifconfig(argc, argv, 0, NULL);
				exit(0);
			}
			errx(1, "interface %s does not exist", ifname);
		}
	}

	/* Check for address family */
	if (argc > 0) {
		afp = af_getbyname(*argv);
		if (afp != NULL)
			argc--, argv++;
	}

	if (getifaddrs(&ifap) != 0)
		err(EXIT_FAILURE, "getifaddrs");
	cp = NULL;
	ifindex = 0;
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
		memset(&paifr, 0, sizeof(paifr));
		strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
		if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
			memcpy(&paifr.ifr_addr, ifa->ifa_addr,
			    ifa->ifa_addr->sa_len);
		}

		if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0)
			continue;
		if (ifa->ifa_addr->sa_family == AF_LINK)
			sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
		else
			sdl = NULL;
		if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0)
			continue;
		iflen = strlcpy(name, ifa->ifa_name, sizeof(name));
		if (iflen >= sizeof(name)) {
			warnx("%s: interface name too long, skipping",
			    ifa->ifa_name);
			continue;
		}
		cp = ifa->ifa_name;

		if (downonly && (ifa->ifa_flags & IFF_UP) != 0)
			continue;
		if (uponly && (ifa->ifa_flags & IFF_UP) == 0)
			continue;
		ifindex++;
		/*
		 * Are we just listing the interfaces?
		 */
		if (namesonly) {
			if (ifindex > 1)
				printf(" ");
			fputs(name, stdout);
			continue;
		}

		if (argc > 0)
			ifconfig(argc, argv, 0, afp);
		else
			status(afp, sdl, ifa);
	}
	if (namesonly)
		printf("\n");
	freeifaddrs(ifap);

	exit(0);
}

static struct afswtch *afs = NULL;

void
af_register(struct afswtch *p)
{
	p->af_next = afs;
	afs = p;
}
Ejemplo n.º 5
0
/*
 * Print the status of the interface.  If an address family was
 * specified, show only it; otherwise, show them all.
 */
static void
status(const struct afswtch *afp, int addrcount, struct	sockaddr_dl *sdl,
       struct if_msghdr *ifm, struct ifa_msghdr *ifam)
{
    struct	rt_addrinfo info;
    int allfamilies, s;
    struct ifstat ifs;

    if (afp == NULL) {
        allfamilies = 1;
        afp = af_getbyname("inet");
    } else
        allfamilies = 0;

    ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af;
    strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));

    s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
    if (s < 0)
        err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);

    printf("%s: ", name);
    printb("flags", flags, IFFBITS);
    if (ifm->ifm_data.ifi_metric)
        printf(" metric %ld", ifm->ifm_data.ifi_metric);
    if (ifm->ifm_data.ifi_mtu)
        printf(" mtu %ld", ifm->ifm_data.ifi_mtu);
    putchar('\n');

    if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
        if (ifr.ifr_curcap != 0) {
            printb("\toptions", ifr.ifr_curcap, IFCAPBITS);
            putchar('\n');
        }
        if (supmedia && ifr.ifr_reqcap != 0) {
            printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
            putchar('\n');
        }
    }

    tunnel_status(s);

    while (addrcount > 0) {
        info.rti_addrs = ifam->ifam_addrs;
        /* Expand the compacted addresses */
        rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
                  &info);

        if (allfamilies) {
            const struct afswtch *p;
            p = af_getbyfamily(info.rti_info[RTAX_IFA]->sa_family);
            if (p != NULL && p->af_status != NULL)
                p->af_status(s, &info);
        } else if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family)
            afp->af_status(s, &info);
        addrcount--;
        ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
    }
    if (allfamilies || afp->af_af == AF_LINK) {
        const struct afswtch *lafp;

        /*
         * Hack; the link level address is received separately
         * from the routing information so any address is not
         * handled above.  Cobble together an entry and invoke
         * the status method specially.
         */
        lafp = af_getbyname("lladdr");
        if (lafp != NULL) {
            info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
            lafp->af_status(s, &info);
        }
    }
    if (allfamilies)
        af_other_status(s);
    else if (afp->af_other_status != NULL)
        afp->af_other_status(s);

    strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
    if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
        printf("%s", ifs.ascii);

    if (flags & IFF_POLLING) {
        if (ioctl(s, SIOCGIFPOLLCPU, &ifr) == 0 && ifr.ifr_pollcpu >= 0)
            printf("\tpollcpu: %d\n", ifr.ifr_pollcpu);
    }

    close(s);
    return;
}
Ejemplo n.º 6
0
int
main(int argc, char *argv[])
{
    int c, all, namesonly, downonly, uponly;
    int need_nl = 0, count = 0;
    const struct afswtch *afp = NULL;
    int addrcount, ifindex;
    struct if_msghdr *ifm, *nextifm;
    struct ifa_msghdr *ifam;
    struct sockaddr_dl *sdl;
    char *buf, *lim, *next;
    size_t needed;
    int mib[6];
    char options[1024];
    const char *ifname;
    struct option *p;
    size_t iflen;

    all = downonly = uponly = namesonly = verbose = 0;

    /* Parse leading line options */
    strlcpy(options, "adklmuv", sizeof(options));
    for (p = opts; p != NULL; p = p->next)
        strlcat(options, p->opt, sizeof(options));
    while ((c = getopt(argc, argv, options)) != -1) {
        switch (c) {
        case 'a':	/* scan all interfaces */
            all++;
            break;
        case 'd':	/* restrict scan to "down" interfaces */
            downonly++;
            break;
        case 'k':
            printkeys++;
            break;
        case 'l':	/* scan interface names only */
            namesonly++;
            break;
        case 'm':	/* show media choices in status */
            supmedia = 1;
            break;
        case 'u':	/* restrict scan to "up" interfaces */
            uponly++;
            break;
        case 'v':
            verbose++;
            break;
        default:
            for (p = opts; p != NULL; p = p->next)
                if (p->opt[0] == c) {
                    p->cb(optarg);
                    break;
                }
            if (p == NULL)
                usage();
            break;
        }
    }
    argc -= optind;
    argv += optind;

    /* -l cannot be used with -a or -m */
    if (namesonly && (all || supmedia))
        usage();

    /* nonsense.. */
    if (uponly && downonly)
        usage();

    /* no arguments is equivalent to '-a' */
    if (!namesonly && argc < 1)
        all = 1;

    /* -a and -l allow an address family arg to limit the output */
    if (all || namesonly) {
        if (argc > 1)
            usage();

        ifname = NULL;
        ifindex = 0;
        if (argc == 1) {
            afp = af_getbyname(*argv);
            if (afp == NULL)
                usage();
            if (afp->af_name != NULL)
                argc--, argv++;
            /* leave with afp non-zero */
        }
    } else {
        /* not listing, need an argument */
        if (argc < 1)
            usage();

        ifname = *argv;
        argc--, argv++;

        /* check and maybe load support for this interface */
        ifmaybeload(ifname);
        ifindex = if_nametoindex(ifname);
        if (ifindex == 0) {
            /*
             * NOTE:  We must special-case the `create' command
             * right here as we would otherwise fail when trying
             * to find the interface.
             */
            if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
                             strcmp(argv[0], "plumb") == 0)) {
                iflen = strlcpy(name, ifname, sizeof(name));
                if (iflen >= sizeof(name))
                    errx(1, "%s: cloning name too long",
                         ifname);
                ifconfig(argc, argv, 1, NULL);
                exit(0);
            }
            errx(1, "interface %s does not exist", ifname);
        }
    }

    /* Check for address family */
    if (argc > 0) {
        afp = af_getbyname(*argv);
        if (afp != NULL)
            argc--, argv++;
    }

retry:
    mib[0] = CTL_NET;
    mib[1] = PF_ROUTE;
    mib[2] = 0;
    mib[3] = 0;			/* address family */
    mib[4] = NET_RT_IFLIST;
    mib[5] = ifindex;		/* interface index */

    /* if particular family specified, only ask about it */
    if (afp != NULL)
        mib[3] = afp->af_af;

    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
        errx(1, "iflist-sysctl-estimate");
    if ((buf = malloc(needed)) == NULL)
        errx(1, "malloc");
    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
        if (errno == ENOMEM && count++ < 10) {
            warnx("Routing table grew, retrying");
            free(buf);
            sleep(1);
            goto retry;
        }
        errx(1, "actual retrieval of interface table");
    }
    lim = buf + needed;

    next = buf;
    while (next < lim) {
        int name_len;

        ifm = (struct if_msghdr *)next;

        if (ifm->ifm_type == RTM_IFINFO) {
#ifdef notyet
            if (ifm->ifm_data.ifi_datalen == 0)
                ifm->ifm_data.ifi_datalen = sizeof(struct if_data);
            sdl = (struct sockaddr_dl *)((char *)ifm + sizeof(struct if_msghdr) -
                                         sizeof(struct if_data) + ifm->ifm_data.ifi_datalen);
#else
            sdl = (struct sockaddr_dl *)(ifm + 1);
#endif
            flags = ifm->ifm_flags;
        } else {
            fprintf(stderr, "out of sync parsing NET_RT_IFLIST\n");
            fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO,
                    ifm->ifm_type);
            fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen);
            fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next,
                    lim);
            exit (1);
        }

        next += ifm->ifm_msglen;
        ifam = NULL;
        addrcount = 0;
        while (next < lim) {

            nextifm = (struct if_msghdr *)next;

            if (nextifm->ifm_type != RTM_NEWADDR)
                break;

            if (ifam == NULL)
                ifam = (struct ifa_msghdr *)nextifm;

            addrcount++;
            next += nextifm->ifm_msglen;
        }

        if (sizeof(name) <= sdl->sdl_nlen)
            name_len = sizeof(name) - 1;
        else
            name_len = sdl->sdl_nlen;

        memcpy(name, sdl->sdl_data, name_len);
        name[name_len] = '\0';

        if (all || namesonly) {
            if (uponly)
                if ((flags & IFF_UP) == 0)
                    continue; /* not up */
            if (downonly)
                if (flags & IFF_UP)
                    continue; /* not down */
            if (namesonly) {
                if (afp == NULL || afp->af_af != AF_LINK ||
                        sdl->sdl_type == IFT_ETHER) {
                    if (need_nl)
                        putchar(' ');
                    fputs(name, stdout);
                    need_nl++;
                }
                continue;
            }
        }

        if (argc > 0)
            ifconfig(argc, argv, 0, afp);
        else
            status(afp, addrcount, sdl, ifm, ifam);
    }
    free(buf);

    if (namesonly && need_nl > 0)
        putchar('\n');
    if (printname)
        printf("%s\n", name);

    exit (0);
}
Ejemplo n.º 7
0
static int
ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp)
{
	const struct afswtch *afp, *nafp;
	const struct cmd *p;
	struct callback *cb;
	int s;

	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
	afp = NULL;
	if (uafp != NULL)
		afp = uafp;
	/*
	 * This is the historical "accident" allowing users to configure IPv4
	 * addresses without the "inet" keyword which while a nice feature has
	 * proven to complicate other things.  We cannot remove this but only
	 * make sure we will never have a similar implicit default for IPv6 or
	 * any other address familiy.  We need a fallback though for
	 * ifconfig IF up/down etc. to work without INET support as people
	 * never used ifconfig IF link up/down, etc. either.
	 */
#ifndef RESCUE
#ifdef INET
	if (afp == NULL && feature_present("inet"))
		afp = af_getbyname("inet");
#endif
#endif
	if (afp == NULL)
		afp = af_getbyname("link");
	if (afp == NULL) {
		warnx("Please specify an address_family.");
		usage();
	}
top:
	ifr.ifr_addr.sa_family =
		afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
		AF_LOCAL : afp->af_af;

	if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0 &&
	    (uafp != NULL || errno != EPROTONOSUPPORT ||
	     (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0))
		err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);

	while (argc > 0) {
		p = cmd_lookup(*argv, iscreate);
		if (iscreate && p == NULL) {
			/*
			 * Push the clone create callback so the new
			 * device is created and can be used for any
			 * remaining arguments.
			 */
			cb = callbacks;
			if (cb == NULL)
				errx(1, "internal error, no callback");
			callbacks = cb->cb_next;
			cb->cb_func(s, cb->cb_arg);
			iscreate = 0;
			/*
			 * Handle any address family spec that
			 * immediately follows and potentially
			 * recreate the socket.
			 */
			nafp = af_getbyname(*argv);
			if (nafp != NULL) {
				argc--, argv++;
				if (nafp != afp) {
					close(s);
					afp = nafp;
					goto top;
				}
			}
			/*
			 * Look for a normal parameter.
			 */
			continue;
		}
		if (p == NULL) {
			/*
			 * Not a recognized command, choose between setting
			 * the interface address and the dst address.
			 */
			p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd);
		}
		if (p->c_u.c_func || p->c_u.c_func2) {
			if (p->c_parameter == NEXTARG) {
				if (argv[1] == NULL)
					errx(1, "'%s' requires argument",
					    p->c_name);
				p->c_u.c_func(argv[1], 0, s, afp);
				argc--, argv++;
			} else if (p->c_parameter == OPTARG) {
				p->c_u.c_func(argv[1], 0, s, afp);
				if (argv[1] != NULL)
					argc--, argv++;
			} else if (p->c_parameter == NEXTARG2) {
				if (argc < 3)
					errx(1, "'%s' requires 2 arguments",
					    p->c_name);
				p->c_u.c_func2(argv[1], argv[2], s, afp);
				argc -= 2, argv += 2;
			} else
				p->c_u.c_func(*argv, p->c_parameter, s, afp);
		}
		argc--, argv++;
	}

	/*
	 * Do any post argument processing required by the address family.
	 */
	if (afp->af_postproc != NULL)
		afp->af_postproc(s, afp);
	/*
	 * Do deferred callbacks registered while processing
	 * command-line arguments.
	 */
	for (cb = callbacks; cb != NULL; cb = cb->cb_next)
		cb->cb_func(s, cb->cb_arg);
	/*
	 * Do deferred operations.
	 */
	if (clearaddr) {
		if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
			warnx("interface %s cannot change %s addresses!",
			      name, afp->af_name);
			clearaddr = 0;
		}
	}
	if (clearaddr) {
		int ret;
		strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
		ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
		if (ret < 0) {
			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
				/* means no previous address for interface */
			} else
				Perror("ioctl (SIOCDIFADDR)");
		}
	}
	if (newaddr) {
		if (afp->af_addreq == NULL || afp->af_aifaddr == 0) {
			warnx("interface %s cannot change %s addresses!",
			      name, afp->af_name);
			newaddr = 0;
		}
	}
	if (newaddr && (setaddr || setmask)) {
		strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
		if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
			Perror("ioctl (SIOCAIFADDR)");
	}

	close(s);
	return(0);
}