+/*
+ * ND6 router advertisement kernel notification
+ */
+void
+nd6_post_msg(u_int32_t code, struct nd_prefix_list *prefix_list,
+ u_int32_t list_length, u_int32_t mtu, char *dl_addr, u_int32_t dl_addr_len)
+{
+ struct kev_msg ev_msg;
+ struct kev_nd6_ra_data nd6_ra_msg_data;
+ struct nd_prefix_list *itr = prefix_list;
+
+ bzero(&ev_msg, sizeof(struct kev_msg));
+ ev_msg.vendor_code = KEV_VENDOR_APPLE;
+ ev_msg.kev_class = KEV_NETWORK_CLASS;
+ ev_msg.kev_subclass = KEV_ND6_SUBCLASS;
+ ev_msg.event_code = code;
+
+ bzero(&nd6_ra_msg_data, sizeof(nd6_ra_msg_data));
+ nd6_ra_msg_data.lladdrlen = (dl_addr_len <= ND6_ROUTER_LL_SIZE) ?
+ dl_addr_len : ND6_ROUTER_LL_SIZE;
+ bcopy(dl_addr, &nd6_ra_msg_data.lladdr, nd6_ra_msg_data.lladdrlen);
+
+ if (mtu > 0 && mtu >= IPV6_MMTU) {
+ nd6_ra_msg_data.mtu = mtu;
+ nd6_ra_msg_data.flags |= KEV_ND6_DATA_VALID_MTU;
+ }
+
+ if (list_length > 0 && prefix_list != NULL) {
+ nd6_ra_msg_data.list_length = list_length;
+ nd6_ra_msg_data.flags |= KEV_ND6_DATA_VALID_PREFIX;
+ }
+
+ while (itr != NULL && nd6_ra_msg_data.list_index < list_length) {
+ bcopy(&itr->pr.ndpr_prefix, &nd6_ra_msg_data.prefix.prefix,
+ sizeof (nd6_ra_msg_data.prefix.prefix));
+ nd6_ra_msg_data.prefix.raflags = itr->pr.ndpr_raf;
+ nd6_ra_msg_data.prefix.prefixlen = itr->pr.ndpr_plen;
+ nd6_ra_msg_data.prefix.origin = PR_ORIG_RA;
+ nd6_ra_msg_data.prefix.vltime = itr->pr.ndpr_vltime;
+ nd6_ra_msg_data.prefix.pltime = itr->pr.ndpr_pltime;
+ nd6_ra_msg_data.prefix.expire = itr->pr.ndpr_expire;
+ nd6_ra_msg_data.prefix.flags = itr->pr.ndpr_stateflags;
+ nd6_ra_msg_data.prefix.refcnt = itr->pr.ndpr_addrcnt;
+ nd6_ra_msg_data.prefix.if_index = itr->pr.ndpr_ifp->if_index;
+
+ /* send the message up */
+ ev_msg.dv[0].data_ptr = &nd6_ra_msg_data;
+ ev_msg.dv[0].data_length = sizeof(nd6_ra_msg_data);
+ ev_msg.dv[1].data_length = 0;
+ kev_post_msg(&ev_msg);
+
+ /* clean up for the next prefix */
+ bzero(&nd6_ra_msg_data.prefix, sizeof(nd6_ra_msg_data.prefix));
+ itr = itr->next;
+ nd6_ra_msg_data.list_index++;
+ }
+}
+