+
+ clock_deadline_for_periodic_event(atv->tv_sec * NSEC_PER_SEC,
+ mach_absolute_time(), &deadline);
+ (void) thread_call_enter_delayed(arp_timeout_tcall, deadline);
+ }
+}
+
+/*
+ * Probe routine.
+ */
+static void
+arp_probe(thread_call_param_t arg0, thread_call_param_t arg1)
+{
+#pragma unused(arg0, arg1)
+ struct llinfo_arp *la, *ola;
+ struct timeval atv;
+ struct arptf_arg farg;
+
+ lck_mtx_lock(rnh_lock);
+ la = llinfo_arp.lh_first;
+ bzero(&farg, sizeof (farg));
+ farg.probing = TRUE;
+ while ((ola = la) != NULL) {
+ la = la->la_le.le_next;
+ arptfree(ola, &farg);
+ }
+ if (arp_verbose) {
+ log(LOG_DEBUG, "%s: found %u, aging %u, sticky %u, killed %u; "
+ "%u pkts held (%u bytes)\n", __func__, farg.found,
+ farg.aging, farg.sticky, farg.killed, farg.qlen,
+ farg.qsize);
+ }
+ atv.tv_usec = 0;
+ atv.tv_sec = MAX(arpt_probe, ARP_PROBE_TIME);
+ /* re-arm the probe if there's work to do */
+ arp_probe_run = 0;
+ if (farg.qlen > 0)
+ arp_sched_probe(&atv);
+ else if (arp_verbose)
+ log(LOG_DEBUG, "%s: not rescheduling probe\n", __func__);
+ lck_mtx_unlock(rnh_lock);
+}
+
+static void
+arp_sched_probe(struct timeval *atv)
+{
+ LCK_MTX_ASSERT(rnh_lock, LCK_MTX_ASSERT_OWNED);
+
+ if (!arp_probe_run) {
+ struct timeval tv;
+ uint64_t deadline = 0;
+
+ if (arp_probe_tcall == NULL) {
+ arp_probe_tcall =
+ thread_call_allocate(arp_probe, NULL);
+ VERIFY(arp_probe_tcall != NULL);
+ }
+
+ if (atv == NULL) {
+ tv.tv_usec = 0;
+ tv.tv_sec = MAX(arpt_probe, ARP_PROBE_TIME);
+ atv = &tv;
+ }
+ if (arp_verbose) {
+ log(LOG_DEBUG, "%s: probe scheduled in "
+ "T+%llus.%lluu\n", __func__,
+ (uint64_t)atv->tv_sec, (uint64_t)atv->tv_usec);
+ }
+ arp_probe_run = 1;
+
+ clock_deadline_for_periodic_event(atv->tv_sec * NSEC_PER_SEC,
+ mach_absolute_time(), &deadline);
+ (void) thread_call_enter_delayed(arp_probe_tcall, deadline);