static errno_t utun_ctl_setopt( __unused kern_ctl_ref kctlref, __unused u_int32_t unit, void *unitinfo, int opt, void *data, size_t len) { struct utun_pcb *pcb = unitinfo; errno_t result = 0; /* check for privileges for privileged options */ switch (opt) { case UTUN_OPT_FLAGS: case UTUN_OPT_EXT_IFDATA_STATS: case UTUN_OPT_SET_DELEGATE_INTERFACE: if (kauth_cred_issuser(kauth_cred_get()) == 0) { return EPERM; } break; } switch (opt) { case UTUN_OPT_FLAGS: if (len != sizeof(u_int32_t)) { result = EMSGSIZE; } else { u_int32_t old_flags = pcb->utun_flags; pcb->utun_flags = *(u_int32_t *)data; if (((old_flags ^ pcb->utun_flags) & UTUN_FLAGS_ENABLE_PROC_UUID)) { // If UTUN_FLAGS_ENABLE_PROC_UUID flag changed, update bpf bpfdetach(pcb->utun_ifp); bpfattach(pcb->utun_ifp, DLT_NULL, UTUN_HEADER_SIZE(pcb)); } } break; case UTUN_OPT_EXT_IFDATA_STATS: if (len != sizeof(int)) { result = EMSGSIZE; break; } pcb->utun_ext_ifdata_stats = (*(int *)data) ? 1 : 0; break; case UTUN_OPT_INC_IFDATA_STATS_IN: case UTUN_OPT_INC_IFDATA_STATS_OUT: { struct utun_stats_param *utsp = (struct utun_stats_param *)data; if (utsp == NULL || len < sizeof(struct utun_stats_param)) { result = EINVAL; break; } if (!pcb->utun_ext_ifdata_stats) { result = EINVAL; break; } if (opt == UTUN_OPT_INC_IFDATA_STATS_IN) ifnet_stat_increment_in(pcb->utun_ifp, utsp->utsp_packets, utsp->utsp_bytes, utsp->utsp_errors); else ifnet_stat_increment_out(pcb->utun_ifp, utsp->utsp_packets, utsp->utsp_bytes, utsp->utsp_errors); break; } case UTUN_OPT_SET_DELEGATE_INTERFACE: { ifnet_t del_ifp = NULL; char name[IFNAMSIZ]; if (len > IFNAMSIZ - 1) { result = EMSGSIZE; break; } if (len != 0) { /* if len==0, del_ifp will be NULL causing the delegate to be removed */ bcopy(data, name, len); name[len] = 0; result = ifnet_find_by_name(name, &del_ifp); } if (result == 0) { result = ifnet_set_delegate(pcb->utun_ifp, del_ifp); if (del_ifp) ifnet_release(del_ifp); } break; } case UTUN_OPT_MAX_PENDING_PACKETS: { u_int32_t max_pending_packets = 0; if (len != sizeof(u_int32_t)) { result = EMSGSIZE; break; } max_pending_packets = *(u_int32_t *)data; if (max_pending_packets == 0) { result = EINVAL; break; } pcb->utun_max_pending_packets = max_pending_packets; break; } default: { result = ENOPROTOOPT; break; } } return result; }
static errno_t utun_ctl_setopt( __unused kern_ctl_ref kctlref, __unused u_int32_t unit, void *unitinfo, int opt, void *data, size_t len) { struct utun_pcb *pcb = unitinfo; errno_t result = 0; /* check for privileges for privileged options */ switch (opt) { case UTUN_OPT_FLAGS: case UTUN_OPT_EXT_IFDATA_STATS: case UTUN_OPT_SET_DELEGATE_INTERFACE: if (kauth_cred_issuser(kauth_cred_get()) == 0) { return EPERM; } break; } switch (opt) { case UTUN_OPT_FLAGS: if (len != sizeof(u_int32_t)) result = EMSGSIZE; else pcb->utun_flags = *(u_int32_t *)data; break; case UTUN_OPT_ENABLE_CRYPTO: result = utun_ctl_enable_crypto(kctlref, unit, unitinfo, opt, data, len); break; case UTUN_OPT_CONFIG_CRYPTO_KEYS: result = utun_ctl_config_crypto_keys(kctlref, unit, unitinfo, opt, data, len); break; case UTUN_OPT_UNCONFIG_CRYPTO_KEYS: result = utun_ctl_unconfig_crypto_keys(kctlref, unit, unitinfo, opt, data, len); break; case UTUN_OPT_DISABLE_CRYPTO: result = utun_ctl_disable_crypto(kctlref, unit, unitinfo, opt, data, len); break; case UTUN_OPT_STOP_CRYPTO_DATA_TRAFFIC: result = utun_ctl_stop_crypto_data_traffic(kctlref, unit, unitinfo, opt, data, len); break; case UTUN_OPT_START_CRYPTO_DATA_TRAFFIC: result = utun_ctl_start_crypto_data_traffic(kctlref, unit, unitinfo, opt, data, len); break; case UTUN_OPT_CONFIG_CRYPTO_FRAMER: result = utun_ctl_config_crypto_framer(kctlref, unit, unitinfo, opt, data, len); break; case UTUN_OPT_UNCONFIG_CRYPTO_FRAMER: result = utun_ctl_unconfig_crypto_framer(kctlref, unit, unitinfo, opt, data, len); break; case UTUN_OPT_EXT_IFDATA_STATS: if (len != sizeof(int)) { result = EMSGSIZE; break; } pcb->utun_ext_ifdata_stats = (*(int *)data) ? 1 : 0; break; case UTUN_OPT_INC_IFDATA_STATS_IN: case UTUN_OPT_INC_IFDATA_STATS_OUT: { struct utun_stats_param *utsp = (struct utun_stats_param *)data; if (utsp == NULL || len < sizeof(struct utun_stats_param)) { result = EINVAL; break; } if (!pcb->utun_ext_ifdata_stats) { result = EINVAL; break; } if (opt == UTUN_OPT_INC_IFDATA_STATS_IN) ifnet_stat_increment_in(pcb->utun_ifp, utsp->utsp_packets, utsp->utsp_bytes, utsp->utsp_errors); else ifnet_stat_increment_out(pcb->utun_ifp, utsp->utsp_packets, utsp->utsp_bytes, utsp->utsp_errors); break; } case UTUN_OPT_SET_DELEGATE_INTERFACE: { ifnet_t del_ifp = NULL; char name[IFNAMSIZ]; if (len > IFNAMSIZ - 1) { result = EMSGSIZE; break; } if (len != 0) { /* if len==0, del_ifp will be NULL causing the delegate to be removed */ bcopy(data, name, len); name[len] = 0; result = ifnet_find_by_name(name, &del_ifp); } if (result == 0) { result = ifnet_set_delegate(pcb->utun_ifp, del_ifp); if (del_ifp) ifnet_release(del_ifp); } break; } default: result = ENOPROTOOPT; break; } return result; }
static errno_t ipsec_ctl_setopt(__unused kern_ctl_ref kctlref, __unused u_int32_t unit, void *unitinfo, int opt, void *data, size_t len) { struct ipsec_pcb *pcb = unitinfo; errno_t result = 0; /* check for privileges for privileged options */ switch (opt) { case IPSEC_OPT_FLAGS: case IPSEC_OPT_EXT_IFDATA_STATS: case IPSEC_OPT_SET_DELEGATE_INTERFACE: case IPSEC_OPT_OUTPUT_TRAFFIC_CLASS: if (kauth_cred_issuser(kauth_cred_get()) == 0) { return EPERM; } break; } switch (opt) { case IPSEC_OPT_FLAGS: if (len != sizeof(u_int32_t)) result = EMSGSIZE; else pcb->ipsec_flags = *(u_int32_t *)data; break; case IPSEC_OPT_EXT_IFDATA_STATS: if (len != sizeof(int)) { result = EMSGSIZE; break; } pcb->ipsec_ext_ifdata_stats = (*(int *)data) ? 1 : 0; break; case IPSEC_OPT_INC_IFDATA_STATS_IN: case IPSEC_OPT_INC_IFDATA_STATS_OUT: { struct ipsec_stats_param *utsp = (struct ipsec_stats_param *)data; if (utsp == NULL || len < sizeof(struct ipsec_stats_param)) { result = EINVAL; break; } if (!pcb->ipsec_ext_ifdata_stats) { result = EINVAL; break; } if (opt == IPSEC_OPT_INC_IFDATA_STATS_IN) ifnet_stat_increment_in(pcb->ipsec_ifp, utsp->utsp_packets, utsp->utsp_bytes, utsp->utsp_errors); else ifnet_stat_increment_out(pcb->ipsec_ifp, utsp->utsp_packets, utsp->utsp_bytes, utsp->utsp_errors); break; } case IPSEC_OPT_SET_DELEGATE_INTERFACE: { ifnet_t del_ifp = NULL; char name[IFNAMSIZ]; if (len > IFNAMSIZ - 1) { result = EMSGSIZE; break; } if (len != 0) { /* if len==0, del_ifp will be NULL causing the delegate to be removed */ bcopy(data, name, len); name[len] = 0; result = ifnet_find_by_name(name, &del_ifp); } if (result == 0) { result = ifnet_set_delegate(pcb->ipsec_ifp, del_ifp); if (del_ifp) ifnet_release(del_ifp); } break; } case IPSEC_OPT_OUTPUT_TRAFFIC_CLASS: { if (len != sizeof(int)) { result = EMSGSIZE; break; } mbuf_svc_class_t output_service_class = so_tc2msc(*(int *)data); if (output_service_class == MBUF_SC_UNSPEC) { pcb->ipsec_output_service_class = MBUF_SC_OAM; } else { pcb->ipsec_output_service_class = output_service_class; } break; } default: result = ENOPROTOOPT; break; } return result; }