static int virtif_create(struct ifnet *ifp) { uint8_t enaddr[ETHER_ADDR_LEN] = { 0xb2, 0x0a, 0x00, 0x0b, 0x0e, 0x01 }; char enaddrstr[3*ETHER_ADDR_LEN]; struct virtif_sc *sc = ifp->if_softc; int error; if (sc->sc_viu) panic("%s: already created", ifp->if_xname); enaddr[2] = cprng_fast32() & 0xff; enaddr[5] = sc->sc_num & 0xff; if ((error = VIFHYPER_CREATE(sc->sc_linkstr, sc, enaddr, &sc->sc_viu)) != 0) { printf("VIFHYPER_CREATE failed: %d\n", error); return error; } ether_ifattach(ifp, enaddr); ether_snprintf(enaddrstr, sizeof(enaddrstr), enaddr); aprint_normal_ifnet(ifp, "Ethernet address %s\n", enaddrstr); IFQ_SET_READY(&ifp->if_snd); return 0; }
/* * The helper functions make Andrew Brown's interface really * shine. It makes possible to create value on the fly whether * the sysctl value is read or written. * * As shown as an example in the man page, the first step is to * create a copy of the node to have sysctl_lookup work on it. * * Here, we have more work to do than just a copy, since we have * to create the string. The first step is to collect the actual * value of the node, which is a convenient pointer to the softc * of the interface. From there we create the string and use it * as the value, but only for the *copy* of the node. * * Then we let sysctl_lookup do the magic, which consists in * setting oldp and newp as required by the operation. When the * value is read, that means that the string will be copied to * the user, and when it is written, the new value will be copied * over in the addr array. * * If newp is NULL, the user was reading the value, so we don't * have anything else to do. If a new value was written, we * have to check it. * * If it is incorrect, we can return an error and leave 'node' as * it is: since it is a copy of the actual node, the change will * be forgotten. * * Upon a correct input, we commit the change to the ifnet * structure of our interface. */ static int tap_sysctl_handler(SYSCTLFN_ARGS) { struct sysctlnode node; struct tap_softc *sc; struct ifnet *ifp; int error; size_t len; char addr[3 * ETHER_ADDR_LEN]; uint8_t enaddr[ETHER_ADDR_LEN]; node = *rnode; sc = node.sysctl_data; ifp = &sc->sc_ec.ec_if; (void)ether_snprintf(addr, sizeof(addr), CLLADDR(ifp->if_sadl)); node.sysctl_data = addr; error = sysctl_lookup(SYSCTLFN_CALL(&node)); if (error || newp == NULL) return (error); len = strlen(addr); if (len < 11 || len > 17) return (EINVAL); /* Commit change */ if (ether_aton_r(enaddr, sizeof(enaddr), addr) != 0) return (EINVAL); if_set_sadl(ifp, enaddr, ETHER_ADDR_LEN, false); return (error); }
static int virtif_create(struct ifnet *ifp) { uint8_t enaddr[ETHER_ADDR_LEN]; char enaddrstr[3*ETHER_ADDR_LEN]; struct virtif_sc *sc = ifp->if_softc; int error; if (sc->sc_viu) panic("%s: already created", ifp->if_xname); /* XXX generalize */ virt_hwaddr(ifp->if_xname, enaddr); if ((error = VIFHYPER_CREATE(sc->sc_linkstr, sc, enaddr, &sc->sc_viu)) != 0) { printf("VIFHYPER_CREATE failed: %d\n", error); return error; } ether_ifattach(ifp, enaddr); ether_snprintf(enaddrstr, sizeof(enaddrstr), enaddr); aprint_normal_ifnet(ifp, "Ethernet address %s\n", enaddrstr); IFQ_SET_READY(&ifp->if_snd); return 0; }
void tap_attach(device_t parent, device_t self, void *aux) { struct tap_softc *sc = device_private(self); struct ifnet *ifp; const struct sysctlnode *node; int error; uint8_t enaddr[ETHER_ADDR_LEN] = { 0xf2, 0x0b, 0xa4, 0xff, 0xff, 0xff }; char enaddrstr[3 * ETHER_ADDR_LEN]; sc->sc_dev = self; sc->sc_sih = NULL; getnanotime(&sc->sc_btime); sc->sc_atime = sc->sc_mtime = sc->sc_btime; sc->sc_flags = 0; selinit(&sc->sc_rsel); /* * Initialize the two locks for the device. * * We need a lock here because even though the tap device can be * opened only once, the file descriptor might be passed to another * process, say a fork(2)ed child. * * The Giant saves us from most of the hassle, but since the read * operation can sleep, we don't want two processes to wake up at * the same moment and both try and dequeue a single packet. * * The queue for event listeners (used by kqueue(9), see below) has * to be protected too, so use a spin lock. */ mutex_init(&sc->sc_rdlock, MUTEX_DEFAULT, IPL_NONE); mutex_init(&sc->sc_kqlock, MUTEX_DEFAULT, IPL_VM); if (!pmf_device_register(self, NULL, NULL)) aprint_error_dev(self, "couldn't establish power handler\n"); /* * In order to obtain unique initial Ethernet address on a host, * do some randomisation. It's not meant for anything but avoiding * hard-coding an address. */ cprng_fast(&enaddr[3], 3); aprint_verbose_dev(self, "Ethernet address %s\n", ether_snprintf(enaddrstr, sizeof(enaddrstr), enaddr)); /* * Why 1000baseT? Why not? You can add more. * * Note that there are 3 steps: init, one or several additions to * list of supported media, and in the end, the selection of one * of them. */ ifmedia_init(&sc->sc_im, 0, tap_mediachange, tap_mediastatus); ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_1000_T, 0, NULL); ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_1000_T|IFM_FDX, 0, NULL); ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_100_TX, 0, NULL); ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_10_T, 0, NULL); ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); ifmedia_add(&sc->sc_im, IFM_ETHER|IFM_AUTO, 0, NULL); ifmedia_set(&sc->sc_im, IFM_ETHER|IFM_AUTO); /* * One should note that an interface must do multicast in order * to support IPv6. */ ifp = &sc->sc_ec.ec_if; strcpy(ifp->if_xname, device_xname(self)); ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = tap_ioctl; ifp->if_start = tap_start; ifp->if_stop = tap_stop; ifp->if_init = tap_init; IFQ_SET_READY(&ifp->if_snd); sc->sc_ec.ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU; /* Those steps are mandatory for an Ethernet driver. */ if_initialize(ifp); ether_ifattach(ifp, enaddr); if_register(ifp); /* * Add a sysctl node for that interface. * * The pointer transmitted is not a string, but instead a pointer to * the softc structure, which we can use to build the string value on * the fly in the helper function of the node. See the comments for * tap_sysctl_handler for details. * * Usually sysctl_createv is called with CTL_CREATE as the before-last * component. However, we can allocate a number ourselves, as we are * the only consumer of the net.link.<iface> node. In this case, the * unit number is conveniently used to number the node. CTL_CREATE * would just work, too. */ if ((error = sysctl_createv(NULL, 0, NULL, &node, CTLFLAG_READWRITE, CTLTYPE_STRING, device_xname(self), NULL, tap_sysctl_handler, 0, (void *)sc, 18, CTL_NET, AF_LINK, tap_node, device_unit(sc->sc_dev), CTL_EOL)) != 0) aprint_error_dev(self, "sysctl_createv returned %d, ignoring\n", error); }