| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /* |
| 2 | * Copyright (c) 1983, 1993 | |
| 3 | * The Regents of the University of California. All rights reserved. | |
| 4 | * | |
| 5 | * Redistribution and use in source and binary forms, with or without | |
| 6 | * modification, are permitted provided that the following conditions | |
| 7 | * are met: | |
| 8 | * 1. Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer. | |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 | * notice, this list of conditions and the following disclaimer in the | |
| 12 | * documentation and/or other materials provided with the distribution. | |
| 984263bc MD |
13 | * 4. Neither the name of the University nor the names of its contributors |
| 14 | * may be used to endorse or promote products derived from this software | |
| 15 | * without specific prior written permission. | |
| 16 | * | |
| 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 27 | * SUCH DAMAGE. | |
| 1de703da | 28 | * |
| ca74a0a2 | 29 | * $FreeBSD: src/sbin/ifconfig/ifconfig.c,v 1.113.2.4 2006/02/09 10:48:43 yar Exp $ |
| 1630efc5 | 30 | * $DragonFly: src/sbin/ifconfig/ifconfig.c,v 1.30 2007/09/30 04:37:27 sephe Exp $ |
| 984263bc MD |
31 | */ |
| 32 | ||
| 984263bc MD |
33 | #include <sys/param.h> |
| 34 | #include <sys/ioctl.h> | |
| 35 | #include <sys/socket.h> | |
| 36 | #include <sys/sysctl.h> | |
| 37 | #include <sys/time.h> | |
| 38 | #include <sys/module.h> | |
| 39 | #include <sys/linker.h> | |
| 40 | ||
| 41 | #include <net/ethernet.h> | |
| 42 | #include <net/if.h> | |
| 43 | #include <net/if_var.h> | |
| 44 | #include <net/if_dl.h> | |
| 45 | #include <net/if_types.h> | |
| 46 | #include <net/route.h> | |
| 47 | ||
| 48 | /* IP */ | |
| 49 | #include <netinet/in.h> | |
| 50 | #include <netinet/in_var.h> | |
| 51 | #include <arpa/inet.h> | |
| 52 | #include <netdb.h> | |
| 53 | ||
| 984263bc MD |
54 | #include <ctype.h> |
| 55 | #include <err.h> | |
| 56 | #include <errno.h> | |
| 57 | #include <fcntl.h> | |
| 58 | #include <stdio.h> | |
| 59 | #include <stdlib.h> | |
| 60 | #include <string.h> | |
| 61 | #include <unistd.h> | |
| 984263bc MD |
62 | |
| 63 | #include "ifconfig.h" | |
| 64 | ||
| ca74a0a2 SZ |
65 | /* |
| 66 | * This macro returns the size of a struct sockaddr when passed | |
| 67 | * through a routing socket. Basically we round up sa_len to | |
| 68 | * a multiple of sizeof(long), with a minimum of sizeof(long). | |
| 69 | * The check for a NULL pointer is just a convenience, probably never used. | |
| 70 | * The case sa_len == 0 should only apply to empty structures. | |
| 71 | */ | |
| 72 | #define SA_SIZE(sa) \ | |
| 73 | ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ | |
| 74 | sizeof(long) : \ | |
| 75 | 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) | |
| 984263bc | 76 | |
| b50e4759 MD |
77 | /* |
| 78 | * Since "struct ifreq" is composed of various union members, callers | |
| 79 | * should pay special attention to interprete the value. | |
| 80 | * (.e.g. little/big endian difference in the structure.) | |
| 81 | */ | |
| ca74a0a2 | 82 | struct ifreq ifr; |
| 984263bc | 83 | |
| c021b82e | 84 | char name[IFNAMSIZ]; |
| 984263bc MD |
85 | int flags; |
| 86 | int setaddr; | |
| 87 | int setipdst; | |
| 88 | int setmask; | |
| 89 | int doalias; | |
| 90 | int clearaddr; | |
| 91 | int newaddr = 1; | |
| ca74a0a2 | 92 | int verbose; |
| 984263bc | 93 | |
| ca74a0a2 SZ |
94 | int supmedia = 0; |
| 95 | int printkeys = 0; /* Print keying material for interfaces. */ | |
| 96 | int printname = 0; /* Print the name of the created interface. */ | |
| 984263bc | 97 | |
| ca74a0a2 SZ |
98 | static int ifconfig(int argc, char *const *argv, const struct afswtch *afp); |
| 99 | static void status(const struct afswtch *afp, int addrcount, | |
| 984263bc | 100 | struct sockaddr_dl *sdl, struct if_msghdr *ifm, |
| cd5332df | 101 | struct ifa_msghdr *ifam); |
| ca74a0a2 SZ |
102 | static void tunnel_status(int s); |
| 103 | static void usage(void); | |
| 984263bc | 104 | |
| ca74a0a2 SZ |
105 | static struct afswtch *af_getbyname(const char *name); |
| 106 | static struct afswtch *af_getbyfamily(int af); | |
| 107 | static void af_other_status(int); | |
| b50e4759 | 108 | |
| ca74a0a2 | 109 | static struct option *opts = NULL; |
| 984263bc MD |
110 | |
| 111 | void | |
| ca74a0a2 | 112 | opt_register(struct option *p) |
| 984263bc | 113 | { |
| ca74a0a2 SZ |
114 | p->next = opts; |
| 115 | opts = p; | |
| 984263bc MD |
116 | } |
| 117 | ||
| ca74a0a2 | 118 | static void |
| b5744197 | 119 | usage(void) |
| 984263bc | 120 | { |
| ca74a0a2 SZ |
121 | char options[1024]; |
| 122 | struct option *p; | |
| 123 | ||
| 124 | /* XXX not right but close enough for now */ | |
| 125 | options[0] = '\0'; | |
| 126 | for (p = opts; p != NULL; p = p->next) { | |
| 127 | strlcat(options, p->opt_usage, sizeof(options)); | |
| 128 | strlcat(options, " ", sizeof(options)); | |
| 129 | } | |
| 130 | ||
| 131 | fprintf(stderr, | |
| 132 | "usage: ifconfig %sinterface address_family [address [dest_address]]\n" | |
| 133 | " [parameters]\n" | |
| 134 | " ifconfig interface create\n" | |
| 135 | " ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n" | |
| 136 | " ifconfig -l [-d] [-u] [address_family]\n" | |
| 137 | " ifconfig %s[-d] [-m] [-u] [-v]\n", | |
| 138 | options, options, options); | |
| 984263bc MD |
139 | exit(1); |
| 140 | } | |
| 141 | ||
| 142 | int | |
| ca74a0a2 | 143 | main(int argc, char *argv[]) |
| 984263bc | 144 | { |
| ca74a0a2 | 145 | int c, all, namesonly, downonly, uponly; |
| b50e4759 | 146 | int need_nl = 0, count = 0; |
| ca74a0a2 | 147 | const struct afswtch *afp = NULL; |
| e0417840 | 148 | int addrcount, ifindex; |
| ca74a0a2 SZ |
149 | struct if_msghdr *ifm, *nextifm; |
| 150 | struct ifa_msghdr *ifam; | |
| 151 | struct sockaddr_dl *sdl; | |
| 152 | char *buf, *lim, *next; | |
| 984263bc MD |
153 | size_t needed; |
| 154 | int mib[6]; | |
| ca74a0a2 SZ |
155 | char options[1024]; |
| 156 | struct option *p; | |
| 157 | ||
| 158 | all = downonly = uponly = namesonly = verbose = 0; | |
| 984263bc MD |
159 | |
| 160 | /* Parse leading line options */ | |
| ca74a0a2 SZ |
161 | strlcpy(options, "adklmuv", sizeof(options)); |
| 162 | for (p = opts; p != NULL; p = p->next) | |
| 163 | strlcat(options, p->opt, sizeof(options)); | |
| 164 | while ((c = getopt(argc, argv, options)) != -1) { | |
| 984263bc MD |
165 | switch (c) { |
| 166 | case 'a': /* scan all interfaces */ | |
| 167 | all++; | |
| 168 | break; | |
| 169 | case 'd': /* restrict scan to "down" interfaces */ | |
| 170 | downonly++; | |
| 171 | break; | |
| ca74a0a2 SZ |
172 | case 'k': |
| 173 | printkeys++; | |
| 174 | break; | |
| 984263bc MD |
175 | case 'l': /* scan interface names only */ |
| 176 | namesonly++; | |
| 177 | break; | |
| 178 | case 'm': /* show media choices in status */ | |
| 179 | supmedia = 1; | |
| 180 | break; | |
| 181 | case 'u': /* restrict scan to "up" interfaces */ | |
| 182 | uponly++; | |
| 183 | break; | |
| ca74a0a2 SZ |
184 | case 'v': |
| 185 | verbose++; | |
| 984263bc | 186 | break; |
| 984263bc | 187 | default: |
| ca74a0a2 SZ |
188 | for (p = opts; p != NULL; p = p->next) |
| 189 | if (p->opt[0] == c) { | |
| 190 | p->cb(optarg); | |
| 191 | break; | |
| 192 | } | |
| 193 | if (p == NULL) | |
| 194 | usage(); | |
| 984263bc MD |
195 | break; |
| 196 | } | |
| 197 | } | |
| 198 | argc -= optind; | |
| 199 | argv += optind; | |
| 200 | ||
| 984263bc MD |
201 | /* -l cannot be used with -a or -m */ |
| 202 | if (namesonly && (all || supmedia)) | |
| 203 | usage(); | |
| 204 | ||
| 205 | /* nonsense.. */ | |
| 206 | if (uponly && downonly) | |
| 207 | usage(); | |
| 208 | ||
| 209 | /* no arguments is equivalent to '-a' */ | |
| 210 | if (!namesonly && argc < 1) | |
| 211 | all = 1; | |
| 212 | ||
| 213 | /* -a and -l allow an address family arg to limit the output */ | |
| 214 | if (all || namesonly) { | |
| 215 | if (argc > 1) | |
| 216 | usage(); | |
| 217 | ||
| e0417840 | 218 | ifindex = 0; |
| 984263bc | 219 | if (argc == 1) { |
| ca74a0a2 SZ |
220 | afp = af_getbyname(*argv); |
| 221 | if (afp == NULL) | |
| 984263bc | 222 | usage(); |
| ca74a0a2 SZ |
223 | if (afp->af_name != NULL) |
| 224 | argc--, argv++; | |
| 984263bc MD |
225 | /* leave with afp non-zero */ |
| 226 | } | |
| 227 | } else { | |
| 228 | /* not listing, need an argument */ | |
| 229 | if (argc < 1) | |
| 230 | usage(); | |
| 231 | ||
| 232 | strncpy(name, *argv, sizeof(name)); | |
| 233 | argc--, argv++; | |
| 234 | ||
| 235 | /* check and maybe load support for this interface */ | |
| 236 | ifmaybeload(name); | |
| 237 | ||
| 238 | /* | |
| 239 | * NOTE: We must special-case the `create' command right | |
| 240 | * here as we would otherwise fail when trying to find | |
| 241 | * the interface. | |
| 242 | */ | |
| 243 | if (argc > 0 && (strcmp(argv[0], "create") == 0 || | |
| 244 | strcmp(argv[0], "plumb") == 0)) { | |
| 245 | clone_create(); | |
| 246 | argc--, argv++; | |
| 247 | if (argc == 0) | |
| c021b82e | 248 | goto end; |
| 984263bc | 249 | } |
| e0417840 JS |
250 | ifindex = if_nametoindex(name); |
| 251 | if (ifindex == 0) | |
| 252 | errx(1, "interface %s does not exist", name); | |
| 984263bc MD |
253 | } |
| 254 | ||
| 255 | /* Check for address family */ | |
| 256 | if (argc > 0) { | |
| ca74a0a2 SZ |
257 | afp = af_getbyname(*argv); |
| 258 | if (afp != NULL) | |
| 259 | argc--, argv++; | |
| 984263bc MD |
260 | } |
| 261 | ||
| b50e4759 | 262 | retry: |
| 984263bc MD |
263 | mib[0] = CTL_NET; |
| 264 | mib[1] = PF_ROUTE; | |
| 265 | mib[2] = 0; | |
| b50e4759 | 266 | mib[3] = 0; /* address family */ |
| 984263bc | 267 | mib[4] = NET_RT_IFLIST; |
| b50e4759 | 268 | mib[5] = ifindex; /* interface index */ |
| 984263bc MD |
269 | |
| 270 | /* if particular family specified, only ask about it */ | |
| ca74a0a2 | 271 | if (afp != NULL) |
| 984263bc MD |
272 | mib[3] = afp->af_af; |
| 273 | ||
| 274 | if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) | |
| 275 | errx(1, "iflist-sysctl-estimate"); | |
| 276 | if ((buf = malloc(needed)) == NULL) | |
| 277 | errx(1, "malloc"); | |
| b50e4759 MD |
278 | if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { |
| 279 | if (errno == ENOMEM && count++ < 10) { | |
| 280 | warnx("Routing table grew, retrying"); | |
| 281 | free(buf); | |
| 282 | sleep(1); | |
| 283 | goto retry; | |
| 284 | } | |
| 984263bc | 285 | errx(1, "actual retrieval of interface table"); |
| b50e4759 | 286 | } |
| 984263bc MD |
287 | lim = buf + needed; |
| 288 | ||
| 289 | next = buf; | |
| 290 | while (next < lim) { | |
| 57a0bd77 | 291 | int name_len; |
| 984263bc MD |
292 | |
| 293 | ifm = (struct if_msghdr *)next; | |
| 294 | ||
| 295 | if (ifm->ifm_type == RTM_IFINFO) { | |
| ca74a0a2 | 296 | #ifdef notyet |
| b50e4759 MD |
297 | if (ifm->ifm_data.ifi_datalen == 0) |
| 298 | ifm->ifm_data.ifi_datalen = sizeof(struct if_data); | |
| 299 | sdl = (struct sockaddr_dl *)((char *)ifm + sizeof(struct if_msghdr) - | |
| ca74a0a2 | 300 | sizeof(struct if_data) + ifm->ifm_data.ifi_datalen); |
| b50e4759 | 301 | #else |
| ca74a0a2 | 302 | sdl = (struct sockaddr_dl *)(ifm + 1); |
| b50e4759 | 303 | #endif |
| 984263bc MD |
304 | flags = ifm->ifm_flags; |
| 305 | } else { | |
| 306 | fprintf(stderr, "out of sync parsing NET_RT_IFLIST\n"); | |
| 307 | fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO, | |
| 308 | ifm->ifm_type); | |
| 309 | fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen); | |
| 310 | fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next, | |
| 311 | lim); | |
| 312 | exit (1); | |
| 313 | } | |
| 314 | ||
| 315 | next += ifm->ifm_msglen; | |
| 316 | ifam = NULL; | |
| 317 | addrcount = 0; | |
| 318 | while (next < lim) { | |
| 319 | ||
| 320 | nextifm = (struct if_msghdr *)next; | |
| 321 | ||
| 322 | if (nextifm->ifm_type != RTM_NEWADDR) | |
| 323 | break; | |
| 324 | ||
| 325 | if (ifam == NULL) | |
| 326 | ifam = (struct ifa_msghdr *)nextifm; | |
| 327 | ||
| 328 | addrcount++; | |
| 329 | next += nextifm->ifm_msglen; | |
| 330 | } | |
| 57a0bd77 SZ |
331 | |
| 332 | if (sizeof(name) <= sdl->sdl_nlen) | |
| 333 | name_len = sizeof(name) - 1; | |
| 334 | else | |
| 335 | name_len = sdl->sdl_nlen; | |
| 336 | ||
| 337 | memcpy(name, sdl->sdl_data, name_len); | |
| 338 | name[name_len] = '\0'; | |
| e0417840 | 339 | |
| 984263bc MD |
340 | if (all || namesonly) { |
| 341 | if (uponly) | |
| 342 | if ((flags & IFF_UP) == 0) | |
| 343 | continue; /* not up */ | |
| 344 | if (downonly) | |
| 345 | if (flags & IFF_UP) | |
| 346 | continue; /* not down */ | |
| 984263bc | 347 | if (namesonly) { |
| ca74a0a2 SZ |
348 | if (afp == NULL || afp->af_af != AF_LINK || |
| 349 | sdl->sdl_type == IFT_ETHER) { | |
| 984263bc MD |
350 | if (need_nl) |
| 351 | putchar(' '); | |
| 352 | fputs(name, stdout); | |
| 353 | need_nl++; | |
| 354 | } | |
| 355 | continue; | |
| 356 | } | |
| 984263bc MD |
357 | } |
| 358 | ||
| 359 | if (argc > 0) | |
| 360 | ifconfig(argc, argv, afp); | |
| 361 | else | |
| 362 | status(afp, addrcount, sdl, ifm, ifam); | |
| 984263bc MD |
363 | } |
| 364 | free(buf); | |
| 365 | ||
| 366 | if (namesonly && need_nl > 0) | |
| 367 | putchar('\n'); | |
| c021b82e HP |
368 | end: |
| 369 | if (printname) | |
| 370 | printf("%s\n", name); | |
| 984263bc | 371 | |
| 984263bc MD |
372 | exit (0); |
| 373 | } | |
| 374 | ||
| ca74a0a2 | 375 | static struct afswtch *afs = NULL; |
| 984263bc | 376 | |
| ca74a0a2 SZ |
377 | void |
| 378 | af_register(struct afswtch *p) | |
| 379 | { | |
| 380 | p->af_next = afs; | |
| 381 | afs = p; | |
| 382 | } | |
| 383 | ||
| 384 | static struct afswtch * | |
| 385 | af_getbyname(const char *name) | |
| 386 | { | |
| 387 | struct afswtch *afp; | |
| 388 | ||
| 389 | for (afp = afs; afp != NULL; afp = afp->af_next) | |
| 390 | if (strcmp(afp->af_name, name) == 0) | |
| 391 | return afp; | |
| 392 | return NULL; | |
| 393 | } | |
| 394 | ||
| 395 | static struct afswtch * | |
| 396 | af_getbyfamily(int af) | |
| 397 | { | |
| 398 | struct afswtch *afp; | |
| 399 | ||
| 400 | for (afp = afs; afp != NULL; afp = afp->af_next) | |
| 401 | if (afp->af_af == af) | |
| 402 | return afp; | |
| 403 | return NULL; | |
| 404 | } | |
| 405 | ||
| 406 | static void | |
| 407 | af_other_status(int s) | |
| 408 | { | |
| 409 | struct afswtch *afp; | |
| 410 | uint8_t afmask[howmany(AF_MAX, NBBY)]; | |
| 411 | ||
| 412 | memset(afmask, 0, sizeof(afmask)); | |
| 413 | for (afp = afs; afp != NULL; afp = afp->af_next) { | |
| 414 | if (afp->af_other_status == NULL) | |
| 415 | continue; | |
| 416 | if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) | |
| 417 | continue; | |
| 418 | afp->af_other_status(s); | |
| 419 | setbit(afmask, afp->af_af); | |
| 420 | } | |
| 421 | } | |
| 422 | ||
| 423 | static void | |
| 424 | af_all_tunnel_status(int s) | |
| 425 | { | |
| 426 | struct afswtch *afp; | |
| 427 | uint8_t afmask[howmany(AF_MAX, NBBY)]; | |
| 428 | ||
| 429 | memset(afmask, 0, sizeof(afmask)); | |
| 430 | for (afp = afs; afp != NULL; afp = afp->af_next) { | |
| 431 | if (afp->af_status_tunnel == NULL) | |
| 432 | continue; | |
| 433 | if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) | |
| 434 | continue; | |
| 435 | afp->af_status_tunnel(s); | |
| 436 | setbit(afmask, afp->af_af); | |
| 437 | } | |
| 438 | } | |
| 439 | ||
| 440 | static struct cmd *cmds = NULL; | |
| 441 | ||
| 442 | void | |
| 443 | cmd_register(struct cmd *p) | |
| 444 | { | |
| 445 | p->c_next = cmds; | |
| 446 | cmds = p; | |
| 447 | } | |
| 448 | ||
| 449 | static const struct cmd * | |
| 450 | cmd_lookup(const char *name) | |
| 451 | { | |
| 452 | #define N(a) (sizeof(a)/sizeof(a[0])) | |
| 453 | const struct cmd *p; | |
| 454 | ||
| 455 | for (p = cmds; p != NULL; p = p->c_next) | |
| 456 | if (strcmp(name, p->c_name) == 0) | |
| 457 | return p; | |
| 458 | return NULL; | |
| 459 | #undef N | |
| 460 | } | |
| 461 | ||
| 462 | struct callback { | |
| 463 | callback_func *cb_func; | |
| 464 | void *cb_arg; | |
| 465 | struct callback *cb_next; | |
| 466 | }; | |
| 467 | static struct callback *callbacks = NULL; | |
| 468 | ||
| 469 | void | |
| 470 | callback_register(callback_func *func, void *arg) | |
| 471 | { | |
| 472 | struct callback *cb; | |
| 473 | ||
| 474 | cb = malloc(sizeof(struct callback)); | |
| 475 | if (cb == NULL) | |
| 476 | errx(1, "unable to allocate memory for callback"); | |
| 477 | cb->cb_func = func; | |
| 478 | cb->cb_arg = arg; | |
| 479 | cb->cb_next = callbacks; | |
| 480 | callbacks = cb; | |
| 481 | } | |
| 482 | ||
| 483 | /* specially-handled commands */ | |
| 484 | static void setifaddr(const char *, int, int, const struct afswtch *); | |
| 485 | static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr); | |
| 486 | ||
| 487 | static void setifdstaddr(const char *, int, int, const struct afswtch *); | |
| 488 | static const struct cmd setifdstaddr_cmd = | |
| 489 | DEF_CMD("ifdstaddr", 0, setifdstaddr); | |
| 490 | ||
| 491 | static int | |
| b5744197 | 492 | ifconfig(int argc, char *const *argv, const struct afswtch *afp) |
| 984263bc | 493 | { |
| ca74a0a2 | 494 | struct callback *cb; |
| 984263bc MD |
495 | int s; |
| 496 | ||
| 497 | if (afp == NULL) | |
| ca74a0a2 SZ |
498 | afp = af_getbyname("inet"); |
| 499 | ifr.ifr_addr.sa_family = | |
| 500 | afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ? | |
| 501 | AF_INET : afp->af_af; | |
| 984263bc MD |
502 | strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); |
| 503 | ||
| 504 | if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) | |
| ca74a0a2 | 505 | err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family); |
| 984263bc MD |
506 | |
| 507 | while (argc > 0) { | |
| 8d5bb0c5 | 508 | const struct cmd *p; |
| 984263bc | 509 | |
| ca74a0a2 SZ |
510 | p = cmd_lookup(*argv); |
| 511 | if (p == NULL) { | |
| 512 | /* | |
| 513 | * Not a recognized command, choose between setting | |
| 514 | * the interface address and the dst address. | |
| 515 | */ | |
| 516 | p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd); | |
| 517 | } | |
| 518 | if (p->c_u.c_func || p->c_u.c_func2) { | |
| 984263bc MD |
519 | if (p->c_parameter == NEXTARG) { |
| 520 | if (argv[1] == NULL) | |
| 521 | errx(1, "'%s' requires argument", | |
| 522 | p->c_name); | |
| ca74a0a2 | 523 | p->c_u.c_func(argv[1], 0, s, afp); |
| 984263bc | 524 | argc--, argv++; |
| ca74a0a2 SZ |
525 | } else if (p->c_parameter == OPTARG) { |
| 526 | p->c_u.c_func(argv[1], 0, s, afp); | |
| 527 | if (argv[1] != NULL) | |
| 528 | argc--, argv++; | |
| 984263bc MD |
529 | } else if (p->c_parameter == NEXTARG2) { |
| 530 | if (argc < 3) | |
| 531 | errx(1, "'%s' requires 2 arguments", | |
| 532 | p->c_name); | |
| ca74a0a2 | 533 | p->c_u.c_func2(argv[1], argv[2], s, afp); |
| 984263bc MD |
534 | argc -= 2, argv += 2; |
| 535 | } else | |
| ca74a0a2 | 536 | p->c_u.c_func(*argv, p->c_parameter, s, afp); |
| 984263bc MD |
537 | } |
| 538 | argc--, argv++; | |
| 539 | } | |
| 984263bc | 540 | |
| ca74a0a2 SZ |
541 | /* |
| 542 | * Do any post argument processing required by the address family. | |
| 543 | */ | |
| 544 | if (afp->af_postproc != NULL) | |
| 545 | afp->af_postproc(s, afp); | |
| 546 | /* | |
| 547 | * Do deferred callbacks registered while processing | |
| 548 | * command-line arguments. | |
| 549 | */ | |
| 550 | for (cb = callbacks; cb != NULL; cb = cb->cb_next) | |
| 551 | cb->cb_func(s, cb->cb_arg); | |
| 552 | /* | |
| 553 | * Do deferred operations. | |
| 554 | */ | |
| 984263bc MD |
555 | if (clearaddr) { |
| 556 | if (afp->af_ridreq == NULL || afp->af_difaddr == 0) { | |
| 557 | warnx("interface %s cannot change %s addresses!", | |
| 558 | name, afp->af_name); | |
| ca74a0a2 | 559 | clearaddr = 0; |
| 984263bc MD |
560 | } |
| 561 | } | |
| 562 | if (clearaddr) { | |
| 563 | int ret; | |
| 564 | strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name); | |
| ca74a0a2 SZ |
565 | ret = ioctl(s, afp->af_difaddr, afp->af_ridreq); |
| 566 | if (ret < 0) { | |
| 984263bc MD |
567 | if (errno == EADDRNOTAVAIL && (doalias >= 0)) { |
| 568 | /* means no previous address for interface */ | |
| 569 | } else | |
| 570 | Perror("ioctl (SIOCDIFADDR)"); | |
| 571 | } | |
| 572 | } | |
| 573 | if (newaddr) { | |
| 574 | if (afp->af_addreq == NULL || afp->af_aifaddr == 0) { | |
| 575 | warnx("interface %s cannot change %s addresses!", | |
| 576 | name, afp->af_name); | |
| 577 | newaddr = 0; | |
| 578 | } | |
| 579 | } | |
| 580 | if (newaddr && (setaddr || setmask)) { | |
| 581 | strncpy(afp->af_addreq, name, sizeof ifr.ifr_name); | |
| 582 | if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0) | |
| 583 | Perror("ioctl (SIOCAIFADDR)"); | |
| 584 | } | |
| ca74a0a2 | 585 | |
| 984263bc MD |
586 | close(s); |
| 587 | return(0); | |
| 588 | } | |
| 984263bc MD |
589 | |
| 590 | /*ARGSUSED*/ | |
| ca74a0a2 SZ |
591 | static void |
| 592 | setifaddr(const char *addr, int param, int s, const struct afswtch *afp) | |
| 984263bc | 593 | { |
| ca74a0a2 | 594 | if (afp->af_getaddr == NULL) |
| 984263bc MD |
595 | return; |
| 596 | /* | |
| 597 | * Delay the ioctl to set the interface addr until flags are all set. | |
| 598 | * The address interpretation may depend on the flags, | |
| 599 | * and the flags may change when the address is set. | |
| 600 | */ | |
| 601 | setaddr++; | |
| 602 | if (doalias == 0 && afp->af_af != AF_LINK) | |
| 603 | clearaddr = 1; | |
| ca74a0a2 | 604 | afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR)); |
| 984263bc MD |
605 | } |
| 606 | ||
| ca74a0a2 | 607 | static void |
| b5744197 | 608 | settunnel(const char *src, const char *dst, int s, const struct afswtch *afp) |
| 984263bc | 609 | { |
| ca74a0a2 | 610 | struct addrinfo *srcres, *dstres; |
| 984263bc | 611 | int ecode; |
| 984263bc | 612 | |
| ca74a0a2 SZ |
613 | if (afp->af_settunnel == NULL) { |
| 614 | warn("address family %s does not support tunnel setup", | |
| 615 | afp->af_name); | |
| 616 | return; | |
| 617 | } | |
| 984263bc MD |
618 | |
| 619 | if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0) | |
| 620 | errx(1, "error in parsing address string: %s", | |
| 621 | gai_strerror(ecode)); | |
| 622 | ||
| 623 | if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0) | |
| 624 | errx(1, "error in parsing address string: %s", | |
| 625 | gai_strerror(ecode)); | |
| 626 | ||
| 627 | if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family) | |
| 628 | errx(1, | |
| 629 | "source and destination address families do not match"); | |
| 630 | ||
| ca74a0a2 | 631 | afp->af_settunnel(s, srcres, dstres); |
| 984263bc MD |
632 | |
| 633 | freeaddrinfo(srcres); | |
| 634 | freeaddrinfo(dstres); | |
| 635 | } | |
| 636 | ||
| 637 | /* ARGSUSED */ | |
| ca74a0a2 SZ |
638 | static void |
| 639 | deletetunnel(const char *vname, int param, int s, const struct afswtch *afp) | |
| 984263bc | 640 | { |
| ca74a0a2 | 641 | |
| 984263bc MD |
642 | if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0) |
| 643 | err(1, "SIOCDIFPHYADDR"); | |
| 644 | } | |
| 645 | ||
| ca74a0a2 SZ |
646 | static void |
| 647 | setifnetmask(const char *addr, int dummy __unused, int s, | |
| 648 | const struct afswtch *afp) | |
| 984263bc | 649 | { |
| ca74a0a2 SZ |
650 | if (afp->af_getaddr != NULL) { |
| 651 | setmask++; | |
| 652 | afp->af_getaddr(addr, MASK); | |
| 984263bc MD |
653 | } |
| 654 | } | |
| 655 | ||
| ca74a0a2 SZ |
656 | static void |
| 657 | setifbroadaddr(const char *addr, int dummy __unused, int s, | |
| 658 | const struct afswtch *afp) | |
| 984263bc | 659 | { |
| ca74a0a2 SZ |
660 | if (afp->af_getaddr != NULL) |
| 661 | afp->af_getaddr(addr, DSTADDR); | |
| 984263bc | 662 | } |
| 984263bc | 663 | |
| ca74a0a2 SZ |
664 | static void |
| 665 | setifipdst(const char *addr, int dummy __unused, int s, | |
| 666 | const struct afswtch *afp) | |
| 984263bc | 667 | { |
| ca74a0a2 | 668 | const struct afswtch *inet; |
| 984263bc | 669 | |
| ca74a0a2 SZ |
670 | inet = af_getbyname("inet"); |
| 671 | if (inet == NULL) | |
| 672 | return; | |
| 673 | inet->af_getaddr(addr, DSTADDR); | |
| 984263bc MD |
674 | setipdst++; |
| 675 | clearaddr = 0; | |
| 676 | newaddr = 0; | |
| 677 | } | |
| 984263bc | 678 | |
| ca74a0a2 SZ |
679 | static void |
| 680 | notealias(const char *addr, int param, int s, const struct afswtch *afp) | |
| 984263bc | 681 | { |
| ca74a0a2 | 682 | #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr)) |
| 984263bc | 683 | if (setaddr && doalias == 0 && param < 0) |
| b50e4759 MD |
684 | if (afp->af_addreq != NULL && afp->af_ridreq != NULL) |
| 685 | bcopy((caddr_t)rqtosa(af_addreq), | |
| 686 | (caddr_t)rqtosa(af_ridreq), | |
| 687 | rqtosa(af_addreq)->sa_len); | |
| 984263bc MD |
688 | doalias = param; |
| 689 | if (param < 0) { | |
| 690 | clearaddr = 1; | |
| 691 | newaddr = 0; | |
| 692 | } else | |
| 693 | clearaddr = 0; | |
| ca74a0a2 | 694 | #undef rqtosa |
| 984263bc MD |
695 | } |
| 696 | ||
| 697 | /*ARGSUSED*/ | |
| ca74a0a2 SZ |
698 | static void |
| 699 | setifdstaddr(const char *addr, int param __unused, int s, | |
| 700 | const struct afswtch *afp) | |
| 984263bc | 701 | { |
| ca74a0a2 SZ |
702 | if (afp->af_getaddr != NULL) |
| 703 | afp->af_getaddr(addr, DSTADDR); | |
| 984263bc MD |
704 | } |
| 705 | ||
| 706 | /* | |
| 707 | * Note: doing an SIOCIGIFFLAGS scribbles on the union portion | |
| 708 | * of the ifreq structure, which may confuse other parts of ifconfig. | |
| 709 | * Make a private copy so we can avoid that. | |
| 710 | */ | |
| ca74a0a2 SZ |
711 | static void |
| 712 | setifflags(const char *vname, int value, int s, const struct afswtch *afp) | |
| 984263bc MD |
713 | { |
| 714 | struct ifreq my_ifr; | |
| 715 | ||
| 716 | bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq)); | |
| 717 | ||
| 718 | if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) { | |
| 719 | Perror("ioctl (SIOCGIFFLAGS)"); | |
| 720 | exit(1); | |
| 721 | } | |
| 722 | strncpy(my_ifr.ifr_name, name, sizeof (my_ifr.ifr_name)); | |
| 723 | flags = (my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16); | |
| 724 | ||
| 725 | if (value < 0) { | |
| 726 | value = -value; | |
| 727 | flags &= ~value; | |
| 728 | } else | |
| 729 | flags |= value; | |
| 730 | my_ifr.ifr_flags = flags & 0xffff; | |
| 731 | my_ifr.ifr_flagshigh = flags >> 16; | |
| 732 | if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) | |
| 733 | Perror(vname); | |
| 734 | } | |
| 735 | ||
| 736 | void | |
| ca74a0a2 | 737 | setifcap(const char *vname, int value, int s, const struct afswtch *afp) |
| 984263bc MD |
738 | { |
| 739 | ||
| 740 | if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) { | |
| 741 | Perror("ioctl (SIOCGIFCAP)"); | |
| 742 | exit(1); | |
| 743 | } | |
| 744 | flags = ifr.ifr_curcap; | |
| 745 | if (value < 0) { | |
| 746 | value = -value; | |
| 747 | flags &= ~value; | |
| 748 | } else | |
| 749 | flags |= value; | |
| 750 | ifr.ifr_reqcap = flags; | |
| 751 | if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0) | |
| 752 | Perror(vname); | |
| 753 | } | |
| 754 | ||
| ca74a0a2 SZ |
755 | static void |
| 756 | setifmetric(const char *val, int dummy __unused, int s, | |
| 757 | const struct afswtch *afp) | |
| 984263bc MD |
758 | { |
| 759 | strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); | |
| 760 | ifr.ifr_metric = atoi(val); | |
| 761 | if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0) | |
| 762 | warn("ioctl (set metric)"); | |
| 763 | } | |
| 764 | ||
| ca74a0a2 SZ |
765 | static void |
| 766 | setifmtu(const char *val, int dummy __unused, int s, | |
| 767 | const struct afswtch *afp) | |
| 984263bc MD |
768 | { |
| 769 | strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); | |
| 770 | ifr.ifr_mtu = atoi(val); | |
| 771 | if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0) | |
| 772 | warn("ioctl (set mtu)"); | |
| 773 | } | |
| 774 | ||
| ca74a0a2 | 775 | static void |
| c021b82e | 776 | setifname(const char *val, int dummy __unused, int s, |
| ca74a0a2 | 777 | const struct afswtch *afp) |
| c021b82e | 778 | { |
| ca74a0a2 | 779 | char *newname; |
| c021b82e HP |
780 | |
| 781 | newname = strdup(val); | |
| ca74a0a2 SZ |
782 | if (newname == NULL) { |
| 783 | warn("no memory to set ifname"); | |
| 784 | return; | |
| 785 | } | |
| c021b82e HP |
786 | ifr.ifr_data = newname; |
| 787 | if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) { | |
| 788 | warn("ioctl (set name)"); | |
| 789 | free(newname); | |
| 790 | return; | |
| 791 | } | |
| 792 | strlcpy(name, newname, sizeof(name)); | |
| c021b82e HP |
793 | free(newname); |
| 794 | ||
| 795 | /* | |
| 796 | * Even if we just created the interface, we don't need to print | |
| 797 | * its name because we just nailed it down separately. | |
| 798 | */ | |
| 799 | printname = 0; | |
| 800 | } | |
| 801 | ||
| 1630efc5 SZ |
802 | static void |
| 803 | setifpollcpu(const char *val, int dummy __unused, int s, | |
| 804 | const struct afswtch *afp) | |
| 805 | { | |
| 806 | int pollcpu; | |
| 807 | ||
| 808 | pollcpu = atoi(val); | |
| 809 | if (pollcpu < 0) { | |
| 810 | warn("pollcpu < 0"); | |
| 811 | return; | |
| 812 | } | |
| 813 | ||
| 814 | setifflags("-polling", -IFF_POLLING, s, afp); | |
| 815 | ||
| 816 | ifr.ifr_pollcpu = pollcpu; | |
| 817 | if (ioctl(s, SIOCSIFPOLLCPU, (caddr_t)&ifr) < 0) { | |
| 818 | warn("ioctl (set pollcpu)"); | |
| 819 | return; | |
| 820 | } | |
| 821 | } | |
| 822 | ||
| ca74a0a2 SZ |
823 | /* |
| 824 | * Expand the compacted form of addresses as returned via the | |
| 825 | * configuration read via sysctl(). | |
| 826 | */ | |
| 827 | static void | |
| 828 | rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) | |
| 829 | { | |
| 830 | struct sockaddr *sa; | |
| 831 | int i; | |
| 832 | ||
| 833 | memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info)); | |
| 834 | for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { | |
| 835 | if ((rtinfo->rti_addrs & (1 << i)) == 0) | |
| 836 | continue; | |
| 837 | rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; | |
| 838 | cp += SA_SIZE(sa); | |
| 839 | } | |
| 840 | } | |
| 841 | ||
| 984263bc MD |
842 | #define IFFBITS \ |
| 843 | "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \ | |
| 844 | "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \ | |
| b3a7093f | 845 | "\20MULTICAST\21POLLING\22PPROMISC\23MONITOR\24STATICARP\25NPOLLING" |
| 984263bc MD |
846 | |
| 847 | #define IFCAPBITS \ | |
| d585233c | 848 | "\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7RSS" |
| 984263bc MD |
849 | |
| 850 | /* | |
| 851 | * Print the status of the interface. If an address family was | |
| ca74a0a2 | 852 | * specified, show only it; otherwise, show them all. |
| 984263bc | 853 | */ |
| ca74a0a2 SZ |
854 | static void |
| 855 | status(const struct afswtch *afp, int addrcount, struct sockaddr_dl *sdl, | |
| 856 | struct if_msghdr *ifm, struct ifa_msghdr *ifam) | |
| 984263bc | 857 | { |
| 984263bc MD |
858 | struct rt_addrinfo info; |
| 859 | int allfamilies, s; | |
| 860 | struct ifstat ifs; | |
| 861 | ||
| 862 | if (afp == NULL) { | |
| 863 | allfamilies = 1; | |
| ca74a0a2 | 864 | afp = af_getbyname("inet"); |
| 984263bc MD |
865 | } else |
| 866 | allfamilies = 0; | |
| 867 | ||
| 868 | ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af; | |
| ca74a0a2 | 869 | strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); |
| 984263bc | 870 | |
| ca74a0a2 SZ |
871 | s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0); |
| 872 | if (s < 0) | |
| 873 | err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family); | |
| 984263bc MD |
874 | |
| 875 | printf("%s: ", name); | |
| 876 | printb("flags", flags, IFFBITS); | |
| 877 | if (ifm->ifm_data.ifi_metric) | |
| 878 | printf(" metric %ld", ifm->ifm_data.ifi_metric); | |
| 879 | if (ifm->ifm_data.ifi_mtu) | |
| 880 | printf(" mtu %ld", ifm->ifm_data.ifi_mtu); | |
| 881 | putchar('\n'); | |
| 882 | ||
| 883 | if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) { | |
| 884 | if (ifr.ifr_curcap != 0) { | |
| 885 | printb("\toptions", ifr.ifr_curcap, IFCAPBITS); | |
| 886 | putchar('\n'); | |
| 887 | } | |
| 888 | if (supmedia && ifr.ifr_reqcap != 0) { | |
| ca74a0a2 | 889 | printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS); |
| 984263bc MD |
890 | putchar('\n'); |
| 891 | } | |
| 892 | } | |
| 893 | ||
| 894 | tunnel_status(s); | |
| 895 | ||
| 896 | while (addrcount > 0) { | |
| 984263bc | 897 | info.rti_addrs = ifam->ifam_addrs; |
| 984263bc MD |
898 | /* Expand the compacted addresses */ |
| 899 | rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, | |
| 900 | &info); | |
| 901 | ||
| ca74a0a2 SZ |
902 | if (allfamilies) { |
| 903 | const struct afswtch *p; | |
| 904 | p = af_getbyfamily(info.rti_info[RTAX_IFA]->sa_family); | |
| 905 | if (p != NULL && p->af_status != NULL) | |
| 906 | p->af_status(s, &info); | |
| 907 | } else if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family) | |
| 908 | afp->af_status(s, &info); | |
| 984263bc MD |
909 | addrcount--; |
| 910 | ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen); | |
| 911 | } | |
| ca74a0a2 SZ |
912 | if (allfamilies || afp->af_af == AF_LINK) { |
| 913 | const struct afswtch *lafp; | |
| 984263bc | 914 | |
| 984263bc | 915 | /* |
| ca74a0a2 SZ |
916 | * Hack; the link level address is received separately |
| 917 | * from the routing information so any address is not | |
| 918 | * handled above. Cobble together an entry and invoke | |
| 919 | * the status method specially. | |
| 984263bc | 920 | */ |
| ca74a0a2 SZ |
921 | lafp = af_getbyname("lladdr"); |
| 922 | if (lafp != NULL) { | |
| 923 | info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl; | |
| 924 | lafp->af_status(s, &info); | |
| 984263bc MD |
925 | } |
| 926 | } | |
| ca74a0a2 SZ |
927 | if (allfamilies) |
| 928 | af_other_status(s); | |
| 929 | else if (afp->af_other_status != NULL) | |
| 930 | afp->af_other_status(s); | |
| 984263bc | 931 | |
| ca74a0a2 SZ |
932 | strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name); |
| 933 | if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) | |
| 934 | printf("%s", ifs.ascii); | |
| 984263bc | 935 | |
| 1630efc5 SZ |
936 | if (flags & IFF_POLLING) { |
| 937 | if (ioctl(s, SIOCGIFPOLLCPU, &ifr) == 0 && ifr.ifr_pollcpu >= 0) | |
| 938 | printf("\tpollcpu: %d\n", ifr.ifr_pollcpu); | |
| 939 | } | |
| 940 | ||
| 984263bc | 941 | close(s); |
| ca74a0a2 | 942 | return; |
| 984263bc | 943 | } |
| 984263bc | 944 | |
| ca74a0a2 SZ |
945 | static void |
| 946 | tunnel_status(int s) | |
| 984263bc | 947 | { |
| ca74a0a2 | 948 | af_all_tunnel_status(s); |
| 984263bc MD |
949 | } |
| 950 | ||
| 951 | void | |
| b5744197 | 952 | Perror(const char *cmd) |
| 984263bc MD |
953 | { |
| 954 | switch (errno) { | |
| 955 | ||
| 956 | case ENXIO: | |
| 957 | errx(1, "%s: no such interface", cmd); | |
| 958 | break; | |
| 959 | ||
| 960 | case EPERM: | |
| 961 | errx(1, "%s: permission denied", cmd); | |
| 962 | break; | |
| 963 | ||
| 964 | default: | |
| 965 | err(1, "%s", cmd); | |
| 966 | } | |
| 967 | } | |
| 968 | ||
| 984263bc MD |
969 | /* |
| 970 | * Print a value a la the %b format of the kernel's printf | |
| 971 | */ | |
| 972 | void | |
| 8d5bb0c5 | 973 | printb(const char *s, unsigned v, const char *bits) |
| 984263bc | 974 | { |
| 8d5bb0c5 CP |
975 | int i, any = 0; |
| 976 | char c; | |
| 984263bc MD |
977 | |
| 978 | if (bits && *bits == 8) | |
| 979 | printf("%s=%o", s, v); | |
| 980 | else | |
| 981 | printf("%s=%x", s, v); | |
| 982 | bits++; | |
| 983 | if (bits) { | |
| 984 | putchar('<'); | |
| 985 | while ((i = *bits++) != '\0') { | |
| 986 | if (v & (1 << (i-1))) { | |
| 987 | if (any) | |
| 988 | putchar(','); | |
| 989 | any = 1; | |
| 990 | for (; (c = *bits) > 32; bits++) | |
| 991 | putchar(c); | |
| 992 | } else | |
| 993 | for (; *bits > 32; bits++) | |
| 994 | ; | |
| 995 | } | |
| 996 | putchar('>'); | |
| 997 | } | |
| 998 | } | |
| 999 | ||
| 984263bc | 1000 | void |
| ca74a0a2 | 1001 | ifmaybeload(char *name) |
| 984263bc MD |
1002 | { |
| 1003 | struct module_stat mstat; | |
| 1004 | int fileid, modid; | |
| 1005 | char ifkind[35], *cp, *dp; | |
| 1006 | ||
| 984263bc MD |
1007 | /* turn interface and unit into module name */ |
| 1008 | strcpy(ifkind, "if_"); | |
| ca74a0a2 | 1009 | for (cp = name, dp = ifkind + 3; |
| 984263bc MD |
1010 | (*cp != 0) && !isdigit(*cp); cp++, dp++) |
| 1011 | *dp = *cp; | |
| 1012 | *dp = 0; | |
| 1013 | ||
| 1014 | /* scan files in kernel */ | |
| 1015 | mstat.version = sizeof(struct module_stat); | |
| 1016 | for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { | |
| 1017 | /* scan modules in file */ | |
| 1018 | for (modid = kldfirstmod(fileid); modid > 0; | |
| 1019 | modid = modfnext(modid)) { | |
| 1020 | if (modstat(modid, &mstat) < 0) | |
| 1021 | continue; | |
| 1022 | /* strip bus name if present */ | |
| 1023 | if ((cp = strchr(mstat.name, '/')) != NULL) { | |
| 1024 | cp++; | |
| 1025 | } else { | |
| 1026 | cp = mstat.name; | |
| 1027 | } | |
| 1028 | /* already loaded? */ | |
| ca74a0a2 SZ |
1029 | if (strncmp(name, cp, strlen(cp)) == 0 || |
| 1030 | strncmp(ifkind, cp, strlen(cp)) == 0) | |
| 984263bc MD |
1031 | return; |
| 1032 | } | |
| 1033 | } | |
| 1034 | ||
| 1035 | /* not present, we should try to load it */ | |
| 1036 | kldload(ifkind); | |
| 1037 | } | |
| 1038 | ||
| ca74a0a2 SZ |
1039 | static struct cmd basic_cmds[] = { |
| 1040 | DEF_CMD("up", IFF_UP, setifflags), | |
| 1041 | DEF_CMD("down", -IFF_UP, setifflags), | |
| 1042 | DEF_CMD("arp", -IFF_NOARP, setifflags), | |
| 1043 | DEF_CMD("-arp", IFF_NOARP, setifflags), | |
| 1044 | DEF_CMD("debug", IFF_DEBUG, setifflags), | |
| 1045 | DEF_CMD("-debug", -IFF_DEBUG, setifflags), | |
| 1046 | DEF_CMD("promisc", IFF_PPROMISC, setifflags), | |
| 1047 | DEF_CMD("-promisc", -IFF_PPROMISC, setifflags), | |
| 1048 | DEF_CMD("add", IFF_UP, notealias), | |
| 1049 | DEF_CMD("alias", IFF_UP, notealias), | |
| 1050 | DEF_CMD("-alias", -IFF_UP, notealias), | |
| 1051 | DEF_CMD("delete", -IFF_UP, notealias), | |
| 1052 | DEF_CMD("remove", -IFF_UP, notealias), | |
| 1053 | #ifdef notdef | |
| 1054 | #define EN_SWABIPS 0x1000 | |
| 1055 | DEF_CMD("swabips", EN_SWABIPS, setifflags), | |
| 1056 | DEF_CMD("-swabips", -EN_SWABIPS, setifflags), | |
| 1057 | #endif | |
| 1058 | DEF_CMD_ARG("netmask", setifnetmask), | |
| 1059 | DEF_CMD_ARG("metric", setifmetric), | |
| 1060 | DEF_CMD_ARG("broadcast", setifbroadaddr), | |
| 1061 | #ifndef NO_IPX | |
| 1062 | DEF_CMD_ARG("ipdst", setifipdst), | |
| 1063 | #endif | |
| 1064 | DEF_CMD_ARG2("tunnel", settunnel), | |
| 1065 | DEF_CMD("-tunnel", 0, deletetunnel), | |
| 1066 | DEF_CMD("deletetunnel", 0, deletetunnel), | |
| 1067 | DEF_CMD("link0", IFF_LINK0, setifflags), | |
| 1068 | DEF_CMD("-link0", -IFF_LINK0, setifflags), | |
| 1069 | DEF_CMD("link1", IFF_LINK1, setifflags), | |
| 1070 | DEF_CMD("-link1", -IFF_LINK1, setifflags), | |
| 1071 | DEF_CMD("link2", IFF_LINK2, setifflags), | |
| 1072 | DEF_CMD("-link2", -IFF_LINK2, setifflags), | |
| ca74a0a2 SZ |
1073 | DEF_CMD("monitor", IFF_MONITOR, setifflags), |
| 1074 | DEF_CMD("-monitor", -IFF_MONITOR, setifflags), | |
| 1075 | DEF_CMD("staticarp", IFF_STATICARP, setifflags), | |
| 1076 | DEF_CMD("-staticarp", -IFF_STATICARP, setifflags), | |
| 5d610d30 SZ |
1077 | DEF_CMD("polling", IFF_POLLING, setifflags), |
| 1078 | DEF_CMD("-polling", -IFF_POLLING, setifflags), | |
| b3a7093f SZ |
1079 | DEF_CMD("npolling", IFF_NPOLLING, setifflags), |
| 1080 | DEF_CMD("-npolling", -IFF_NPOLLING, setifflags), | |
| ca74a0a2 SZ |
1081 | DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap), |
| 1082 | DEF_CMD("-rxcsum", -IFCAP_RXCSUM, setifcap), | |
| 1083 | DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap), | |
| 1084 | DEF_CMD("-txcsum", -IFCAP_TXCSUM, setifcap), | |
| 1085 | DEF_CMD("netcons", IFCAP_NETCONS, setifcap), | |
| 1086 | DEF_CMD("-netcons", -IFCAP_NETCONS, setifcap), | |
| d585233c SZ |
1087 | DEF_CMD("rss", IFCAP_RSS, setifcap), |
| 1088 | DEF_CMD("-rss", -IFCAP_RSS, setifcap), | |
| ca74a0a2 SZ |
1089 | DEF_CMD("normal", -IFF_LINK0, setifflags), |
| 1090 | DEF_CMD("compress", IFF_LINK0, setifflags), | |
| 1091 | DEF_CMD("noicmp", IFF_LINK1, setifflags), | |
| 1092 | DEF_CMD_ARG("mtu", setifmtu), | |
| 1093 | DEF_CMD_ARG("name", setifname), | |
| 1630efc5 | 1094 | DEF_CMD_ARG("pollcpu", setifpollcpu) |
| ca74a0a2 | 1095 | }; |
| 984263bc | 1096 | |
| ca74a0a2 SZ |
1097 | static __constructor void |
| 1098 | ifconfig_ctor(void) | |
| 984263bc | 1099 | { |
| ca74a0a2 SZ |
1100 | #define N(a) (sizeof(a) / sizeof(a[0])) |
| 1101 | int i; | |
| 984263bc | 1102 | |
| ca74a0a2 SZ |
1103 | for (i = 0; i < N(basic_cmds); i++) |
| 1104 | cmd_register(&basic_cmds[i]); | |
| 1105 | #undef N | |
| 984263bc | 1106 | } |