static bool npf_log(npf_cache_t *npc, nbuf_t *nbuf, void *meta, int *decision) { struct mbuf *m = nbuf_head_mbuf(nbuf); const npf_ext_log_t *log = meta; ifnet_t *ifp; int family; /* Set the address family. */ if (npf_iscached(npc, NPC_IP4)) { family = AF_INET; } else if (npf_iscached(npc, NPC_IP6)) { family = AF_INET6; } else { family = AF_UNSPEC; } KERNEL_LOCK(1, NULL); /* Find a pseudo-interface to log. */ ifp = if_byindex(log->if_idx); if (ifp == NULL) { /* No interface. */ KERNEL_UNLOCK_ONE(NULL); return true; } /* Pass through BPF. */ ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; bpf_mtap_af(ifp, family, m); KERNEL_UNLOCK_ONE(NULL); return true; }
/* * generate standard sockaddr_in6 from embedded form. */ int sa6_recoverscope(struct sockaddr_in6 *sin6) { uint32_t zoneid; if (sin6->sin6_scope_id != 0) { log(LOG_NOTICE, "sa6_recoverscope: assumption failure (non 0 ID): %s%%%d\n", ip6_sprintf(&sin6->sin6_addr), sin6->sin6_scope_id); /* XXX: proceed anyway... */ } if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) { /* * KAME assumption: link id == interface id */ zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]); if (zoneid) { int s = pserialize_read_enter(); if (!if_byindex(zoneid)) { pserialize_read_exit(s); return (ENXIO); } pserialize_read_exit(s); sin6->sin6_addr.s6_addr16[1] = 0; sin6->sin6_scope_id = zoneid; } } return 0; }
/* * Validate the specified scope zone ID in the sin6_scope_id field. If the ID * is unspecified (=0), needs to be specified, and the default zone ID can be * used, the default value will be used. * This routine then generates the kernel-internal form: if the address scope * of is interface-local or link-local, embed the interface index in the * address. */ int sa6_embedscope(struct sockaddr_in6 *sin6, int defaultok) { struct ifnet *ifp; uint32_t zoneid; if ((zoneid = sin6->sin6_scope_id) == 0 && defaultok) zoneid = scope6_addr2default(&sin6->sin6_addr); if (zoneid != 0 && (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr))) { int s; /* * At this moment, we only check interface-local and * link-local scope IDs, and use interface indices as the * zone IDs assuming a one-to-one mapping between interfaces * and links. */ s = pserialize_read_enter(); ifp = if_byindex(zoneid); if (ifp == NULL) { pserialize_read_exit(s); return (ENXIO); } pserialize_read_exit(s); /* XXX assignment to 16bit from 32bit variable */ sin6->sin6_addr.s6_addr16[1] = htons(zoneid & 0xffff); sin6->sin6_scope_id = 0; } return 0; }
int scope6_set(struct ifnet *ifp, const struct scope6_id *idlist) { int i; int error = 0; struct scope6_id *sid = SID(ifp); if (!sid) /* paranoid? */ return (EINVAL); /* * XXX: We need more consistency checks of the relationship among * scopes (e.g. an organization should be larger than a site). */ /* * TODO(XXX): after setting, we should reflect the changes to * interface addresses, routing table entries, PCB entries... */ for (i = 0; i < 16; i++) { if (idlist->s6id_list[i] && idlist->s6id_list[i] != sid->s6id_list[i]) { int s; /* * An interface zone ID must be the corresponding * interface index by definition. */ if (i == IPV6_ADDR_SCOPE_INTFACELOCAL && idlist->s6id_list[i] != ifp->if_index) return (EINVAL); s = pserialize_read_enter(); if (i == IPV6_ADDR_SCOPE_LINKLOCAL && !if_byindex(idlist->s6id_list[i])) { /* * XXX: theoretically, there should be no * relationship between link IDs and interface * IDs, but we check the consistency for * safety in later use. */ pserialize_read_exit(s); return (EINVAL); } pserialize_read_exit(s); /* * XXX: we must need lots of work in this case, * but we simply set the new value in this initial * implementation. */ sid->s6id_list[i] = idlist->s6id_list[i]; } } return (error); }
/* * Add a mif to the mif table */ static int add_m6if(struct mif6ctl *mifcp) { struct mif6 *mifp; struct ifnet *ifp; struct sockaddr_in6 sin6; int error, s; #ifdef notyet struct tbf *m_tbf = tbftable + mifcp->mif6c_mifi; #endif if (mifcp->mif6c_mifi >= MAXMIFS) return EINVAL; mifp = mif6table + mifcp->mif6c_mifi; if (mifp->m6_ifp) return EADDRINUSE; /* XXX: is it appropriate? */ if (!mifcp->mif6c_pifi || (ifp = if_byindex(mifcp->mif6c_pifi)) == NULL) return ENXIO; if (mifcp->mif6c_flags & MIFF_REGISTER) { ifp = &multicast_register_if6; if (reg_mif_num == (mifi_t)-1) { strlcpy(ifp->if_xname, "register_mif", sizeof(ifp->if_xname)); ifp->if_flags |= IFF_LOOPBACK; ifp->if_index = mifcp->mif6c_mifi; reg_mif_num = mifcp->mif6c_mifi; if_attach(ifp); } } /* if REGISTER */ else { /* Make sure the interface supports multicast */ if ((ifp->if_flags & IFF_MULTICAST) == 0) return EOPNOTSUPP; s = splsoftnet(); /* * Enable promiscuous reception of all IPv6 multicasts * from the interface. */ sin6.sin6_family = AF_INET6; sin6.sin6_addr = in6addr_any; error = if_mcast_op(ifp, SIOCADDMULTI, sin6tosa(&sin6)); splx(s); if (error) return error; } s = splsoftnet(); mifp->m6_flags = mifcp->mif6c_flags; mifp->m6_ifp = ifp; #ifdef notyet /* scaling up here allows division by 1024 in critical code */ mifp->m6_rate_limit = mifcp->mif6c_rate_limit * 1024 / 1000; #endif /* initialize per mif pkt counters */ mifp->m6_pkt_in = 0; mifp->m6_pkt_out = 0; mifp->m6_bytes_in = 0; mifp->m6_bytes_out = 0; splx(s); /* Adjust nummifs up if the mifi is higher than nummifs */ if (nummifs <= mifcp->mif6c_mifi) nummifs = mifcp->mif6c_mifi + 1; #ifdef MRT6DEBUG if (mrt6debug) log(LOG_DEBUG, "add_mif #%d, phyint %s\n", mifcp->mif6c_mifi, ifp->if_xname); #endif return 0; }