/* * Create a unique interface name */ const char * ni_netdev_make_name(ni_netconfig_t *nc, const char *stem, unsigned int first) { static char namebuf[64]; unsigned int num; for (num = first; num < 65536; ++num) { snprintf(namebuf, sizeof(namebuf), "%s%u", stem, num); if (!ni_netdev_by_name(nc, namebuf)) return namebuf; } return NULL; }
ni_netdev_t * ni_netdev_ref_bind_ifindex(ni_netdev_ref_t *ref, ni_netconfig_t *nc) { ni_netdev_t *dev; if (!ref || (!nc && !(nc = ni_global_state_handle(0)))) return NULL; dev = ni_netdev_by_name(nc, ref->name); if (dev == NULL) return NULL; ref->index = dev->link.ifindex; return dev; }
ni_netdev_t * ni_netdev_ref_resolve(ni_netdev_ref_t *ref, ni_netconfig_t *nc) { ni_netdev_t *dev = NULL; if (!ref || (!nc && !(nc = ni_global_state_handle(0)))) return NULL; if (ref->index && (dev = ni_netdev_by_index(nc, ref->index))) return dev; if (ref->name && (dev = ni_netdev_by_name(nc, ref->name))) return dev; return NULL; }
static int __do_arp_validate_init(struct arp_handle *handle, ni_capture_devinfo_t *dev_info) { ni_netconfig_t *nc; ni_netdev_t *dev; if (ni_server_listen_interface_events(NULL) < 0) { ni_error("unable to initialize netlink link listener"); return NI_LSB_RC_ERROR; } if (ni_server_enable_interface_addr_events(NULL) < 0) { ni_error("unable to initialize netlink addr listener"); return NI_LSB_RC_ERROR; } if (!(nc = ni_global_state_handle(1))) { ni_error("Cannot refresh interface list!"); return NI_LSB_RC_ERROR; } if (!(dev = ni_netdev_by_name(nc, handle->ifname))) { ni_error("Cannot find interface with name '%s'", handle->ifname); return NI_LSB_RC_ERROR; } if (!ni_netdev_supports_arp(dev)) { ni_error("%s: arp is not supported/enabled", dev->name); return NI_LSB_RC_ERROR; } if (!ni_netdev_link_is_up(dev)) { ni_error("%s: link is not up", dev->name); return NI_LSB_RC_ERROR; } if (ni_capture_devinfo_init(dev_info, dev->name, &dev->link) < 0) { ni_error("%s: cannot initialize capture", dev->name); return NI_LSB_RC_ERROR; } return 0; }
/* * Process NEWLINK event */ int __ni_rtevent_newlink(ni_netconfig_t *nc, const struct sockaddr_nl *nladdr, struct nlmsghdr *h) { char namebuf[IF_NAMESIZE+1] = {'\0'}; ni_netdev_t *dev, *old; struct ifinfomsg *ifi; struct nlattr *nla; char *ifname = NULL; int old_flags = 0; if (!(ifi = ni_rtnl_ifinfomsg(h, RTM_NEWLINK))) return -1; if (ifi->ifi_family == AF_BRIDGE) return 0; old = ni_netdev_by_index(nc, ifi->ifi_index); ifname = if_indextoname(ifi->ifi_index, namebuf); if (!ifname) { /* * device (index) does not exists any more; * process deletion/cleanup of the device. */ if (old) { old_flags = old->link.ifflags; old->link.ifflags = 0; old->deleted = 1; __ni_netdev_process_events(nc, old, old_flags); ni_client_state_drop(old->link.ifindex); ni_netconfig_device_remove(nc, old); } return 0; } if (old) { if (!ni_string_eq(old->name, ifname)) { ni_debug_events("%s[%u]: device renamed to %s", old->name, old->link.ifindex, ifname); ni_string_dup(&old->name, ifname); __ni_netdev_event(nc, old, NI_EVENT_DEVICE_RENAME); } dev = old; old_flags = old->link.ifflags; } else { if (!(dev = ni_netdev_new(ifname, ifi->ifi_index))) { ni_warn("%s[%u]: unable to allocate memory for device", ifname, ifi->ifi_index); return -1; } dev->created = 1; ni_netconfig_device_append(nc, dev); } if (__ni_netdev_process_newlink(dev, h, ifi, nc) < 0) { ni_error("Problem parsing RTM_NEWLINK message for %s", ifname); return -1; } if ((ifname = dev->name)) { ni_netdev_t *conflict; conflict = ni_netdev_by_name(nc, ifname); if (conflict && conflict->link.ifindex != (unsigned int)ifi->ifi_index) { /* * As the events often provide an already obsolete name [2 events, * we process 1st with next in read buffer], we are reading the * current dev->name in advance (above). * * On a rename like eth0->rename1->eth1, eth1->rename2->eth0, the * current dev->name is already eth1 at processing time of eth0 * to rename1 event. This sometimes causes that we find eth1 in * our device list [eth1 -> rename2 event in the read buffer]. * * Just update the name of the conflicting device in advance too * and when the interface does not exist any more, emit events. */ char *current = if_indextoname(conflict->link.ifindex, namebuf); if (current) { ni_string_dup(&conflict->name, current); __ni_netdev_event(nc, conflict, NI_EVENT_DEVICE_RENAME); } else { unsigned int ifflags = conflict->link.ifflags; conflict->link.ifflags = 0; conflict->deleted = 1; __ni_netdev_process_events(nc, conflict, ifflags); ni_client_state_drop(conflict->link.ifindex); ni_netconfig_device_remove(nc, conflict); } } } __ni_netdev_process_events(nc, dev, old_flags); if ((nla = nlmsg_find_attr(h, sizeof(*ifi), IFLA_WIRELESS)) != NULL) __ni_wireless_link_event(nc, dev, nla_data(nla), nla_len(nla)); return 0; }
int ni_dhcp4_tester_run(ni_dhcp4_tester_t *opts) { ni_netconfig_t *nc; ni_netdev_t *ifp = NULL; ni_dhcp4_device_t *dev = NULL; ni_dhcp4_request_t *req = NULL; unsigned int link_timeout = 20; int rv; if (opts->timeout && opts->timeout != -1U) { link_timeout = (opts->timeout * 2) / 3; opts->timeout -= link_timeout; } if (!opts || ni_string_empty(opts->ifname)) ni_fatal("Invalid start parameters!"); dhcp4_tester_opts = *opts; dhcp4_tester_status = NI_WICKED_RC_ERROR; if (!(nc = ni_global_state_handle(1))) ni_fatal("Cannot refresh interface list!"); if (!(ifp = ni_netdev_by_name(nc, opts->ifname))) ni_fatal("Cannot find interface with name '%s'", opts->ifname); if (!ni_dhcp4_supported(ifp)) ni_fatal("DHCPv4 not supported on '%s'", opts->ifname); if (!(dev = ni_dhcp4_device_new(ifp->name, &ifp->link))) ni_fatal("Cannot allocate dhcp4 client for '%s'", opts->ifname); ni_dhcp4_set_event_handler(ni_dhcp4_tester_protocol_event); if (!(req = ni_dhcp4_request_new())) { ni_error("Cannot allocate dhcp4 request"); goto failure; } if (!ni_dhcp4_tester_req_init(req, opts->request)) goto failure; if (!ni_netdev_link_is_up(ifp)) { ni_netdev_req_t *ifreq; ni_debug_dhcp("%s: Link is not up, trying to bring it up", ifp->name); ifreq = ni_netdev_req_new(); ifreq->ifflags = NI_IFF_LINK_UP | NI_IFF_NETWORK_UP; if ((rv = ni_system_interface_link_change(ifp, ifreq)) < 0) { ni_error("%s: Unable to set up link", ifp->name); ni_netdev_req_free(ifreq); goto failure; } ni_netdev_req_free(ifreq); do { sleep(1); if (!(nc = ni_global_state_handle(1))) goto failure; if (!(ifp = ni_netdev_by_index(nc, dev->link.ifindex))) break; if (ni_netdev_link_is_up(ifp)) break; ni_debug_dhcp("%s: Link is not (yet) up", ifp->name); } while (link_timeout-- > 1); if (!ifp || !ni_netdev_link_is_up(ifp) || !link_timeout) { ni_error("%s: Unable to bring link up", ifp && ifp->name ? ifp->name : dev->ifname); goto failure; } /* Do not try to send too early, even link is reported up now */ sleep(1); } if (opts->timeout && opts->timeout != -1U) req->acquire_timeout = opts->timeout; req->broadcast = opts->broadcast; if ((rv = ni_dhcp4_acquire(dev, req)) < 0) { ni_error("%s: DHCP4v6 acquire request %s failed: %s", dev->ifname, ni_uuid_print(&req->uuid), ni_strerror(rv)); goto failure; } dhcp4_tester_status = NI_WICKED_RC_IN_PROGRESS; while (!ni_caught_terminal_signal()) { long timeout; timeout = ni_timer_next_timeout(); if (ni_socket_wait(timeout) != 0) break; } ni_server_deactivate_interface_events(); ni_socket_deactivate_all(); failure: if (dev) ni_dhcp4_device_put(dev); if (req) ni_dhcp4_request_free(req); return dhcp4_tester_status; }
static int ni_do_duid_create_ll_type(uint16_t type, int argc, char **argv) { enum { OPT_HELP = 'h', OPT_SCOPE = 's', OPT_UPDATE = 'u' }; static struct option options[] = { { "help", no_argument, NULL, OPT_HELP }, { "scope", required_argument, NULL, OPT_SCOPE }, { "update", no_argument, NULL, OPT_UPDATE }, { NULL, no_argument, NULL, 0 } }; int opt = 0, status = NI_WICKED_RC_USAGE; const char *scope = NULL; ni_bool_t update = FALSE; const char *ifname = NULL; const char *hwtype = NULL; const char *hwaddr = NULL; const char *hex = NULL; ni_opaque_t raw; optind = 1; while ((opt = getopt_long(argc, argv, "+hs:u", options, NULL)) != EOF) { switch (opt) { case OPT_UPDATE: update = TRUE; break; case OPT_SCOPE: if (optarg && !ni_string_eq(optarg, "default")) scope = optarg; break; case OPT_HELP: status = NI_WICKED_RC_SUCCESS; default: usage: fprintf(stderr, "Usage: %s [options] [ [ifname] | <hwtype> <hwaddr> ]\n" "\n" "Options:\n" " --help, -h show this help text and exit.\n" " --scope <ifname> create device specific duid instead of default\n" " --update create a duid and update duid map file\n" "\n" "Arguments:\n" " ifname get hardware type and address from interface\n" " htwype hardware type to use in the duid\n" " htaddr hardware address to use in the duid\n" "\n", argv[0]); ni_do_duid_create_ll_print_hwtypes(stderr); goto cleanup; } } switch (argc - optind) { case 2: hwtype = argv[optind++]; hwaddr = argv[optind++]; break; case 1: ifname = argv[optind++]; break; case 0: break; default: goto usage; } status = NI_WICKED_RC_ERROR; if (scope && !ni_netdev_name_is_valid(scope)) { fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0], ni_print_suspect(scope, ni_string_len(scope))); goto cleanup; } if (hwtype || hwaddr) { switch (type) { case NI_DUID_TYPE_LL: if (ni_duid_create_ll(&raw, hwtype, hwaddr)) status = NI_WICKED_RC_SUCCESS; break; case NI_DUID_TYPE_LLT: if (ni_duid_create_llt(&raw, hwtype, hwaddr)) status = NI_WICKED_RC_SUCCESS; break; default: break; } if (status != NI_WICKED_RC_SUCCESS) { fprintf(stderr, "%s: cannot create duid using hardware type '%s' and address '%s'\n", argv[0], hwtype, hwaddr); goto cleanup; } } else { ni_netconfig_t *nc = ni_global_state_handle(1); ni_netdev_t *dev = NULL; if (!nc) { fprintf(stderr, "%s: cannot retrieve interface properties", argv[0]); goto cleanup; } if (ifname) { dev = ni_netdev_by_name(nc, ifname); if (!dev || !ni_duid_create_from_device(&raw, type, dev)) { hwtype = dev ? ni_duid_hwtype_to_name(dev->link.hwaddr.type) : "missing"; fprintf(stderr, "%s: unable to create %s duid using %s device '%s'\n", argv[0], ni_duid_type_to_name(type), hwtype ? hwtype : "unsupported", ifname); goto cleanup; } } else { dev = scope ? ni_netdev_by_name(nc, scope) : NULL; if (!ni_duid_create_pref_device(&raw, type, nc, dev)) { fprintf(stderr, "%s: unable to create any %s duid (no usable devices)", argv[0], ni_duid_type_to_name(type)); goto cleanup; } } } status = NI_WICKED_RC_ERROR; hex = raw.len ? ni_duid_print_hex(&raw) : NULL; if (ni_string_empty(hex)) { fprintf(stderr, "%s: cannot format en duid as a colon-separated hex string\n", argv[0]); goto cleanup; } if (update) { status = ni_do_duid_create_update(scope, hex); if (status != NI_WICKED_RC_SUCCESS) { fprintf(stderr, "%s: cannot update duid map file using the created duid\n", argv[0]); goto cleanup; } } printf("%s\t%s\n", scope ? scope : "default", hex); status = NI_WICKED_RC_SUCCESS; cleanup: return status; }