static int agrether_ctor(struct agr_softc *sc, struct ifnet *ifp_port) { struct ifnet *ifp = &sc->sc_if; struct ethercom *ec = (void *)ifp; struct agrether_private *priv; priv = malloc(sizeof(*priv), M_DEVBUF, M_NOWAIT | M_ZERO); if (!priv) return ENOMEM; agr_mc_init(sc, &priv->aep_multiaddrs); sc->sc_iftprivate = priv; /* inherit ports capabilities * XXX this really needs to be the intersection of all * ports capabilities, not just the latest port. * Okay if ports are the same. */ ifp->if_capabilities = ifp_port->if_capabilities & (IFCAP_TSOv4 | IFCAP_TSOv6 | IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx); ether_ifattach(ifp, CLLADDR(ifp_port->if_sadl)); ec->ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_VLAN_HWTAGGING | ETHERCAP_JUMBO_MTU; ieee8023ad_ctor(sc); 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); }
int atmresolve(struct rtentry *rt0, struct mbuf *m, const struct sockaddr *dst, struct atm_pseudohdr *desten /* OUT */) { const struct sockaddr_dl *sdl; struct rtentry *rt = rt0; if (m->m_flags & (M_BCAST|M_MCAST)) { log(LOG_INFO, "atmresolve: BCAST/MCAST packet detected/dumped\n"); goto bad; } if (rt == NULL) { rt = RTALLOC1(dst, 0); if (rt == NULL) goto bad; /* failed */ if ((rt->rt_flags & RTF_GATEWAY) != 0 || /* XXX: are we using LLINFO? */ rt->rt_gateway->sa_family != AF_LINK) { rtfree(rt); goto bad; } } /* * note that rt_gateway is a sockaddr_dl which contains the * atm_pseudohdr data structure for this route. we currently * don't need any rt_llinfo info (but will if we want to support * ATM ARP [c.f. if_ether.c]). */ sdl = satocsdl(rt->rt_gateway); /* * Check the address family and length is valid, the address * is resolved; otherwise, try to resolve. */ if (sdl->sdl_family == AF_LINK && sdl->sdl_alen == sizeof(*desten)) { memcpy(desten, CLLADDR(sdl), sdl->sdl_alen); if (rt != rt0) rtfree(rt); return (1); /* ok, go for it! */ } if (rt != rt0) rtfree(rt); /* * we got an entry, but it doesn't have valid link address * info in it (it is prob. the interface route, which has * sdl_alen == 0). dump packet. (fall through to "bad"). */ bad: m_freem(m); return (0); }
/* * Do a hardware reset of the board, and upload the ethernet address again in * case the board forgets. */ static inline void el_hardreset(struct el_softc *sc) { bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; int i; bus_space_write_1(iot, ioh, EL_AC, EL_AC_RESET); delay(5); bus_space_write_1(iot, ioh, EL_AC, 0); for (i = 0; i < ETHER_ADDR_LEN; i++) bus_space_write_1(iot, ioh, i, CLLADDR(sc->sc_ethercom.ec_if.if_sadl)[i]); }
static void camprogram(struct sn_softc *sc) { struct ether_multistep step; struct ether_multi *enm; struct ifnet *ifp; int timeout; int mcount = 0; caminitialise(sc); ifp = &sc->sc_if; /* Always load our own address first. */ camentry(sc, mcount, CLLADDR(ifp->if_sadl)); mcount++; /* Assume we won't need allmulti bit. */ ifp->if_flags &= ~IFF_ALLMULTI; /* Loop through multicast addresses */ ETHER_FIRST_MULTI(step, &sc->sc_ethercom, enm); while (enm != NULL) { if (mcount == MAXCAM) { ifp->if_flags |= IFF_ALLMULTI; break; } if (memcmp(enm->enm_addrlo, enm->enm_addrhi, sizeof(enm->enm_addrlo)) != 0) { /* * SONIC's CAM is programmed with specific * addresses. It has no way to specify a range. * (Well, thats not exactly true. If the * range is small one could program each addr * within the range as a separate CAM entry) */ ifp->if_flags |= IFF_ALLMULTI; break; } /* program the CAM with the specified entry */ camentry(sc, mcount, enm->enm_addrlo); mcount++; ETHER_NEXT_MULTI(step, enm); } NIC_PUT(sc, SNR_CDP, LOWER(sc->v_cda)); NIC_PUT(sc, SNR_CDC, MAXCAM); NIC_PUT(sc, SNR_CR, CR_LCAM); wbflush(); timeout = 10000; while ((NIC_GET(sc, SNR_CR) & CR_LCAM) && timeout--) delay(10); if (timeout == 0) { /* XXX */ panic("%s: CAM initialisation failed", device_xname(sc->sc_dev)); } timeout = 10000; while (((NIC_GET(sc, SNR_ISR) & ISR_LCD) == 0) && timeout--) delay(10); if (NIC_GET(sc, SNR_ISR) & ISR_LCD) NIC_PUT(sc, SNR_ISR, ISR_LCD); else printf("%s: CAM initialisation without interrupt\n", device_xname(sc->sc_dev)); }
int smsc_chip_init(struct smsc_softc *sc) { int err; uint32_t reg_val; int burst_cap; /* Enter H/W config mode */ smsc_write_reg(sc, SMSC_HW_CFG, SMSC_HW_CFG_LRST); if ((err = smsc_wait_for_bits(sc, SMSC_HW_CFG, SMSC_HW_CFG_LRST)) != 0) { smsc_warn_printf(sc, "timed-out waiting for reset to " "complete\n"); goto init_failed; } /* Reset the PHY */ smsc_write_reg(sc, SMSC_PM_CTRL, SMSC_PM_CTRL_PHY_RST); if ((err = smsc_wait_for_bits(sc, SMSC_PM_CTRL, SMSC_PM_CTRL_PHY_RST) != 0)) { smsc_warn_printf(sc, "timed-out waiting for phy reset to " "complete\n"); goto init_failed; } usbd_delay_ms(sc->sc_udev, 40); /* Set the mac address */ struct ifnet *ifp = &sc->sc_ec.ec_if; const char *eaddr = CLLADDR(ifp->if_sadl); if ((err = smsc_setmacaddress(sc, eaddr)) != 0) { smsc_warn_printf(sc, "failed to set the MAC address\n"); goto init_failed; } /* * Don't know what the HW_CFG_BIR bit is, but following the reset * sequence as used in the Linux driver. */ if ((err = smsc_read_reg(sc, SMSC_HW_CFG, ®_val)) != 0) { smsc_warn_printf(sc, "failed to read HW_CFG: %d\n", err); goto init_failed; } reg_val |= SMSC_HW_CFG_BIR; smsc_write_reg(sc, SMSC_HW_CFG, reg_val); /* * There is a so called 'turbo mode' that the linux driver supports, it * seems to allow you to jam multiple frames per Rx transaction. * By default this driver supports that and therefore allows multiple * frames per USB transfer. * * The xfer buffer size needs to reflect this as well, therefore based * on the calculations in the Linux driver the RX bufsize is set to * 18944, * bufsz = (16 * 1024 + 5 * 512) * * Burst capability is the number of URBs that can be in a burst of * data/ethernet frames. */ if (sc->sc_udev->speed == USB_SPEED_HIGH) burst_cap = 37; else burst_cap = 128; smsc_write_reg(sc, SMSC_BURST_CAP, burst_cap); /* Set the default bulk in delay (magic value from Linux driver) */ smsc_write_reg(sc, SMSC_BULK_IN_DLY, 0x00002000); /* * Initialise the RX interface */ if ((err = smsc_read_reg(sc, SMSC_HW_CFG, ®_val)) < 0) { smsc_warn_printf(sc, "failed to read HW_CFG: (err = %d)\n", err); goto init_failed; } /* * The following settings are used for 'turbo mode', a.k.a multiple * frames per Rx transaction (again info taken form Linux driver). */ reg_val |= (SMSC_HW_CFG_MEF | SMSC_HW_CFG_BCE); /* * set Rx data offset to ETHER_ALIGN which will make the IP header * align on a word boundary. */ reg_val |= ETHER_ALIGN << SMSC_HW_CFG_RXDOFF_SHIFT; smsc_write_reg(sc, SMSC_HW_CFG, reg_val); /* Clear the status register ? */ smsc_write_reg(sc, SMSC_INTR_STATUS, 0xffffffff); /* Read and display the revision register */ if ((err = smsc_read_reg(sc, SMSC_ID_REV, &sc->sc_rev_id)) < 0) { smsc_warn_printf(sc, "failed to read ID_REV (err = %d)\n", err); goto init_failed; } /* GPIO/LED setup */ reg_val = SMSC_LED_GPIO_CFG_SPD_LED | SMSC_LED_GPIO_CFG_LNK_LED | SMSC_LED_GPIO_CFG_FDX_LED; smsc_write_reg(sc, SMSC_LED_GPIO_CFG, reg_val); /* * Initialise the TX interface */ smsc_write_reg(sc, SMSC_FLOW, 0); smsc_write_reg(sc, SMSC_AFC_CFG, AFC_CFG_DEFAULT); /* Read the current MAC configuration */ if ((err = smsc_read_reg(sc, SMSC_MAC_CSR, &sc->sc_mac_csr)) < 0) { smsc_warn_printf(sc, "failed to read MAC_CSR (err=%d)\n", err); goto init_failed; } /* disable pad stripping, collides with checksum offload */ sc->sc_mac_csr &= ~SMSC_MAC_CSR_PADSTR; /* Vlan */ smsc_write_reg(sc, SMSC_VLAN1, (uint32_t)ETHERTYPE_VLAN); /* * Start TX */ sc->sc_mac_csr |= SMSC_MAC_CSR_TXEN; smsc_write_reg(sc, SMSC_MAC_CSR, sc->sc_mac_csr); smsc_write_reg(sc, SMSC_TX_CFG, SMSC_TX_CFG_ON); /* * Start RX */ sc->sc_mac_csr |= SMSC_MAC_CSR_RXEN; smsc_write_reg(sc, SMSC_MAC_CSR, sc->sc_mac_csr); return (0); init_failed: smsc_err_printf(sc, "smsc_chip_init failed (err=%d)\n", err); return (err); }
void atm_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) { struct sockaddr *gate = rt->rt_gateway; struct atm_pseudoioctl api; #ifdef NATM const struct sockaddr_in *sin; struct natmpcb *npcb = NULL; const struct atm_pseudohdr *aph; #endif const struct ifnet *ifp = rt->rt_ifp; uint8_t namelen = strlen(ifp->if_xname); uint8_t addrlen = ifp->if_addrlen; if (rt->rt_flags & RTF_GATEWAY) /* link level requests only */ return; switch (req) { case RTM_RESOLVE: /* resolve: only happens when cloning */ printf("atm_rtrequest: RTM_RESOLVE request detected?\n"); break; case RTM_ADD: /* * route added by a command (e.g. ifconfig, route, arp...). * * first check to see if this is not a host route, in which * case we are being called via "ifconfig" to set the address. */ if ((rt->rt_flags & RTF_HOST) == 0) { union { struct sockaddr sa; struct sockaddr_dl sdl; struct sockaddr_storage ss; } u; sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index, ifp->if_type, NULL, namelen, NULL, addrlen); rt_setgate(rt, &u.sa); gate = rt->rt_gateway; break; } if ((rt->rt_flags & RTF_CLONING) != 0) { printf("atm_rtrequest: cloning route detected?\n"); break; } if (gate->sa_family != AF_LINK || gate->sa_len < sockaddr_dl_measure(namelen, addrlen)) { log(LOG_DEBUG, "atm_rtrequest: bad gateway value\n"); break; } #ifdef DIAGNOSTIC if (rt->rt_ifp->if_ioctl == NULL) panic("atm null ioctl"); #endif #ifdef NATM /* * let native ATM know we are using this VCI/VPI * (i.e. reserve it) */ sin = satocsin(rt_getkey(rt)); if (sin->sin_family != AF_INET) goto failed; aph = (const struct atm_pseudohdr *)CLLADDR(satosdl(gate)); npcb = npcb_add(NULL, rt->rt_ifp, ATM_PH_VCI(aph), ATM_PH_VPI(aph)); if (npcb == NULL) goto failed; npcb->npcb_flags |= NPCB_IP; npcb->ipaddr.s_addr = sin->sin_addr.s_addr; /* XXX: move npcb to llinfo when ATM ARP is ready */ rt->rt_llinfo = (void *) npcb; rt->rt_flags |= RTF_LLINFO; #endif /* * let the lower level know this circuit is active */ memcpy(&api.aph, CLLADDR(satocsdl(gate)), sizeof(api.aph)); api.rxhand = NULL; if (rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMENA, &api) != 0) { printf("atm: couldn't add VC\n"); goto failed; } satosdl(gate)->sdl_type = rt->rt_ifp->if_type; satosdl(gate)->sdl_index = rt->rt_ifp->if_index; break; failed: #ifdef NATM if (npcb) { npcb_free(npcb, NPCB_DESTROY); rt->rt_llinfo = NULL; rt->rt_flags &= ~RTF_LLINFO; } #endif rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, NULL); break; case RTM_DELETE: #ifdef NATM /* * tell native ATM we are done with this VC */ if (rt->rt_flags & RTF_LLINFO) { npcb_free((struct natmpcb *)rt->rt_llinfo, NPCB_DESTROY); rt->rt_llinfo = NULL; rt->rt_flags &= ~RTF_LLINFO; } #endif /* * tell the lower layer to disable this circuit */ memcpy(&api.aph, CLLADDR(satocsdl(gate)), sizeof(api.aph)); api.rxhand = NULL; (void)rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMDIS, &api); break; } }
int manage_link(int fd) { char *p, *e, *cp; char ifname[IF_NAMESIZE]; ssize_t bytes; struct rt_msghdr *rtm; struct if_announcemsghdr *ifan; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr *sa, *rti_info[RTAX_MAX]; int len; struct sockaddr_dl sdl; #ifdef INET struct rt rt; #endif #if defined(INET6) && !defined(LISTEN_DAD) struct in6_addr ia6; struct sockaddr_in6 *sin6; int ifa_flags; #endif for (;;) { if (ioctl(fd, FIONREAD, &len) == -1) return -1; if (link_buflen < len) { p = realloc(link_buf, len); if (p == NULL) return -1; link_buf = p; link_buflen = len; } bytes = read(fd, link_buf, link_buflen); if (bytes == -1) { if (errno == EAGAIN) return 0; if (errno == EINTR) continue; return -1; } e = link_buf + bytes; for (p = link_buf; p < e; p += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)(void *)p; // Ignore messages generated by us if (rtm->rtm_pid == getpid()) break; switch(rtm->rtm_type) { #ifdef RTM_IFANNOUNCE case RTM_IFANNOUNCE: ifan = (struct if_announcemsghdr *)(void *)p; switch(ifan->ifan_what) { case IFAN_ARRIVAL: handle_interface(1, ifan->ifan_name); break; case IFAN_DEPARTURE: handle_interface(-1, ifan->ifan_name); break; } break; #endif case RTM_IFINFO: ifm = (struct if_msghdr *)(void *)p; memset(ifname, 0, sizeof(ifname)); if (!(if_indextoname(ifm->ifm_index, ifname))) break; switch (ifm->ifm_data.ifi_link_state) { case LINK_STATE_DOWN: len = LINK_DOWN; break; case LINK_STATE_UP: len = LINK_UP; break; default: /* handle_carrier will re-load * the interface flags and check for * IFF_RUNNING as some drivers that * don't handle link state also don't * set IFF_RUNNING when this routing * message is generated. * As such, it is a race ...*/ len = LINK_UNKNOWN; break; } handle_carrier(len, ifm->ifm_flags, ifname); break; case RTM_DELETE: if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY | RTA_NETMASK)) break; cp = (char *)(void *)(rtm + 1); sa = (struct sockaddr *)(void *)cp; if (sa->sa_family != AF_INET) break; #ifdef INET get_addrs(rtm->rtm_addrs, cp, rti_info); memset(&rt, 0, sizeof(rt)); rt.iface = NULL; COPYOUT(rt.dest, rti_info[RTAX_DST]); COPYOUT(rt.net, rti_info[RTAX_NETMASK]); COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]); ipv4_routedeleted(&rt); #endif break; #ifdef RTM_CHGADDR case RTM_CHGADDR: /* FALLTHROUGH */ #endif case RTM_DELADDR: /* FALLTHROUGH */ case RTM_NEWADDR: ifam = (struct ifa_msghdr *)(void *)p; if (!if_indextoname(ifam->ifam_index, ifname)) break; cp = (char *)(void *)(ifam + 1); get_addrs(ifam->ifam_addrs, cp, rti_info); if (rti_info[RTAX_IFA] == NULL) break; switch (rti_info[RTAX_IFA]->sa_family) { case AF_LINK: #ifdef RTM_CHGADDR if (rtm->rtm_type != RTM_CHGADDR) break; #else if (rtm->rtm_type != RTM_NEWADDR) break; #endif memcpy(&sdl, rti_info[RTAX_IFA], rti_info[RTAX_IFA]->sa_len); handle_hwaddr(ifname, (const unsigned char*)CLLADDR(&sdl), sdl.sdl_alen); break; #ifdef INET case AF_INET: case 255: /* FIXME: Why 255? */ COPYOUT(rt.dest, rti_info[RTAX_IFA]); COPYOUT(rt.net, rti_info[RTAX_NETMASK]); COPYOUT(rt.gate, rti_info[RTAX_BRD]); ipv4_handleifa(rtm->rtm_type, NULL, ifname, &rt.dest, &rt.net, &rt.gate); break; #endif #if defined(INET6) && !defined(LISTEN_DAD) case AF_INET6: sin6 = (struct sockaddr_in6*)(void *) rti_info[RTAX_IFA]; memcpy(ia6.s6_addr, sin6->sin6_addr.s6_addr, sizeof(ia6.s6_addr)); if (rtm->rtm_type == RTM_NEWADDR) { ifa_flags = in6_addr_flags( ifname, &ia6); if (ifa_flags == -1) break; } else ifa_flags = 0; ipv6_handleifa(rtm->rtm_type, NULL, ifname, &ia6, ifa_flags); break; #endif } break; } } } }
/* * Get interface identifier for the specified interface. * * in6 - upper 64bits are preserved */ int in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6) { struct ifaddr *ifa; const struct sockaddr_dl *sdl = NULL, *tsdl; const char *addr; size_t addrlen; static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; static u_int8_t allone[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; IFADDR_FOREACH(ifa, ifp) { if (ifa->ifa_addr->sa_family != AF_LINK) continue; tsdl = satocsdl(ifa->ifa_addr); if (tsdl == NULL || tsdl->sdl_alen == 0) continue; if (sdl == NULL || ifa == ifp->if_dl || ifa == ifp->if_hwdl) sdl = tsdl; if (ifa == ifp->if_hwdl) break; } if (sdl == NULL) return -1; addr = CLLADDR(sdl); addrlen = sdl->sdl_alen; switch (ifp->if_type) { case IFT_IEEE1394: case IFT_IEEE80211: /* IEEE1394 uses 16byte length address starting with EUI64 */ if (addrlen > 8) addrlen = 8; break; default: break; } /* get EUI64 */ switch (ifp->if_type) { /* IEEE802/EUI64 cases - what others? */ case IFT_ETHER: case IFT_FDDI: case IFT_ATM: case IFT_IEEE1394: case IFT_IEEE80211: /* look at IEEE802/EUI64 only */ if (addrlen != 8 && addrlen != 6) return -1; /* * check for invalid MAC address - on bsdi, we see it a lot * since wildboar configures all-zero MAC on pccard before * card insertion. */ if (memcmp(addr, allzero, addrlen) == 0) return -1; if (memcmp(addr, allone, addrlen) == 0) return -1; /* make EUI64 address */ if (addrlen == 8) memcpy(&in6->s6_addr[8], addr, 8); else if (addrlen == 6) { in6->s6_addr[8] = addr[0]; in6->s6_addr[9] = addr[1]; in6->s6_addr[10] = addr[2]; in6->s6_addr[11] = 0xff; in6->s6_addr[12] = 0xfe; in6->s6_addr[13] = addr[3]; in6->s6_addr[14] = addr[4]; in6->s6_addr[15] = addr[5]; } break; case IFT_ARCNET: if (addrlen != 1) return -1; if (!addr[0]) return -1; memset(&in6->s6_addr[8], 0, 8); in6->s6_addr[15] = addr[0]; /* * due to insufficient bitwidth, we mark it local. */ in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ break; case IFT_GIF: #ifdef IFT_STF case IFT_STF: #endif /* * RFC2893 says: "SHOULD use IPv4 address as ifid source". * however, IPv4 address is not very suitable as unique * identifier source (can be renumbered). * we don't do this. */ return -1; default: return -1; } /* sanity check: g bit must not indicate "group" */ if (EUI64_GROUP(in6)) return -1; /* convert EUI64 into IPv6 interface identifier */ EUI64_TO_IFID(in6); /* * sanity check: ifid must not be all zero, avoid conflict with * subnet router anycast */ if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 && memcmp(&in6->s6_addr[9], allzero, 7) == 0) { return -1; } return 0; }
static int ieee1394_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst, const struct rtentry *rt) { uint16_t etype = 0; struct mbuf *m; int hdrlen, error = 0; struct mbuf *mcopy = NULL; struct ieee1394_hwaddr *hwdst, baddr; const struct ieee1394_hwaddr *myaddr; #ifdef INET struct arphdr *ah; #endif /* INET */ struct m_tag *mtag; int unicast; if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) senderr(ENETDOWN); /* * If the queueing discipline needs packet classification, * do it before prepending link headers. */ IFQ_CLASSIFY(&ifp->if_snd, m0, dst->sa_family); /* * For unicast, we make a tag to store the lladdr of the * destination. This might not be the first time we have seen * the packet (for instance, the arp code might be trying to * re-send it after receiving an arp reply) so we only * allocate a tag if there isn't one there already. For * multicast, we will eventually use a different tag to store * the channel number. */ unicast = !(m0->m_flags & (M_BCAST | M_MCAST)); if (unicast) { mtag = m_tag_find(m0, MTAG_FIREWIRE_HWADDR, NULL); if (!mtag) { mtag = m_tag_get(MTAG_FIREWIRE_HWADDR, sizeof (struct ieee1394_hwaddr), M_NOWAIT); if (!mtag) { error = ENOMEM; goto bad; } m_tag_prepend(m0, mtag); } hwdst = (struct ieee1394_hwaddr *)(mtag + 1); } else { hwdst = &baddr; } switch (dst->sa_family) { #ifdef INET case AF_INET: if (unicast && (error = arpresolve(ifp, rt, m0, dst, hwdst, sizeof(*hwdst))) != 0) return error == EWOULDBLOCK ? 0 : error; /* if broadcasting on a simplex interface, loopback a copy */ if ((m0->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) mcopy = m_copy(m0, 0, M_COPYALL); etype = htons(ETHERTYPE_IP); break; case AF_ARP: ah = mtod(m0, struct arphdr *); ah->ar_hrd = htons(ARPHRD_IEEE1394); etype = htons(ETHERTYPE_ARP); break; #endif /* INET */ #ifdef INET6 case AF_INET6: if (unicast && (!nd6_storelladdr(ifp, rt, m0, dst, hwdst->iha_uid, IEEE1394_ADDR_LEN))) { /* something bad happened */ return 0; } etype = htons(ETHERTYPE_IPV6); break; #endif /* INET6 */ case pseudo_AF_HDRCMPLT: case AF_UNSPEC: /* TODO? */ default: printf("%s: can't handle af%d\n", ifp->if_xname, dst->sa_family); senderr(EAFNOSUPPORT); break; } if (mcopy) looutput(ifp, mcopy, dst, rt); myaddr = (const struct ieee1394_hwaddr *)CLLADDR(ifp->if_sadl); if (ifp->if_bpf) { struct ieee1394_bpfhdr h; if (unicast) memcpy(h.ibh_dhost, hwdst->iha_uid, 8); else memcpy(h.ibh_dhost, ((const struct ieee1394_hwaddr *) ifp->if_broadcastaddr)->iha_uid, 8); memcpy(h.ibh_shost, myaddr->iha_uid, 8); h.ibh_type = etype; bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m0); } if ((ifp->if_flags & IFF_SIMPLEX) && unicast && memcmp(hwdst, myaddr, IEEE1394_ADDR_LEN) == 0) return looutput(ifp, m0, dst, rt); /* * XXX: * The maximum possible rate depends on the topology. * So the determination of maxrec and fragmentation should be * called from the driver after probing the topology map. */ if (unicast) { hdrlen = IEEE1394_GASP_LEN; hwdst->iha_speed = 0; /* XXX */ } else hdrlen = 0; if (hwdst->iha_speed > myaddr->iha_speed) hwdst->iha_speed = myaddr->iha_speed; if (hwdst->iha_maxrec > myaddr->iha_maxrec) hwdst->iha_maxrec = myaddr->iha_maxrec; if (hwdst->iha_maxrec > (8 + hwdst->iha_speed)) hwdst->iha_maxrec = 8 + hwdst->iha_speed; if (hwdst->iha_maxrec < 8) hwdst->iha_maxrec = 8; m0 = ieee1394_fragment(ifp, m0, (2<<hwdst->iha_maxrec) - hdrlen, etype); if (m0 == NULL) senderr(ENOBUFS); while ((m = m0) != NULL) { m0 = m->m_nextpkt; error = if_transmit_lock(ifp, m); if (error) { /* mbuf is already freed */ goto bad; } } return 0; bad: while (m0 != NULL) { m = m0->m_nextpkt; m_freem(m0); m0 = m; } return error; }
/* * Create a setup packet and put in queue for sending. */ void ze_setup(struct ze_softc *sc) { struct ether_multi *enm; struct ether_multistep step; struct ze_cdata *zc = sc->sc_zedata; struct ifnet *ifp = &sc->sc_if; const u_int8_t *enaddr = CLLADDR(ifp->if_sadl); int j, idx, reg; if (sc->sc_inq == (TXDESCS - 1)) { sc->sc_setup = 1; return; } sc->sc_setup = 0; /* * Init the setup packet with valid info. */ memset(zc->zc_setup, 0xff, sizeof(zc->zc_setup)); /* Broadcast */ memcpy(zc->zc_setup, enaddr, ETHER_ADDR_LEN); /* * Multicast handling. The SGEC can handle up to 16 direct * ethernet addresses. */ j = 16; ifp->if_flags &= ~IFF_ALLMULTI; ETHER_FIRST_MULTI(step, &sc->sc_ec, enm); while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6)) { ifp->if_flags |= IFF_ALLMULTI; break; } memcpy(&zc->zc_setup[j], enm->enm_addrlo, ETHER_ADDR_LEN); j += 8; ETHER_NEXT_MULTI(step, enm); if ((enm != NULL)&& (j == 128)) { ifp->if_flags |= IFF_ALLMULTI; break; } } /* * ALLMULTI implies PROMISC in this driver. */ if (ifp->if_flags & IFF_ALLMULTI) ifp->if_flags |= IFF_PROMISC; else if (ifp->if_pcount == 0) ifp->if_flags &= ~IFF_PROMISC; /* * Fiddle with the receive logic. */ reg = ZE_RCSR(ZE_CSR6); DELAY(10); ZE_WCSR(ZE_CSR6, reg & ~ZE_NICSR6_SR); /* Stop rx */ reg &= ~ZE_NICSR6_AF; if (ifp->if_flags & IFF_PROMISC) reg |= ZE_NICSR6_AF_PROM; else if (ifp->if_flags & IFF_ALLMULTI) reg |= ZE_NICSR6_AF_ALLM; DELAY(10); ZE_WCSR(ZE_CSR6, reg); /* * Only send a setup packet if needed. */ if ((ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) == 0) { idx = sc->sc_nexttx; zc->zc_xmit[idx].ze_tdes1 = ZE_TDES1_DT_SETUP; zc->zc_xmit[idx].ze_bufsize = 128; zc->zc_xmit[idx].ze_bufaddr = sc->sc_pzedata->zc_setup; zc->zc_xmit[idx].ze_tdr = ZE_TDR_OW; if ((ZE_RCSR(ZE_CSR5) & ZE_NICSR5_TS) != ZE_NICSR5_TS_RUN) ZE_WCSR(ZE_CSR1, -1); sc->sc_inq++; if (++sc->sc_nexttx == TXDESCS) sc->sc_nexttx = 0; } }
struct if_head * discover_interfaces(struct dhcpcd_ctx *ctx, int argc, char * const *argv) { struct ifaddrs *ifaddrs, *ifa; char *p; int i, sdl_type; struct if_head *ifs; struct interface *ifp; #ifdef __linux__ char ifn[IF_NAMESIZE]; #endif #ifdef INET const struct sockaddr_in *addr; const struct sockaddr_in *net; const struct sockaddr_in *dst; #endif #ifdef INET6 const struct sockaddr_in6 *sin6; int ifa_flags; #endif #ifdef AF_LINK const struct sockaddr_dl *sdl; #ifdef SIOCGIFPRIORITY struct ifreq ifr; int s_inet; #endif #ifdef IFLR_ACTIVE struct if_laddrreq iflr; int s_link; #endif #ifdef SIOCGIFPRIORITY if ((s_inet = socket(AF_INET, SOCK_DGRAM, 0)) == -1) return NULL; #endif #ifdef IFLR_ACTIVE if ((s_link = socket(AF_LINK, SOCK_DGRAM, 0)) == -1) { #ifdef SIOCGIFPRIORITY close(s_inet); #endif return NULL; } memset(&iflr, 0, sizeof(iflr)); #endif #elif AF_PACKET const struct sockaddr_ll *sll; #endif if (getifaddrs(&ifaddrs) == -1) return NULL; ifs = malloc(sizeof(*ifs)); if (ifs == NULL) return NULL; TAILQ_INIT(ifs); for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr != NULL) { #ifdef AF_LINK if (ifa->ifa_addr->sa_family != AF_LINK) continue; #elif AF_PACKET if (ifa->ifa_addr->sa_family != AF_PACKET) continue; #endif } /* Ensure that the interface name has settled */ if (!dev_initialized(ctx, ifa->ifa_name)) continue; /* It's possible for an interface to have >1 AF_LINK. * For our purposes, we use the first one. */ TAILQ_FOREACH(ifp, ifs, next) { if (strcmp(ifp->name, ifa->ifa_name) == 0) break; } if (ifp) continue; if (argc > 0) { for (i = 0; i < argc; i++) { #ifdef __linux__ /* Check the real interface name */ strlcpy(ifn, argv[i], sizeof(ifn)); p = strchr(ifn, ':'); if (p) *p = '\0'; if (strcmp(ifn, ifa->ifa_name) == 0) break; #else if (strcmp(argv[i], ifa->ifa_name) == 0) break; #endif } if (i == argc) continue; p = argv[i]; } else { p = ifa->ifa_name; /* -1 means we're discovering against a specific * interface, but we still need the below rules * to apply. */ if (argc == -1 && strcmp(argv[0], ifa->ifa_name) != 0) continue; } for (i = 0; i < ctx->ifdc; i++) if (!fnmatch(ctx->ifdv[i], p, 0)) break; if (i < ctx->ifdc) continue; for (i = 0; i < ctx->ifac; i++) if (!fnmatch(ctx->ifav[i], p, 0)) break; if (ctx->ifac && i == ctx->ifac) continue; if (if_vimaster(ifa->ifa_name) == 1) { syslog(argc ? LOG_ERR : LOG_DEBUG, "%s: is a Virtual Interface Master, skipping", ifa->ifa_name); continue; } ifp = calloc(1, sizeof(*ifp)); if (ifp == NULL) { syslog(LOG_ERR, "%s: %m", __func__); break; } ifp->ctx = ctx; strlcpy(ifp->name, p, sizeof(ifp->name)); ifp->flags = ifa->ifa_flags; /* Bring the interface up if not already */ if (!(ifp->flags & IFF_UP) #ifdef SIOCGIFMEDIA && carrier_status(ifp) != LINK_UNKNOWN #endif ) { if (up_interface(ifp) == 0) ctx->options |= DHCPCD_WAITUP; else syslog(LOG_ERR, "%s: up_interface: %m", ifp->name); } sdl_type = 0; /* Don't allow loopback unless explicit */ if (ifp->flags & IFF_LOOPBACK) { if (argc == 0 && ctx->ifac == 0) { free_interface(ifp); continue; } } else if (ifa->ifa_addr != NULL) { #ifdef AF_LINK sdl = (const struct sockaddr_dl *)(void *)ifa->ifa_addr; #ifdef IFLR_ACTIVE /* We need to check for active address */ strlcpy(iflr.iflr_name, ifp->name, sizeof(iflr.iflr_name)); memcpy(&iflr.addr, ifa->ifa_addr, MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr))); iflr.flags = IFLR_PREFIX; iflr.prefixlen = sdl->sdl_alen * NBBY; if (ioctl(s_link, SIOCGLIFADDR, &iflr) == -1 || !(iflr.flags & IFLR_ACTIVE)) { free_interface(ifp); continue; } #endif ifp->index = sdl->sdl_index; sdl_type = sdl->sdl_type; switch(sdl->sdl_type) { case IFT_BRIDGE: /* FALLTHROUGH */ case IFT_L2VLAN: /* FALLTHOUGH */ case IFT_L3IPVLAN: /* FALLTHROUGH */ case IFT_ETHER: ifp->family = ARPHRD_ETHER; break; case IFT_IEEE1394: ifp->family = ARPHRD_IEEE1394; break; #ifdef IFT_INFINIBAND case IFT_INFINIBAND: ifp->family = ARPHRD_INFINIBAND; break; #endif } ifp->hwlen = sdl->sdl_alen; #ifndef CLLADDR # define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen)) #endif memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen); #elif AF_PACKET sll = (const struct sockaddr_ll *)(void *)ifa->ifa_addr; ifp->index = sll->sll_ifindex; ifp->family = sdl_type = sll->sll_hatype; ifp->hwlen = sll->sll_halen; if (ifp->hwlen != 0) memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen); #endif } #ifdef __linux__ /* PPP addresses on Linux don't have hardware addresses */ else ifp->index = if_nametoindex(ifp->name); #endif /* We only work on ethernet by default */ if (!(ifp->flags & IFF_POINTOPOINT) && ifp->family != ARPHRD_ETHER) { if (argc == 0 && ctx->ifac == 0) { free_interface(ifp); continue; } switch (ifp->family) { case ARPHRD_IEEE1394: /* FALLTHROUGH */ case ARPHRD_INFINIBAND: /* We don't warn for supported families */ break; default: syslog(LOG_WARNING, "%s: unsupported interface type %.2x" ", falling back to ethernet", ifp->name, sdl_type); ifp->family = ARPHRD_ETHER; break; } } /* Handle any platform init for the interface */ if (if_init(ifp) == -1) { syslog(LOG_ERR, "%s: if_init: %m", p); free_interface(ifp); continue; } /* Ensure that the MTU is big enough for DHCP */ if (get_mtu(ifp->name) < MTU_MIN && set_mtu(ifp->name, MTU_MIN) == -1) { syslog(LOG_ERR, "%s: set_mtu: %m", p); free_interface(ifp); continue; } #ifdef SIOCGIFPRIORITY /* Respect the interface priority */ memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); if (ioctl(s_inet, SIOCGIFPRIORITY, &ifr) == 0) ifp->metric = ifr.ifr_metric; #else /* We reserve the 100 range for virtual interfaces, if and when * we can work them out. */ ifp->metric = 200 + ifp->index; if (getifssid(ifp->name, ifp->ssid) != -1) { ifp->wireless = 1; ifp->metric += 100; } #endif TAILQ_INSERT_TAIL(ifs, ifp, next); } for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) continue; switch(ifa->ifa_addr->sa_family) { #ifdef INET case AF_INET: addr = (const struct sockaddr_in *) (void *)ifa->ifa_addr; net = (const struct sockaddr_in *) (void *)ifa->ifa_netmask; if (ifa->ifa_flags & IFF_POINTOPOINT) dst = (const struct sockaddr_in *) (void *)ifa->ifa_dstaddr; else dst = NULL; ipv4_handleifa(ctx, RTM_NEWADDR, ifs, ifa->ifa_name, &addr->sin_addr, &net->sin_addr, dst ? &dst->sin_addr : NULL); break; #endif #ifdef INET6 case AF_INET6: sin6 = (const struct sockaddr_in6 *) (void *)ifa->ifa_addr; ifa_flags = in6_addr_flags(ifa->ifa_name, &sin6->sin6_addr); if (ifa_flags != -1) ipv6_handleifa(ctx, RTM_NEWADDR, ifs, ifa->ifa_name, &sin6->sin6_addr, ifa_flags); break; #endif } } freeifaddrs(ifaddrs); #ifdef SIOCGIFPRIORITY close(s_inet); #endif #ifdef IFLR_ACTIVE close(s_link); #endif return ifs; }
int if_managelink(struct dhcpcd_ctx *ctx) { /* route and ifwatchd like a msg buf size of 2048 */ char msg[2048], *p, *e, *cp; ssize_t bytes; struct rt_msghdr *rtm; struct if_announcemsghdr *ifan; struct if_msghdr *ifm; struct ifa_msghdr *ifam; struct sockaddr *sa, *rti_info[RTAX_MAX]; int len; struct sockaddr_dl sdl; struct interface *ifp; #ifdef INET struct rt rt; #endif #ifdef INET6 struct rt6 rt6; struct in6_addr ia6; struct sockaddr_in6 *sin6; int ifa_flags; #endif bytes = read(ctx->link_fd, msg, sizeof(msg)); if (bytes == -1) return -1; if (bytes == 0) return 0; e = msg + bytes; for (p = msg; p < e; p += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)(void *)p; // Ignore messages generated by us if (rtm->rtm_pid == getpid()) break; switch(rtm->rtm_type) { #ifdef RTM_IFANNOUNCE case RTM_IFANNOUNCE: ifan = (struct if_announcemsghdr *)(void *)p; switch(ifan->ifan_what) { case IFAN_ARRIVAL: dhcpcd_handleinterface(ctx, 1, ifan->ifan_name); break; case IFAN_DEPARTURE: dhcpcd_handleinterface(ctx, -1, ifan->ifan_name); break; } break; #endif case RTM_IFINFO: ifm = (struct if_msghdr *)(void *)p; if ((ifp = if_findindex(ctx, ifm->ifm_index)) == NULL) break; switch (ifm->ifm_data.ifi_link_state) { case LINK_STATE_DOWN: len = LINK_DOWN; break; case LINK_STATE_UP: len = LINK_UP; break; default: /* handle_carrier will re-load * the interface flags and check for * IFF_RUNNING as some drivers that * don't handle link state also don't * set IFF_RUNNING when this routing * message is generated. * As such, it is a race ...*/ len = LINK_UNKNOWN; break; } dhcpcd_handlecarrier(ctx, len, (unsigned int)ifm->ifm_flags, ifp->name); break; case RTM_DELETE: if (~rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY | RTA_NETMASK)) break; cp = (char *)(void *)(rtm + 1); sa = (struct sockaddr *)(void *)cp; get_addrs(rtm->rtm_addrs, cp, rti_info); switch (sa->sa_family) { #ifdef INET case AF_INET: memset(&rt, 0, sizeof(rt)); rt.iface = NULL; COPYOUT(rt.dest, rti_info[RTAX_DST]); COPYOUT(rt.net, rti_info[RTAX_NETMASK]); COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]); ipv4_routedeleted(ctx, &rt); break; #endif #ifdef INET6 case AF_INET6: memset(&rt6, 0, sizeof(rt6)); rt6.iface = NULL; COPYOUT6(rt6.dest, rti_info[RTAX_DST]); COPYOUT6(rt6.net, rti_info[RTAX_NETMASK]); COPYOUT6(rt6.gate, rti_info[RTAX_GATEWAY]); ipv6_routedeleted(ctx, &rt6); break; #endif } #ifdef RTM_CHGADDR case RTM_CHGADDR: /* FALLTHROUGH */ #endif case RTM_DELADDR: /* FALLTHROUGH */ case RTM_NEWADDR: ifam = (struct ifa_msghdr *)(void *)p; if ((ifp = if_findindex(ctx, ifam->ifam_index)) == NULL) break; cp = (char *)(void *)(ifam + 1); get_addrs(ifam->ifam_addrs, cp, rti_info); if (rti_info[RTAX_IFA] == NULL) break; switch (rti_info[RTAX_IFA]->sa_family) { case AF_LINK: #ifdef RTM_CHGADDR if (rtm->rtm_type != RTM_CHGADDR) break; #else if (rtm->rtm_type != RTM_NEWADDR) break; #endif memcpy(&sdl, rti_info[RTAX_IFA], rti_info[RTAX_IFA]->sa_len); dhcpcd_handlehwaddr(ctx, ifp->name, (const unsigned char*)CLLADDR(&sdl), sdl.sdl_alen); break; #ifdef INET case AF_INET: case 255: /* FIXME: Why 255? */ COPYOUT(rt.dest, rti_info[RTAX_IFA]); COPYOUT(rt.net, rti_info[RTAX_NETMASK]); COPYOUT(rt.gate, rti_info[RTAX_BRD]); ipv4_handleifa(ctx, rtm->rtm_type, NULL, ifp->name, &rt.dest, &rt.net, &rt.gate); break; #endif #ifdef INET6 case AF_INET6: sin6 = (struct sockaddr_in6*)(void *) rti_info[RTAX_IFA]; ia6 = sin6->sin6_addr; #ifdef __KAME__ if (IN6_IS_ADDR_LINKLOCAL(&ia6)) ia6.s6_addr[2] = ia6.s6_addr[3] = '\0'; #endif if (rtm->rtm_type == RTM_NEWADDR) { ifa_flags = if_addrflags6(&ia6, ifp); if (ifa_flags == -1) break; } else ifa_flags = 0; ipv6_handleifa(ctx, rtm->rtm_type, NULL, ifp->name, &ia6, ifa_flags); break; #endif } break; } } return 0; }
static void shmif_rcv(void *arg) { struct ifnet *ifp = arg; struct shmif_sc *sc = ifp->if_softc; struct shmif_mem *busmem; struct mbuf *m = NULL; struct ether_header *eth; uint32_t nextpkt; bool wrap, passup; int error; const int align = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header); reup: mutex_enter(&sc->sc_mtx); while ((ifp->if_flags & IFF_RUNNING) == 0 && !sc->sc_dying) cv_wait(&sc->sc_cv, &sc->sc_mtx); mutex_exit(&sc->sc_mtx); busmem = sc->sc_busmem; while (ifp->if_flags & IFF_RUNNING) { struct shmif_pkthdr sp; if (m == NULL) { m = m_gethdr(M_WAIT, MT_DATA); MCLGET(m, M_WAIT); m->m_data += align; } DPRINTF(("waiting %d/%" PRIu64 "\n", sc->sc_nextpacket, sc->sc_devgen)); KASSERT(m->m_flags & M_EXT); shmif_lockbus(busmem); KASSERT(busmem->shm_magic == SHMIF_MAGIC); KASSERT(busmem->shm_gen >= sc->sc_devgen); /* need more data? */ if (sc->sc_devgen == busmem->shm_gen && shmif_nextpktoff(busmem, busmem->shm_last) == sc->sc_nextpacket) { shmif_unlockbus(busmem); error = 0; rumpcomp_shmif_watchwait(sc->sc_kq); if (__predict_false(error)) printf("shmif_rcv: wait failed %d\n", error); membar_consumer(); continue; } if (stillvalid_p(sc)) { nextpkt = sc->sc_nextpacket; } else { KASSERT(busmem->shm_gen > 0); nextpkt = busmem->shm_first; if (busmem->shm_first > busmem->shm_last) sc->sc_devgen = busmem->shm_gen - 1; else sc->sc_devgen = busmem->shm_gen; DPRINTF(("dev %p overrun, new data: %d/%" PRIu64 "\n", sc, nextpkt, sc->sc_devgen)); } /* * If our read pointer is ahead the bus last write, our * generation must be one behind. */ KASSERT(!(nextpkt > busmem->shm_last && sc->sc_devgen == busmem->shm_gen)); wrap = false; nextpkt = shmif_busread(busmem, &sp, nextpkt, sizeof(sp), &wrap); KASSERT(sp.sp_len <= ETHERMTU + ETHER_HDR_LEN); nextpkt = shmif_busread(busmem, mtod(m, void *), nextpkt, sp.sp_len, &wrap); DPRINTF(("shmif_rcv: read packet of length %d at %d\n", sp.sp_len, nextpkt)); sc->sc_nextpacket = nextpkt; shmif_unlockbus(sc->sc_busmem); if (wrap) { sc->sc_devgen++; DPRINTF(("dev %p generation now %" PRIu64 "\n", sc, sc->sc_devgen)); } /* * Ignore packets too short to possibly be valid. * This is hit at least for the first frame on a new bus. */ if (__predict_false(sp.sp_len < ETHER_HDR_LEN)) { DPRINTF(("shmif read packet len %d < ETHER_HDR_LEN\n", sp.sp_len)); continue; } m->m_len = m->m_pkthdr.len = sp.sp_len; m->m_pkthdr.rcvif = ifp; /* * Test if we want to pass the packet upwards */ eth = mtod(m, struct ether_header *); if (memcmp(eth->ether_dhost, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN) == 0) { passup = true; } else if (ETHER_IS_MULTICAST(eth->ether_dhost)) { passup = true; } else if (ifp->if_flags & IFF_PROMISC) { m->m_flags |= M_PROMISC; passup = true; } else { passup = false; } if (passup) { KERNEL_LOCK(1, NULL); bpf_mtap(ifp, m); ifp->if_input(ifp, m); KERNEL_UNLOCK_ONE(NULL); m = NULL; } /* else: reuse mbuf for a future packet */ } m_freem(m); m = NULL; if (!sc->sc_dying) goto reup; kthread_exit(0); }
/* * Initialization of interface; clear recorded pending * operations, and reinitialize UNIBUS usage. */ int ilinit(struct ifnet *ifp) { struct il_softc *sc = ifp->if_softc; int s; if (sc->sc_flags & ILF_RUNNING) return 0; if ((ifp->if_flags & IFF_RUNNING) == 0) { if (if_ubainit(&sc->sc_ifuba, device_private(device_parent(sc->sc_dev)), ETHER_MAX_LEN)) { aprint_error_dev(sc->sc_dev, "can't initialize\n"); sc->sc_if.if_flags &= ~IFF_UP; return 0; } sc->sc_ui.ui_size = sizeof(sc->sc_isu); sc->sc_ui.ui_vaddr = (void *)&sc->sc_isu; uballoc(device_private(device_parent(sc->sc_dev)), &sc->sc_ui, 0); } sc->sc_scaninterval = ILWATCHINTERVAL; ifp->if_timer = sc->sc_scaninterval; /* * Turn off source address insertion (it's faster this way), * and set board online. Former doesn't work if board is * already online (happens on ubareset), so we put it offline * first. */ s = splnet(); IL_WCSR(IL_CSR, ILC_RESET); if (ilwait(sc, "hardware diag")) { sc->sc_if.if_flags &= ~IFF_UP; goto out; } IL_WCSR(IL_CSR, ILC_CISA); while ((IL_RCSR(IL_CSR) & IL_CDONE) == 0) ; /* * If we must reprogram this board's physical ethernet * address (as for secondary XNS interfaces), we do so * before putting it on line, and starting receive requests. * If you try this on an older 1010 board, it will total * wedge the board. */ if (sc->sc_flags & ILF_SETADDR) { memcpy(&sc->sc_isu, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN); IL_WCSR(IL_BAR, LOWORD(sc->sc_ui.ui_baddr)); IL_WCSR(IL_BCR, ETHER_ADDR_LEN); IL_WCSR(IL_CSR, ((sc->sc_ui.ui_baddr >> 2) & IL_EUA)|ILC_LDPA); if (ilwait(sc, "setaddr")) goto out; IL_WCSR(IL_BAR, LOWORD(sc->sc_ui.ui_baddr)); IL_WCSR(IL_BCR, sizeof (struct il_stats)); IL_WCSR(IL_CSR, ((sc->sc_ui.ui_baddr >> 2) & IL_EUA)|ILC_STAT); if (ilwait(sc, "verifying setaddr")) goto out; if (memcmp(sc->sc_stats.ils_addr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN) != 0) { aprint_error_dev(sc->sc_dev, "setaddr didn't work\n"); goto out; } }
Static void kue_init(void *xsc) { struct kue_softc *sc = xsc; struct ifnet *ifp = GET_IFP(sc); int s; u_char eaddr[ETHER_ADDR_LEN]; DPRINTFN(5,("%s: %s: enter\n", USBDEVNAME(sc->kue_dev),__func__)); if (ifp->if_flags & IFF_RUNNING) return; s = splnet(); memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); /* Set MAC address */ kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SET_MAC, 0, eaddr, ETHER_ADDR_LEN); sc->kue_rxfilt = KUE_RXFILT_UNICAST | KUE_RXFILT_BROADCAST; /* If we want promiscuous mode, set the allframes bit. */ if (ifp->if_flags & IFF_PROMISC) sc->kue_rxfilt |= KUE_RXFILT_PROMISC; kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt); /* I'm not sure how to tune these. */ #if 0 /* * Leave this one alone for now; setting it * wrong causes lockups on some machines/controllers. */ kue_setword(sc, KUE_CMD_SET_SOFS, 1); #endif kue_setword(sc, KUE_CMD_SET_URB_SIZE, 64); /* Init TX ring. */ if (kue_tx_list_init(sc) == ENOBUFS) { printf("%s: tx list init failed\n", USBDEVNAME(sc->kue_dev)); splx(s); return; } /* Init RX ring. */ if (kue_rx_list_init(sc) == ENOBUFS) { printf("%s: rx list init failed\n", USBDEVNAME(sc->kue_dev)); splx(s); return; } /* Load the multicast filter. */ kue_setmulti(sc); if (sc->kue_ep[KUE_ENDPT_RX] == NULL) { if (kue_open_pipes(sc)) { splx(s); return; } } ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; splx(s); }
Static int url_init(struct ifnet *ifp) { struct url_softc *sc = ifp->if_softc; struct mii_data *mii = GET_MII(sc); const u_char *eaddr; int i, rc, s; DPRINTF(("%s: %s: enter\n", device_xname(sc->sc_dev), __func__)); if (sc->sc_dying) return (EIO); s = splnet(); /* Cancel pending I/O and free all TX/RX buffers */ url_stop(ifp, 1); eaddr = CLLADDR(ifp->if_sadl); for (i = 0; i < ETHER_ADDR_LEN; i++) url_csr_write_1(sc, URL_IDR0 + i, eaddr[i]); /* Init transmission control register */ URL_CLRBIT(sc, URL_TCR, URL_TCR_TXRR1 | URL_TCR_TXRR0 | URL_TCR_IFG1 | URL_TCR_IFG0 | URL_TCR_NOCRC); /* Init receive control register */ URL_SETBIT2(sc, URL_RCR, URL_RCR_TAIL | URL_RCR_AD); if (ifp->if_flags & IFF_BROADCAST) URL_SETBIT2(sc, URL_RCR, URL_RCR_AB); else URL_CLRBIT2(sc, URL_RCR, URL_RCR_AB); /* If we want promiscuous mode, accept all physical frames. */ if (ifp->if_flags & IFF_PROMISC) URL_SETBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP); else URL_CLRBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP); /* Initialize transmit ring */ if (url_tx_list_init(sc) == ENOBUFS) { printf("%s: tx list init failed\n", device_xname(sc->sc_dev)); splx(s); return (EIO); } /* Initialize receive ring */ if (url_rx_list_init(sc) == ENOBUFS) { printf("%s: rx list init failed\n", device_xname(sc->sc_dev)); splx(s); return (EIO); } /* Load the multicast filter */ url_setmulti(sc); /* Enable RX and TX */ URL_SETBIT(sc, URL_CR, URL_CR_TE | URL_CR_RE); if ((rc = mii_mediachg(mii)) == ENXIO) rc = 0; else if (rc != 0) goto out; if (sc->sc_pipe_tx == NULL || sc->sc_pipe_rx == NULL) { if (url_openpipes(sc)) { splx(s); return (EIO); } } ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; callout_reset(&sc->sc_stat_ch, hz, url_tick, sc); out: splx(s); return rc; }
int rump_netconfig_auto_ipv6(const char *ifname) { struct ifnet *ifp; int ifindex; struct socket *rsso = NULL; int rv = 0; int hoplimit = 255; struct mbuf *m_nam = NULL, *m_outbuf = NULL; struct sockaddr_in6 *sin6; char *buf; struct nd_router_solicit rs; struct nd_opt_hdr opt; ifp = ifunit(ifname); if (ifp == NULL) { rv = ENXIO; goto out; } if (ifp->if_sadl->sdl_type != IFT_ETHER) { rv = EINVAL; goto out; } rv = socreate(PF_INET6, &rsso, SOCK_RAW, IPPROTO_ICMPV6, curlwp, NULL); if (rv != 0) goto out; ifindex = ifp->if_index; rv = so_setsockopt(curlwp, rsso, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof ifindex); if (rv != 0) goto out; rv = so_setsockopt(curlwp, rsso, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hoplimit, sizeof hoplimit); if (rv != 0) goto out; m_nam = m_get(M_WAIT, MT_SONAME); sin6 = mtod(m_nam, struct sockaddr_in6 *); sin6->sin6_len = m_nam->m_len = sizeof (*sin6); sin6->sin6_family = AF_INET6; netconfig_inet_pton6("ff02::2", &sin6->sin6_addr); #define rslen (sizeof rs + sizeof opt + ETHER_ADDR_LEN) CTASSERT(rslen <= MCLBYTES); m_outbuf = m_gethdr(M_WAIT, MT_DATA); m_clget(m_outbuf, M_WAIT); m_outbuf->m_pkthdr.len = m_outbuf->m_len = rslen; #if __NetBSD_Prereq__(7,99,31) m_set_rcvif(m_outbuf, NULL); #else m_outbuf->m_pkthdr.rcvif = NULL; #endif #undef rslen buf = mtod(m_outbuf, char *); memset(&rs, 0, sizeof rs); rs.nd_rs_type = ND_ROUTER_SOLICIT; memset(&opt, 0, sizeof opt); opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR; opt.nd_opt_len = 1; /* units of 8 octets */ memcpy(buf, &rs, sizeof rs); buf += sizeof rs; memcpy(buf, &opt, sizeof opt); buf += sizeof opt; memcpy(buf, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN); ip6_accept_rtadv = 1; rv = rump_netconfig_ifup(ifname); if (rv != 0) goto out; #if __NetBSD_Prereq__(7,99,12) rv = (*rsso->so_send)(rsso, (struct sockaddr *)sin6, NULL, m_outbuf, NULL, 0, curlwp); #else rv = (*rsso->so_send)(rsso, m_nam, NULL, m_outbuf, NULL, 0, curlwp); #endif if (rv == 0) /* *(so_send)() takes ownership of m_outbuf on success */ m_outbuf = NULL; else goto out; rv = 0; out: if (m_nam) m_freem(m_nam); if (m_outbuf) m_freem(m_outbuf); if (rsso) soclose(rsso); return rv; }
/* * How Command Block List Processing is done. * * A running CBL is never manipulated. If there is a CBL already running, * further CMDs are deferred until the current list is done. A new list is * setup when the old one has finished. * This eases programming. To manipulate a running CBL it is necessary to * suspend the Command Unit to avoid race conditions. After a suspend * is sent we have to wait for an interrupt that ACKs the suspend. Then * we can manipulate the CBL and resume operation. I am not sure that this * is more effective than the current, much simpler approach. => KISS * See i82596CA data sheet page 26. * * A CBL is running or on the way to be set up when (sc->sc_next_cb != 0). * * A CBL may consist of TX CMDs, and _only_ TX CMDs. * A TX CBL is running or on the way to be set up when * ((sc->sc_next_cb != 0) && (sc->sc_next_tbd != 0)). * * A CBL may consist of other non-TX CMDs like IAS or CONF, and _only_ * non-TX CMDs. * * This comes mostly through the way how an Ethernet driver works and * because running CBLs are not manipulated when they are on the way. If * if_start() is called there will be TX CMDs enqueued so we have a running * CBL and other CMDs from e.g. if_ioctl() will be deferred and vice versa. * * The Multicast Setup Command is special. A MCS needs more space than * a single CB has. Actual space requirement depends on the length of the * multicast list. So we always defer MCS until other CBLs are finished, * then we setup a CONF CMD in the first CB. The CONF CMD is needed to * turn ALLMULTI on the hardware on or off. The MCS is the 2nd CB and may * use all the remaining space in the CBL and the Transmit Buffer Descriptor * List. (Therefore CBL and TBDL must be continuous in physical and virtual * memory. This is guaranteed through the definitions of the list offsets * in i82596reg.h and because it is only a single DMA segment used for all * lists.) When ALLMULTI is enabled via the CONF CMD, the MCS is run with * a multicast list length of 0, thus disabling the multicast filter. * A deferred MCS is signaled via ((sc->sc_flags & IEE_WANT_MCAST) != 0) */ void iee_cb_setup(struct iee_softc *sc, uint32_t cmd) { struct iee_cb *cb = SC_CB(sc, sc->sc_next_cb); struct ifnet *ifp = &sc->sc_ethercom.ec_if; struct ether_multistep step; struct ether_multi *enm; memset(cb, 0, sc->sc_cb_sz); cb->cb_cmd = cmd; switch (cmd & IEE_CB_CMD) { case IEE_CB_CMD_NOP: /* NOP CMD */ break; case IEE_CB_CMD_IAS: /* Individual Address Setup */ memcpy(__UNVOLATILE(cb->cb_ind_addr), CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN); break; case IEE_CB_CMD_CONF: /* Configure */ memcpy(__UNVOLATILE(cb->cb_cf), sc->sc_cf, sc->sc_cf[0] & IEE_CF_0_CNT_M); break; case IEE_CB_CMD_MCS: /* Multicast Setup */ if (sc->sc_next_cb != 0) { sc->sc_flags |= IEE_WANT_MCAST; return; } sc->sc_flags &= ~IEE_WANT_MCAST; if ((sc->sc_cf[8] & IEE_CF_8_PRM) != 0) { /* Need no multicast filter in promisc mode. */ iee_cb_setup(sc, IEE_CB_CMD_CONF | IEE_CB_S | IEE_CB_EL | IEE_CB_I); return; } /* Leave room for a CONF CMD to en/dis-able ALLMULTI mode */ cb = SC_CB(sc, sc->sc_next_cb + 1); cb->cb_cmd = cmd; cb->cb_mcast.mc_size = 0; ETHER_FIRST_MULTI(step, &sc->sc_ethercom, enm); while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) != 0 || cb->cb_mcast.mc_size * ETHER_ADDR_LEN + 2 * sc->sc_cb_sz > sc->sc_cb_sz * IEE_NCB + sc->sc_tbd_sz * IEE_NTBD * IEE_NCB) { cb->cb_mcast.mc_size = 0; break; } memcpy(__UNVOLATILE(&cb->cb_mcast.mc_addrs[ cb->cb_mcast.mc_size * ETHER_ADDR_LEN]), enm->enm_addrlo, ETHER_ADDR_LEN); ETHER_NEXT_MULTI(step, enm); cb->cb_mcast.mc_size++; } if (cb->cb_mcast.mc_size == 0) { /* Can't do exact mcast filtering, do ALLMULTI mode. */ ifp->if_flags |= IFF_ALLMULTI; sc->sc_cf[11] &= ~IEE_CF_11_MCALL; } else { /* disable ALLMULTI and load mcast list */ ifp->if_flags &= ~IFF_ALLMULTI; sc->sc_cf[11] |= IEE_CF_11_MCALL; /* Mcast setup may need more than sc->sc_cb_sz bytes. */ bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map, sc->sc_cb_off, sc->sc_cb_sz * IEE_NCB + sc->sc_tbd_sz * IEE_NTBD * IEE_NCB, BUS_DMASYNC_PREWRITE); } iee_cb_setup(sc, IEE_CB_CMD_CONF); break; case IEE_CB_CMD_TR: /* Transmit */ cb->cb_transmit.tx_tbd_addr = IEE_SWAPA32(IEE_PHYS_SHMEM(sc->sc_tbd_off + sc->sc_tbd_sz * sc->sc_next_tbd)); cb->cb_cmd |= IEE_CB_SF; /* Always use Flexible Mode. */ break; case IEE_CB_CMD_TDR: /* Time Domain Reflectometry */ break; case IEE_CB_CMD_DUMP: /* Dump */ break; case IEE_CB_CMD_DIAG: /* Diagnose */ break; default: /* can't happen */ break; } cb->cb_link_addr = IEE_SWAPA32(IEE_PHYS_SHMEM(sc->sc_cb_off + sc->sc_cb_sz * (sc->sc_next_cb + 1))); IEE_CBSYNC(sc, sc->sc_next_cb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); sc->sc_next_cb++; ifp->if_timer = 5; }