- bzero((caddr_t)&info, sizeof(info));
- for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
- if (w->w_arg && w->w_arg != ifp->if_index)
- continue;
- ifa = ifp->if_addrhead.tqh_first;
- ifpaddr = ifa->ifa_addr;
- len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w);
- ifpaddr = 0;
- if (w->w_req && w->w_tmem) {
- register struct if_msghdr *ifm;
-
- ifm = (struct if_msghdr *)w->w_tmem;
- ifm->ifm_index = ifp->if_index;
- ifm->ifm_flags = (u_short)ifp->if_flags;
- ifm->ifm_data = ifp->if_data;
- ifm->ifm_addrs = info.rti_addrs;
- error = SYSCTL_OUT(w->w_req,(caddr_t)ifm, len);
+ cred = kauth_cred_proc_ref(current_proc());
+
+ bzero((caddr_t)&info, sizeof (info));
+
+ for (pass = 0; pass < 2; pass++) {
+ ifnet_head_lock_shared();
+
+ TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
+ if (error)
+ break;
+ if (w->w_arg && w->w_arg != ifp->if_index)
+ continue;
+ ifnet_lock_shared(ifp);
+ /*
+ * Holding ifnet lock here prevents the link address
+ * from changing contents, so no need to hold the ifa
+ * lock. The link address is always present; it's
+ * never freed.
+ */
+ ifa = ifp->if_lladdr;
+ info.rti_info[RTAX_IFP] = ifa->ifa_addr;
+ len = rt_msg2(RTM_IFINFO, &info, NULL, NULL, &cred);
+ if (pass == 0) {
+ total_len += len;
+ } else {
+ struct if_msghdr *ifm;
+
+ if (current_len + len > total_len) {
+ ifnet_lock_done(ifp);
+ error = ENOBUFS;
+ break;
+ }
+ info.rti_info[RTAX_IFP] = ifa->ifa_addr;
+ len = rt_msg2(RTM_IFINFO, &info,
+ (caddr_t)cp, NULL, &cred);
+ info.rti_info[RTAX_IFP] = NULL;
+
+ ifm = (struct if_msghdr *)(void *)cp;
+ ifm->ifm_index = ifp->if_index;
+ ifm->ifm_flags = (u_short)ifp->if_flags;
+ if_data_internal_to_if_data(ifp, &ifp->if_data,
+ &ifm->ifm_data);
+ ifm->ifm_addrs = info.rti_addrs;
+ /*
+ * <rdar://problem/32940901>
+ * Round bytes only for non-platform
+ */
+ if (!csproc_get_platform_binary(w->w_req->p)) {
+ ALIGN_BYTES(ifm->ifm_data.ifi_ibytes);
+ ALIGN_BYTES(ifm->ifm_data.ifi_obytes);
+ }
+
+ cp += len;
+ VERIFY(IS_P2ALIGNED(cp, sizeof (u_int32_t)));
+ current_len += len;
+ }
+ while ((ifa = ifa->ifa_link.tqe_next) != NULL) {
+ IFA_LOCK(ifa);
+ if (af && af != ifa->ifa_addr->sa_family) {
+ IFA_UNLOCK(ifa);
+ continue;
+ }
+ info.rti_info[RTAX_IFA] = ifa->ifa_addr;
+ info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
+ info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr;
+ len = rt_msg2(RTM_NEWADDR, &info, NULL, NULL,
+ &cred);
+ if (pass == 0) {
+ total_len += len;
+ } else {
+ struct ifa_msghdr *ifam;
+
+ if (current_len + len > total_len) {
+ IFA_UNLOCK(ifa);
+ error = ENOBUFS;
+ break;
+ }
+ len = rt_msg2(RTM_NEWADDR, &info,
+ (caddr_t)cp, NULL, &cred);
+
+ ifam = (struct ifa_msghdr *)(void *)cp;
+ ifam->ifam_index =
+ ifa->ifa_ifp->if_index;
+ ifam->ifam_flags = ifa->ifa_flags;
+ ifam->ifam_metric = ifa->ifa_metric;
+ ifam->ifam_addrs = info.rti_addrs;
+
+ cp += len;
+ VERIFY(IS_P2ALIGNED(cp,
+ sizeof (u_int32_t)));
+ current_len += len;
+ }
+ IFA_UNLOCK(ifa);
+ }
+ ifnet_lock_done(ifp);
+ info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] =
+ info.rti_info[RTAX_BRD] = NULL;
+ }
+
+ ifnet_head_done();
+
+ if (error != 0) {
+ if (error == ENOBUFS)
+ printf("%s: current_len (%d) + len (%d) > "
+ "total_len (%d)\n", __func__, current_len,
+ len, total_len);
+ break;
+ }
+
+ if (pass == 0) {
+ /* Better to return zero length buffer than ENOBUFS */
+ if (total_len == 0)
+ total_len = 1;
+ total_len += total_len >> 3;
+ total_buffer = _MALLOC(total_len, M_RTABLE,
+ M_ZERO | M_WAITOK);
+ if (total_buffer == NULL) {
+ printf("%s: _MALLOC(%d) failed\n", __func__,
+ total_len);
+ error = ENOBUFS;
+ break;
+ }
+ cp = total_buffer;
+ VERIFY(IS_P2ALIGNED(cp, sizeof (u_int32_t)));
+ } else {
+ error = SYSCTL_OUT(w->w_req, total_buffer, current_len);