+ if (ifp == NULL)
+ return (EINVAL);
+
+ ifp->if_output_bw.max_bw = ifp->if_input_bw.max_bw =
+ ifp->if_output_bw.eff_bw = ifp->if_input_bw.eff_bw = baudrate;
+
+ /* Pin if_baudrate to 32 bits until we can change the storage size */
+ ifp->if_baudrate = (baudrate > 0xFFFFFFFF) ? 0xFFFFFFFF : baudrate;
+
+ return (0);
+}
+
+u_int64_t
+ifnet_baudrate(struct ifnet *ifp)
+{
+ return ((ifp == NULL) ? 0 : ifp->if_baudrate);
+}
+
+errno_t
+ifnet_set_bandwidths(struct ifnet *ifp, struct if_bandwidths *output_bw,
+ struct if_bandwidths *input_bw)
+{
+ if (ifp == NULL)
+ return (EINVAL);
+
+ /* set input values first (if any), as output values depend on them */
+ if (input_bw != NULL)
+ (void) ifnet_set_input_bandwidths(ifp, input_bw);
+
+ if (output_bw != NULL)
+ (void) ifnet_set_output_bandwidths(ifp, output_bw, FALSE);
+
+ return (0);
+}
+
+static void
+ifnet_set_link_status_outbw(struct ifnet *ifp)
+{
+ struct if_wifi_status_v1 *sr;
+ sr = &ifp->if_link_status->ifsr_u.ifsr_wifi.if_wifi_u.if_status_v1;
+ if (ifp->if_output_bw.eff_bw != 0) {
+ sr->valid_bitmask |=
+ IF_WIFI_UL_EFFECTIVE_BANDWIDTH_VALID;
+ sr->ul_effective_bandwidth =
+ ifp->if_output_bw.eff_bw;
+ }
+ if (ifp->if_output_bw.max_bw != 0) {
+ sr->valid_bitmask |=
+ IF_WIFI_UL_MAX_BANDWIDTH_VALID;
+ sr->ul_max_bandwidth =
+ ifp->if_output_bw.max_bw;
+ }
+}
+
+errno_t
+ifnet_set_output_bandwidths(struct ifnet *ifp, struct if_bandwidths *bw,
+ boolean_t locked)
+{
+ struct if_bandwidths old_bw;
+ struct ifclassq *ifq;
+ u_int64_t br;
+
+ VERIFY(ifp != NULL && bw != NULL);
+
+ ifq = &ifp->if_snd;
+ if (!locked)
+ IFCQ_LOCK(ifq);
+ IFCQ_LOCK_ASSERT_HELD(ifq);
+
+ old_bw = ifp->if_output_bw;
+ if (bw->eff_bw != 0)
+ ifp->if_output_bw.eff_bw = bw->eff_bw;
+ if (bw->max_bw != 0)
+ ifp->if_output_bw.max_bw = bw->max_bw;
+ if (ifp->if_output_bw.eff_bw > ifp->if_output_bw.max_bw)
+ ifp->if_output_bw.max_bw = ifp->if_output_bw.eff_bw;
+ else if (ifp->if_output_bw.eff_bw == 0)
+ ifp->if_output_bw.eff_bw = ifp->if_output_bw.max_bw;
+
+ /* Pin if_baudrate to 32 bits */
+ br = MAX(ifp->if_output_bw.max_bw, ifp->if_input_bw.max_bw);
+ if (br != 0)
+ ifp->if_baudrate = (br > 0xFFFFFFFF) ? 0xFFFFFFFF : br;
+
+ /* Adjust queue parameters if needed */
+ if (old_bw.eff_bw != ifp->if_output_bw.eff_bw ||
+ old_bw.max_bw != ifp->if_output_bw.max_bw)
+ ifnet_update_sndq(ifq, CLASSQ_EV_LINK_BANDWIDTH);
+
+ if (!locked)
+ IFCQ_UNLOCK(ifq);
+
+ /*
+ * If this is a Wifi interface, update the values in
+ * if_link_status structure also.
+ */
+ if (IFNET_IS_WIFI(ifp) && ifp->if_link_status != NULL) {
+ lck_rw_lock_exclusive(&ifp->if_link_status_lock);
+ ifnet_set_link_status_outbw(ifp);
+ lck_rw_done(&ifp->if_link_status_lock);
+ }
+
+ return (0);
+}
+
+static void
+ifnet_set_link_status_inbw(struct ifnet *ifp)
+{
+ struct if_wifi_status_v1 *sr;
+
+ sr = &ifp->if_link_status->ifsr_u.ifsr_wifi.if_wifi_u.if_status_v1;
+ if (ifp->if_input_bw.eff_bw != 0) {
+ sr->valid_bitmask |=
+ IF_WIFI_DL_EFFECTIVE_BANDWIDTH_VALID;
+ sr->dl_effective_bandwidth =
+ ifp->if_input_bw.eff_bw;
+ }
+ if (ifp->if_input_bw.max_bw != 0) {
+ sr->valid_bitmask |=
+ IF_WIFI_DL_MAX_BANDWIDTH_VALID;
+ sr->dl_max_bandwidth = ifp->if_input_bw.max_bw;
+ }
+}
+
+errno_t
+ifnet_set_input_bandwidths(struct ifnet *ifp, struct if_bandwidths *bw)
+{
+ struct if_bandwidths old_bw;
+
+ VERIFY(ifp != NULL && bw != NULL);
+
+ old_bw = ifp->if_input_bw;
+ if (bw->eff_bw != 0)
+ ifp->if_input_bw.eff_bw = bw->eff_bw;
+ if (bw->max_bw != 0)
+ ifp->if_input_bw.max_bw = bw->max_bw;
+ if (ifp->if_input_bw.eff_bw > ifp->if_input_bw.max_bw)
+ ifp->if_input_bw.max_bw = ifp->if_input_bw.eff_bw;
+ else if (ifp->if_input_bw.eff_bw == 0)
+ ifp->if_input_bw.eff_bw = ifp->if_input_bw.max_bw;
+
+ if (IFNET_IS_WIFI(ifp) && ifp->if_link_status != NULL) {
+ lck_rw_lock_exclusive(&ifp->if_link_status_lock);
+ ifnet_set_link_status_inbw(ifp);
+ lck_rw_done(&ifp->if_link_status_lock);
+ }
+
+ if (old_bw.eff_bw != ifp->if_input_bw.eff_bw ||
+ old_bw.max_bw != ifp->if_input_bw.max_bw)
+ ifnet_update_rcv(ifp, CLASSQ_EV_LINK_BANDWIDTH);
+
+ return (0);
+}
+
+u_int64_t
+ifnet_output_linkrate(struct ifnet *ifp)
+{
+ struct ifclassq *ifq = &ifp->if_snd;
+ u_int64_t rate;
+
+ IFCQ_LOCK_ASSERT_HELD(ifq);
+
+ rate = ifp->if_output_bw.eff_bw;
+ if (IFCQ_TBR_IS_ENABLED(ifq)) {
+ u_int64_t tbr_rate = ifp->if_snd.ifcq_tbr.tbr_rate_raw;
+ VERIFY(tbr_rate > 0);
+ rate = MIN(rate, ifp->if_snd.ifcq_tbr.tbr_rate_raw);
+ }
+
+ return (rate);
+}
+
+u_int64_t
+ifnet_input_linkrate(struct ifnet *ifp)
+{
+ return (ifp->if_input_bw.eff_bw);
+}
+
+errno_t
+ifnet_bandwidths(struct ifnet *ifp, struct if_bandwidths *output_bw,
+ struct if_bandwidths *input_bw)
+{
+ if (ifp == NULL)
+ return (EINVAL);
+
+ if (output_bw != NULL)
+ *output_bw = ifp->if_output_bw;
+ if (input_bw != NULL)
+ *input_bw = ifp->if_input_bw;
+
+ return (0);
+}
+
+errno_t
+ifnet_set_latencies(struct ifnet *ifp, struct if_latencies *output_lt,
+ struct if_latencies *input_lt)
+{
+ if (ifp == NULL)
+ return (EINVAL);
+
+ if (output_lt != NULL)
+ (void) ifnet_set_output_latencies(ifp, output_lt, FALSE);
+
+ if (input_lt != NULL)
+ (void) ifnet_set_input_latencies(ifp, input_lt);
+
+ return (0);
+}
+
+errno_t
+ifnet_set_output_latencies(struct ifnet *ifp, struct if_latencies *lt,
+ boolean_t locked)
+{
+ struct if_latencies old_lt;
+ struct ifclassq *ifq;
+
+ VERIFY(ifp != NULL && lt != NULL);
+
+ ifq = &ifp->if_snd;
+ if (!locked)
+ IFCQ_LOCK(ifq);
+ IFCQ_LOCK_ASSERT_HELD(ifq);
+
+ old_lt = ifp->if_output_lt;
+ if (lt->eff_lt != 0)
+ ifp->if_output_lt.eff_lt = lt->eff_lt;
+ if (lt->max_lt != 0)
+ ifp->if_output_lt.max_lt = lt->max_lt;
+ if (ifp->if_output_lt.eff_lt > ifp->if_output_lt.max_lt)
+ ifp->if_output_lt.max_lt = ifp->if_output_lt.eff_lt;
+ else if (ifp->if_output_lt.eff_lt == 0)
+ ifp->if_output_lt.eff_lt = ifp->if_output_lt.max_lt;
+
+ /* Adjust queue parameters if needed */
+ if (old_lt.eff_lt != ifp->if_output_lt.eff_lt ||
+ old_lt.max_lt != ifp->if_output_lt.max_lt)
+ ifnet_update_sndq(ifq, CLASSQ_EV_LINK_LATENCY);
+
+ if (!locked)
+ IFCQ_UNLOCK(ifq);
+
+ return (0);
+}
+
+errno_t
+ifnet_set_input_latencies(struct ifnet *ifp, struct if_latencies *lt)
+{
+ struct if_latencies old_lt;
+
+ VERIFY(ifp != NULL && lt != NULL);
+
+ old_lt = ifp->if_input_lt;
+ if (lt->eff_lt != 0)
+ ifp->if_input_lt.eff_lt = lt->eff_lt;
+ if (lt->max_lt != 0)
+ ifp->if_input_lt.max_lt = lt->max_lt;
+ if (ifp->if_input_lt.eff_lt > ifp->if_input_lt.max_lt)
+ ifp->if_input_lt.max_lt = ifp->if_input_lt.eff_lt;
+ else if (ifp->if_input_lt.eff_lt == 0)
+ ifp->if_input_lt.eff_lt = ifp->if_input_lt.max_lt;
+
+ if (old_lt.eff_lt != ifp->if_input_lt.eff_lt ||
+ old_lt.max_lt != ifp->if_input_lt.max_lt)
+ ifnet_update_rcv(ifp, CLASSQ_EV_LINK_LATENCY);
+
+ return (0);
+}
+
+errno_t
+ifnet_latencies(struct ifnet *ifp, struct if_latencies *output_lt,
+ struct if_latencies *input_lt)
+{
+ if (ifp == NULL)
+ return (EINVAL);
+
+ if (output_lt != NULL)
+ *output_lt = ifp->if_output_lt;
+ if (input_lt != NULL)
+ *input_lt = ifp->if_input_lt;
+
+ return (0);
+}
+
+errno_t
+ifnet_set_poll_params(struct ifnet *ifp, struct ifnet_poll_params *p)
+{
+ errno_t err;
+
+ if (ifp == NULL)
+ return (EINVAL);
+ else if (!ifnet_is_attached(ifp, 1))
+ return (ENXIO);
+
+ err = dlil_rxpoll_set_params(ifp, p, FALSE);
+
+ /* Release the io ref count */
+ ifnet_decr_iorefcnt(ifp);
+
+ return (err);
+}
+
+errno_t
+ifnet_poll_params(struct ifnet *ifp, struct ifnet_poll_params *p)
+{
+ errno_t err;
+
+ if (ifp == NULL || p == NULL)
+ return (EINVAL);
+ else if (!ifnet_is_attached(ifp, 1))
+ return (ENXIO);
+
+ err = dlil_rxpoll_get_params(ifp, p);
+
+ /* Release the io ref count */
+ ifnet_decr_iorefcnt(ifp);
+
+ return (err);
+}
+
+errno_t
+ifnet_stat_increment(struct ifnet *ifp,
+ const struct ifnet_stat_increment_param *s)
+{
+ if (ifp == NULL)
+ return (EINVAL);
+
+ if (s->packets_in != 0)
+ atomic_add_64(&ifp->if_data.ifi_ipackets, s->packets_in);
+ if (s->bytes_in != 0)
+ atomic_add_64(&ifp->if_data.ifi_ibytes, s->bytes_in);
+ if (s->errors_in != 0)
+ atomic_add_64(&ifp->if_data.ifi_ierrors, s->errors_in);
+
+ if (s->packets_out != 0)
+ atomic_add_64(&ifp->if_data.ifi_opackets, s->packets_out);
+ if (s->bytes_out != 0)
+ atomic_add_64(&ifp->if_data.ifi_obytes, s->bytes_out);
+ if (s->errors_out != 0)
+ atomic_add_64(&ifp->if_data.ifi_oerrors, s->errors_out);
+
+ if (s->collisions != 0)
+ atomic_add_64(&ifp->if_data.ifi_collisions, s->collisions);
+ if (s->dropped != 0)
+ atomic_add_64(&ifp->if_data.ifi_iqdrops, s->dropped);
+
+ /* Touch the last change time. */
+ TOUCHLASTCHANGE(&ifp->if_lastchange);
+
+ return (0);
+}
+
+errno_t
+ifnet_stat_increment_in(struct ifnet *ifp, u_int32_t packets_in,
+ u_int32_t bytes_in, u_int32_t errors_in)
+{
+ if (ifp == NULL)
+ return (EINVAL);
+
+ if (packets_in != 0)
+ atomic_add_64(&ifp->if_data.ifi_ipackets, packets_in);
+ if (bytes_in != 0)
+ atomic_add_64(&ifp->if_data.ifi_ibytes, bytes_in);
+ if (errors_in != 0)
+ atomic_add_64(&ifp->if_data.ifi_ierrors, errors_in);
+
+ TOUCHLASTCHANGE(&ifp->if_lastchange);
+
+ return (0);
+}
+
+errno_t
+ifnet_stat_increment_out(struct ifnet *ifp, u_int32_t packets_out,
+ u_int32_t bytes_out, u_int32_t errors_out)
+{
+ if (ifp == NULL)
+ return (EINVAL);
+
+ if (packets_out != 0)
+ atomic_add_64(&ifp->if_data.ifi_opackets, packets_out);
+ if (bytes_out != 0)
+ atomic_add_64(&ifp->if_data.ifi_obytes, bytes_out);
+ if (errors_out != 0)
+ atomic_add_64(&ifp->if_data.ifi_oerrors, errors_out);
+
+ TOUCHLASTCHANGE(&ifp->if_lastchange);
+
+ return (0);
+}
+
+errno_t
+ifnet_set_stat(struct ifnet *ifp, const struct ifnet_stats_param *s)
+{
+ if (ifp == NULL)
+ return (EINVAL);
+
+ atomic_set_64(&ifp->if_data.ifi_ipackets, s->packets_in);
+ atomic_set_64(&ifp->if_data.ifi_ibytes, s->bytes_in);
+ atomic_set_64(&ifp->if_data.ifi_imcasts, s->multicasts_in);
+ atomic_set_64(&ifp->if_data.ifi_ierrors, s->errors_in);
+
+ atomic_set_64(&ifp->if_data.ifi_opackets, s->packets_out);
+ atomic_set_64(&ifp->if_data.ifi_obytes, s->bytes_out);
+ atomic_set_64(&ifp->if_data.ifi_omcasts, s->multicasts_out);
+ atomic_set_64(&ifp->if_data.ifi_oerrors, s->errors_out);
+
+ atomic_set_64(&ifp->if_data.ifi_collisions, s->collisions);
+ atomic_set_64(&ifp->if_data.ifi_iqdrops, s->dropped);
+ atomic_set_64(&ifp->if_data.ifi_noproto, s->no_protocol);
+
+ /* Touch the last change time. */
+ TOUCHLASTCHANGE(&ifp->if_lastchange);
+
+ return (0);
+}
+
+errno_t
+ifnet_stat(struct ifnet *ifp, struct ifnet_stats_param *s)
+{
+ if (ifp == NULL)
+ return (EINVAL);
+
+ atomic_get_64(s->packets_in, &ifp->if_data.ifi_ipackets);
+ atomic_get_64(s->bytes_in, &ifp->if_data.ifi_ibytes);
+ atomic_get_64(s->multicasts_in, &ifp->if_data.ifi_imcasts);
+ atomic_get_64(s->errors_in, &ifp->if_data.ifi_ierrors);
+
+ atomic_get_64(s->packets_out, &ifp->if_data.ifi_opackets);
+ atomic_get_64(s->bytes_out, &ifp->if_data.ifi_obytes);
+ atomic_get_64(s->multicasts_out, &ifp->if_data.ifi_omcasts);
+ atomic_get_64(s->errors_out, &ifp->if_data.ifi_oerrors);
+
+ atomic_get_64(s->collisions, &ifp->if_data.ifi_collisions);
+ atomic_get_64(s->dropped, &ifp->if_data.ifi_iqdrops);
+ atomic_get_64(s->no_protocol, &ifp->if_data.ifi_noproto);
+
+ return (0);
+}
+
+errno_t
+ifnet_touch_lastchange(ifnet_t interface)
+{
+ if (interface == NULL)
+ return (EINVAL);
+
+ TOUCHLASTCHANGE(&interface->if_lastchange);
+
+ return (0);
+}
+
+errno_t
+ifnet_lastchange(ifnet_t interface, struct timeval *last_change)
+{
+ if (interface == NULL)
+ return (EINVAL);
+
+ *last_change = interface->if_data.ifi_lastchange;
+ /* Crude conversion from uptime to calendar time */
+ last_change->tv_sec += boottime_sec();
+
+ return (0);
+}
+
+errno_t
+ifnet_get_address_list(ifnet_t interface, ifaddr_t **addresses)
+{
+ return (addresses == NULL ? EINVAL :
+ ifnet_get_address_list_family(interface, addresses, 0));
+}
+
+struct ifnet_addr_list {
+ SLIST_ENTRY(ifnet_addr_list) ifal_le;
+ struct ifaddr *ifal_ifa;
+};
+
+errno_t
+ifnet_get_address_list_family(ifnet_t interface, ifaddr_t **addresses,
+ sa_family_t family)
+{
+ return (ifnet_get_address_list_family_internal(interface, addresses,
+ family, 0, M_NOWAIT, 0));
+}
+
+errno_t
+ifnet_get_inuse_address_list(ifnet_t interface, ifaddr_t **addresses)
+{
+ return (addresses == NULL ? EINVAL :
+ ifnet_get_address_list_family_internal(interface, addresses,
+ 0, 0, M_NOWAIT, 1));
+}
+
+extern uint32_t tcp_find_anypcb_byaddr(struct ifaddr *ifa);
+
+extern uint32_t udp_find_anypcb_byaddr(struct ifaddr *ifa);
+
+__private_extern__ errno_t
+ifnet_get_address_list_family_internal(ifnet_t interface, ifaddr_t **addresses,
+ sa_family_t family, int detached, int how, int return_inuse_addrs)
+{
+ SLIST_HEAD(, ifnet_addr_list) ifal_head;
+ struct ifnet_addr_list *ifal, *ifal_tmp;
+ struct ifnet *ifp;
+ int count = 0;
+ errno_t err = 0;
+ int usecount = 0;
+ int index = 0;
+
+ SLIST_INIT(&ifal_head);
+
+ if (addresses == NULL) {
+ err = EINVAL;
+ goto done;
+ }
+ *addresses = NULL;
+
+ if (detached) {
+ /*
+ * Interface has been detached, so skip the lookup
+ * at ifnet_head and go directly to inner loop.
+ */
+ ifp = interface;
+ if (ifp == NULL) {
+ err = EINVAL;
+ goto done;
+ }
+ goto one;
+ }
+
+ ifnet_head_lock_shared();
+ TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
+ if (interface != NULL && ifp != interface)
+ continue;
+one: