/* * 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); }
void eco_ifattach(struct ifnet *ifp, const uint8_t *lla) { struct ecocom *ec = (void *)ifp; ifp->if_type = IFT_ECONET; ifp->if_addrlen = ECO_ADDR_LEN; ifp->if_hdrlen = ECO_HDR_LEN; ifp->if_dlt = DLT_ECONET; ifp->if_mtu = ECO_MTU; ifp->if_output = eco_output; ifp->if_input = eco_input; ifp->if_start = eco_start; ifp->if_ioctl = eco_ioctl; /* ifp->if_baudrate...; */ if_set_sadl(ifp, lla, ECO_ADDR_LEN, FALSE); ifp->if_broadcastaddr = eco_broadcastaddr; LIST_INIT(&ec->ec_retries); bpf_attach(ifp, ifp->if_dlt, ECO_HDR_LEN); }
/* * Helper function to set Ethernet address. This has been replaced by * the generic SIOCALIFADDR ioctl on a PF_LINK socket. */ static int tap_lifaddr(struct ifnet *ifp, u_long cmd, struct ifaliasreq *ifra) { const struct sockaddr *sa = &ifra->ifra_addr; if (sa->sa_family != AF_LINK) return (EINVAL); if_set_sadl(ifp, sa->sa_data, ETHER_ADDR_LEN, false); return (0); }