static int tcp_ipsec_pcbctl(struct inpcb *inp, struct sockopt *sopt) { struct tcpcb *tp; int error, optval; INP_WLOCK_ASSERT(inp); if (sopt->sopt_name != TCP_MD5SIG) { INP_WUNLOCK(inp); return (ENOPROTOOPT); } tp = intotcpcb(inp); if (sopt->sopt_dir == SOPT_GET) { optval = (tp->t_flags & TF_SIGNATURE) ? 1 : 0; INP_WUNLOCK(inp); /* On success return with released INP_WLOCK */ return (sooptcopyout(sopt, &optval, sizeof(optval))); } INP_WUNLOCK(inp); error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval)); if (error != 0) return (error); /* INP_WLOCK_RECHECK */ INP_WLOCK(inp); if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { INP_WUNLOCK(inp); return (ECONNRESET); } if (optval > 0) tp->t_flags |= TF_SIGNATURE; else tp->t_flags &= ~TF_SIGNATURE; /* On success return with acquired INP_WLOCK */ return (error); }
/* * Handle UDP_ENCAP socket option. Always return with released INP_WLOCK. */ int udp_ipsec_pcbctl(struct inpcb *inp, struct sockopt *sopt) { struct udpcb *up; int error, optval; INP_WLOCK_ASSERT(inp); if (sopt->sopt_name != UDP_ENCAP) { INP_WUNLOCK(inp); return (ENOPROTOOPT); } up = intoudpcb(inp); if (sopt->sopt_dir == SOPT_GET) { if (up->u_flags & UF_ESPINUDP) optval = UDP_ENCAP_ESPINUDP; else optval = 0; INP_WUNLOCK(inp); return (sooptcopyout(sopt, &optval, sizeof(optval))); } INP_WUNLOCK(inp); error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval)); if (error != 0) return (error); INP_WLOCK(inp); switch (optval) { case 0: up->u_flags &= ~UF_ESPINUDP; break; case UDP_ENCAP_ESPINUDP: up->u_flags |= UF_ESPINUDP; break; default: error = EINVAL; } INP_WUNLOCK(inp); return (error); }
int tcp_ctloutput(struct socket *so, struct sockopt *sopt) { int error, opt, optval; struct inpcb *inp; struct tcpcb *tp; struct tcp_info ti; error = 0; inp = sotoinpcb(so); KASSERT(inp != NULL, ("tcp_ctloutput: inp == NULL")); INP_WLOCK(inp); if (sopt->sopt_level != IPPROTO_TCP) { #ifdef INET6 if (inp->inp_vflag & INP_IPV6PROTO) { INP_WUNLOCK(inp); error = ip6_ctloutput(so, sopt); } else { #endif /* INET6 */ INP_WUNLOCK(inp); error = ip_ctloutput(so, sopt); #ifdef INET6 } #endif return (error); } if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { INP_WUNLOCK(inp); return (ECONNRESET); } switch (sopt->sopt_dir) { case SOPT_SET: switch (sopt->sopt_name) { #ifdef TCP_SIGNATURE case TCP_MD5SIG: INP_WUNLOCK(inp); error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); if (error) return (error); INP_WLOCK_RECHECK(inp); if (optval > 0) tp->t_flags |= TF_SIGNATURE; else tp->t_flags &= ~TF_SIGNATURE; INP_WUNLOCK(inp); break; #endif /* TCP_SIGNATURE */ case TCP_NODELAY: case TCP_NOOPT: INP_WUNLOCK(inp); error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); if (error) return (error); INP_WLOCK_RECHECK(inp); switch (sopt->sopt_name) { case TCP_NODELAY: opt = TF_NODELAY; break; case TCP_NOOPT: opt = TF_NOOPT; break; default: opt = 0; /* dead code to fool gcc */ break; } if (optval) tp->t_flags |= opt; else tp->t_flags &= ~opt; INP_WUNLOCK(inp); break; case TCP_NOPUSH: INP_WUNLOCK(inp); error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); if (error) return (error); INP_WLOCK_RECHECK(inp); if (optval) tp->t_flags |= TF_NOPUSH; else { tp->t_flags &= ~TF_NOPUSH; error = tcp_output(tp); } INP_WUNLOCK(inp); break; case TCP_MAXSEG: INP_WUNLOCK(inp); error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); if (error) return (error); INP_WLOCK_RECHECK(inp); if (optval > 0 && optval <= tp->t_maxseg && optval + 40 >= V_tcp_minmss) tp->t_maxseg = optval; else error = EINVAL; INP_WUNLOCK(inp); break; case TCP_INFO: INP_WUNLOCK(inp); error = EINVAL; break; default: INP_WUNLOCK(inp); error = ENOPROTOOPT; break; } break; case SOPT_GET: tp = intotcpcb(inp); switch (sopt->sopt_name) { #ifdef TCP_SIGNATURE case TCP_MD5SIG: optval = (tp->t_flags & TF_SIGNATURE) ? 1 : 0; INP_WUNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof optval); break; #endif case TCP_NODELAY: optval = tp->t_flags & TF_NODELAY; INP_WUNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof optval); break; case TCP_MAXSEG: optval = tp->t_maxseg; INP_WUNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof optval); break; case TCP_NOOPT: optval = tp->t_flags & TF_NOOPT; INP_WUNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof optval); break; case TCP_NOPUSH: optval = tp->t_flags & TF_NOPUSH; INP_WUNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof optval); break; case TCP_INFO: tcp_fill_info(tp, &ti); INP_WUNLOCK(inp); error = sooptcopyout(sopt, &ti, sizeof ti); break; default: INP_WUNLOCK(inp); error = ENOPROTOOPT; break; } break; } return (error); }
int udp_ctloutput(struct socket *so, struct sockopt *sopt) { struct inpcb *inp; struct udpcb *up; int isudplite, error, optval; error = 0; isudplite = (so->so_proto->pr_protocol == IPPROTO_UDPLITE) ? 1 : 0; inp = sotoinpcb(so); KASSERT(inp != NULL, ("%s: inp == NULL", __func__)); INP_WLOCK(inp); if (sopt->sopt_level != so->so_proto->pr_protocol) { #ifdef INET6 if (INP_CHECK_SOCKAF(so, AF_INET6)) { INP_WUNLOCK(inp); error = ip6_ctloutput(so, sopt); } #endif #if defined(INET) && defined(INET6) else #endif #ifdef INET { INP_WUNLOCK(inp); error = ip_ctloutput(so, sopt); } #endif return (error); } switch (sopt->sopt_dir) { case SOPT_SET: switch (sopt->sopt_name) { case UDP_ENCAP: INP_WUNLOCK(inp); error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); if (error) break; inp = sotoinpcb(so); KASSERT(inp != NULL, ("%s: inp == NULL", __func__)); INP_WLOCK(inp); #ifdef IPSEC_NAT_T up = intoudpcb(inp); KASSERT(up != NULL, ("%s: up == NULL", __func__)); #endif switch (optval) { case 0: /* Clear all UDP encap. */ #ifdef IPSEC_NAT_T up->u_flags &= ~UF_ESPINUDP_ALL; #endif break; #ifdef IPSEC_NAT_T case UDP_ENCAP_ESPINUDP: case UDP_ENCAP_ESPINUDP_NON_IKE: up->u_flags &= ~UF_ESPINUDP_ALL; if (optval == UDP_ENCAP_ESPINUDP) up->u_flags |= UF_ESPINUDP; else if (optval == UDP_ENCAP_ESPINUDP_NON_IKE) up->u_flags |= UF_ESPINUDP_NON_IKE; break; #endif default: error = EINVAL; break; } INP_WUNLOCK(inp); break; case UDPLITE_SEND_CSCOV: case UDPLITE_RECV_CSCOV: if (!isudplite) { INP_WUNLOCK(inp); error = ENOPROTOOPT; break; } INP_WUNLOCK(inp); error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval)); if (error != 0) break; inp = sotoinpcb(so); KASSERT(inp != NULL, ("%s: inp == NULL", __func__)); INP_WLOCK(inp); up = intoudpcb(inp); KASSERT(up != NULL, ("%s: up == NULL", __func__)); if (optval != 0 && optval < 8) { INP_WUNLOCK(inp); error = EINVAL; break; } if (sopt->sopt_name == UDPLITE_SEND_CSCOV) up->u_txcslen = optval; else up->u_rxcslen = optval; INP_WUNLOCK(inp); break; default: INP_WUNLOCK(inp); error = ENOPROTOOPT; break; } break; case SOPT_GET: switch (sopt->sopt_name) { #ifdef IPSEC_NAT_T case UDP_ENCAP: up = intoudpcb(inp); KASSERT(up != NULL, ("%s: up == NULL", __func__)); optval = up->u_flags & UF_ESPINUDP_ALL; INP_WUNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof optval); break; #endif case UDPLITE_SEND_CSCOV: case UDPLITE_RECV_CSCOV: if (!isudplite) { INP_WUNLOCK(inp); error = ENOPROTOOPT; break; } up = intoudpcb(inp); KASSERT(up != NULL, ("%s: up == NULL", __func__)); if (sopt->sopt_name == UDPLITE_SEND_CSCOV) optval = up->u_txcslen; else optval = up->u_rxcslen; INP_WUNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof(optval)); break; default: INP_WUNLOCK(inp); error = ENOPROTOOPT; break; } break; } return (error); }
int do_setopt_accept_filter(struct socket *so, struct sockopt *sopt) { struct accept_filter_arg *afap; struct accept_filter *afp; struct so_accf *newaf; int error = 0; /* * Handle the simple delete case first. */ if (sopt == NULL || sopt->sopt_val == NULL) { SOCK_LOCK(so); if ((so->so_options & SO_ACCEPTCONN) == 0) { SOCK_UNLOCK(so); return (EINVAL); } if (so->so_accf != NULL) { struct so_accf *af = so->so_accf; if (af->so_accept_filter != NULL && af->so_accept_filter->accf_destroy != NULL) { af->so_accept_filter->accf_destroy(so); } if (af->so_accept_filter_str != NULL) free(af->so_accept_filter_str, M_ACCF); free(af, M_ACCF); so->so_accf = NULL; } so->so_options &= ~SO_ACCEPTFILTER; SOCK_UNLOCK(so); return (0); } /* * Pre-allocate any memory we may need later to avoid blocking at * untimely moments. This does not optimize for invalid arguments. */ afap = malloc(sizeof(*afap), M_TEMP, M_WAITOK); error = sooptcopyin(sopt, afap, sizeof *afap, sizeof *afap); afap->af_name[sizeof(afap->af_name)-1] = '\0'; afap->af_arg[sizeof(afap->af_arg)-1] = '\0'; if (error) { free(afap, M_TEMP); return (error); } afp = accept_filt_get(afap->af_name); if (afp == NULL) { free(afap, M_TEMP); return (ENOENT); } /* * Allocate the new accept filter instance storage. We may * have to free it again later if we fail to attach it. If * attached properly, 'newaf' is NULLed to avoid a free() * while in use. */ newaf = malloc(sizeof(*newaf), M_ACCF, M_WAITOK | M_ZERO); if (afp->accf_create != NULL && afap->af_name[0] != '\0') { int len = strlen(afap->af_name) + 1; newaf->so_accept_filter_str = malloc(len, M_ACCF, M_WAITOK); strcpy(newaf->so_accept_filter_str, afap->af_name); } /* * Require a listen socket; don't try to replace an existing filter * without first removing it. */ SOCK_LOCK(so); if (((so->so_options & SO_ACCEPTCONN) == 0) || (so->so_accf != NULL)) { error = EINVAL; goto out; } /* * Invoke the accf_create() method of the filter if required. The * socket mutex is held over this call, so create methods for filters * can't block. */ if (afp->accf_create != NULL) { newaf->so_accept_filter_arg = afp->accf_create(so, afap->af_arg); if (newaf->so_accept_filter_arg == NULL) { error = EINVAL; goto out; } } newaf->so_accept_filter = afp; so->so_accf = newaf; so->so_options |= SO_ACCEPTFILTER; newaf = NULL; out: SOCK_UNLOCK(so); if (newaf != NULL) { if (newaf->so_accept_filter_str != NULL) free(newaf->so_accept_filter_str, M_ACCF); free(newaf, M_ACCF); } if (afap != NULL) free(afap, M_TEMP); return (error); }
/* ----------------------------------------------------------------------------- This function is called by socket layer to handle get/set-socketoption ----------------------------------------------------------------------------- */ int l2tp_ctloutput(struct socket *so, struct sockopt *sopt) { int error, optval; u_int32_t lval, cmd = 0; u_int16_t val; u_char *addr; lck_mtx_assert(ppp_domain_mutex, LCK_MTX_ASSERT_OWNED); //IOLog("l2tp_ctloutput, so = %p\n", so); error = optval = 0; if (sopt->sopt_level != PPPPROTO_L2TP) { return EINVAL; } switch (sopt->sopt_dir) { case SOPT_SET: switch (sopt->sopt_name) { case L2TP_OPT_FLAGS: case L2TP_OPT_BAUDRATE: if (sopt->sopt_valsize != 4) error = EMSGSIZE; else if ((error = sooptcopyin(sopt, &lval, 4, 4)) == 0) { switch (sopt->sopt_name) { case L2TP_OPT_BAUDRATE: cmd = L2TP_CMD_SETBAUDRATE; break; case L2TP_OPT_FLAGS: cmd = L2TP_CMD_SETFLAGS; break; } l2tp_rfc_command(so->so_pcb, cmd, &lval); } break; case L2TP_OPT_ACCEPT: if (sopt->sopt_valsize != 0) error = EMSGSIZE; else l2tp_rfc_command(so->so_pcb, L2TP_CMD_ACCEPT, 0); break; case L2TP_OPT_OURADDRESS: case L2TP_OPT_PEERADDRESS: if (sopt->sopt_valsize < sizeof(struct sockaddr)) error = EMSGSIZE; else { if ((addr = _MALLOC(sopt->sopt_valsize, M_TEMP, M_WAITOK)) == 0) error = ENOMEM; else { if ((error = sooptcopyin(sopt, addr, sopt->sopt_valsize, sopt->sopt_valsize)) == 0) error = l2tp_rfc_command(so->so_pcb, sopt->sopt_name == L2TP_OPT_OURADDRESS ? L2TP_CMD_SETOURADDR : L2TP_CMD_SETPEERADDR, addr); _FREE(addr, M_TEMP); } } break; case L2TP_OPT_TUNNEL_ID: case L2TP_OPT_PEER_TUNNEL_ID: case L2TP_OPT_SESSION_ID: case L2TP_OPT_PEER_SESSION_ID: case L2TP_OPT_WINDOW: case L2TP_OPT_PEER_WINDOW: case L2TP_OPT_INITIAL_TIMEOUT: case L2TP_OPT_TIMEOUT_CAP: case L2TP_OPT_MAX_RETRIES: case L2TP_OPT_RELIABILITY: if (sopt->sopt_valsize != 2) error = EMSGSIZE; else if ((error = sooptcopyin(sopt, &val, 2, 2)) == 0) { switch (sopt->sopt_name) { case L2TP_OPT_TUNNEL_ID: cmd = L2TP_CMD_SETTUNNELID; break; case L2TP_OPT_PEER_TUNNEL_ID: cmd = L2TP_CMD_SETPEERTUNNELID; break; case L2TP_OPT_SESSION_ID: cmd = L2TP_CMD_SETSESSIONID; break; case L2TP_OPT_PEER_SESSION_ID: cmd = L2TP_CMD_SETPEERSESSIONID; break; case L2TP_OPT_WINDOW: cmd = L2TP_CMD_SETWINDOW; break; case L2TP_OPT_PEER_WINDOW: cmd = L2TP_CMD_SETPEERWINDOW; break; case L2TP_OPT_INITIAL_TIMEOUT: cmd = L2TP_CMD_SETTIMEOUT; break; case L2TP_OPT_TIMEOUT_CAP: cmd = L2TP_CMD_SETTIMEOUTCAP; break; case L2TP_OPT_MAX_RETRIES: cmd = L2TP_CMD_SETMAXRETRIES; break; case L2TP_OPT_RELIABILITY: cmd = L2TP_CMD_SETRELIABILITY; break; } l2tp_rfc_command(so->so_pcb, cmd, &val); } break; default: error = ENOPROTOOPT; } break; case SOPT_GET: switch (sopt->sopt_name) { case L2TP_OPT_NEW_TUNNEL_ID: case L2TP_OPT_TUNNEL_ID: case L2TP_OPT_SESSION_ID: if (sopt->sopt_valsize != 2) error = EMSGSIZE; else { switch (sopt->sopt_name) { case L2TP_OPT_NEW_TUNNEL_ID: cmd = L2TP_CMD_GETNEWTUNNELID; break; case L2TP_OPT_TUNNEL_ID: cmd = L2TP_CMD_GETTUNNELID; break; case L2TP_OPT_SESSION_ID: cmd = L2TP_CMD_GETSESSIONID; break; } l2tp_rfc_command(so->so_pcb, cmd, &val); error = sooptcopyout(sopt, &val, 2); } break; case L2TP_OPT_FLAGS: if (sopt->sopt_valsize != 4) error = EMSGSIZE; else { l2tp_rfc_command(so->so_pcb, L2TP_CMD_GETFLAGS, &lval); error = sooptcopyout(sopt, &lval, 4); } break; case L2TP_OPT_OURADDRESS: case L2TP_OPT_PEERADDRESS: if ((addr = _MALLOC(sopt->sopt_valsize, M_TEMP, M_WAITOK)) == 0) error = ENOMEM; else { *addr = sopt->sopt_valsize; /* max size */ if ((error = l2tp_rfc_command(so->so_pcb, sopt->sopt_name == L2TP_OPT_OURADDRESS ? L2TP_CMD_GETOURADDR : L2TP_CMD_GETPEERADDR, addr)) == 0) { error = sooptcopyout(sopt, addr, sopt->sopt_valsize); _FREE(addr, M_TEMP); } } break; default: error = ENOPROTOOPT; break; } break; } return error; }
/* * Handle MRT setsockopt commands to modify the multicast routing tables. */ int X_ip6_mrouter_set(struct socket *so, struct sockopt *sopt) { int error = 0; int optval; struct mif6ctl mifc; struct mf6cctl mfcc; mifi_t mifi; if (so != V_ip6_mrouter && sopt->sopt_name != MRT6_INIT) return (EACCES); switch (sopt->sopt_name) { case MRT6_INIT: #ifdef MRT6_OINIT case MRT6_OINIT: #endif error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval)); if (error) break; error = ip6_mrouter_init(so, optval, sopt->sopt_name); break; case MRT6_DONE: error = X_ip6_mrouter_done(); break; case MRT6_ADD_MIF: error = sooptcopyin(sopt, &mifc, sizeof(mifc), sizeof(mifc)); if (error) break; error = add_m6if(&mifc); break; case MRT6_ADD_MFC: error = sooptcopyin(sopt, &mfcc, sizeof(mfcc), sizeof(mfcc)); if (error) break; error = add_m6fc(&mfcc); break; case MRT6_DEL_MFC: error = sooptcopyin(sopt, &mfcc, sizeof(mfcc), sizeof(mfcc)); if (error) break; error = del_m6fc(&mfcc); break; case MRT6_DEL_MIF: error = sooptcopyin(sopt, &mifi, sizeof(mifi), sizeof(mifi)); if (error) break; error = del_m6if(&mifi); break; case MRT6_PIM: error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval)); if (error) break; error = set_pim6(&optval); break; default: error = EOPNOTSUPP; break; } return (error); }
int Lpx_USER_ctloutput( struct socket *so, struct sockopt *sopt ) { struct lpxpcb *lpxp = sotolpxpcb(so); int mask, error, optval; short soptval; struct lpx ioptval; error = 0; if (lpxp == NULL) return (EINVAL); switch (sopt->sopt_dir) { case SOPT_GET: switch (sopt->sopt_name) { case SO_ALL_PACKETS: mask = LPXP_ALL_PACKETS; goto get_flags; case SO_HEADERS_ON_INPUT: mask = LPXP_RAWIN; goto get_flags; case SO_LPX_CHECKSUM: mask = LPXP_CHECKSUM; goto get_flags; case SO_HEADERS_ON_OUTPUT: mask = LPXP_RAWOUT; get_flags: soptval = lpxp->lpxp_flags & mask; error = sooptcopyout(sopt, &soptval, sizeof soptval); break; case SO_DEFAULT_HEADERS: ioptval.lpx_len = 0; ioptval.lpx_sum = 0; ioptval.lpx_tc = 0; ioptval.lpx_pt = lpxp->lpxp_dpt; ioptval.lpx_dna = lpxp->lpxp_faddr; ioptval.lpx_sna = lpxp->lpxp_laddr; error = sooptcopyout(sopt, &soptval, sizeof soptval); break; case SO_SEQNO: error = sooptcopyout(sopt, &lpx_pexseq, sizeof lpx_pexseq); lpx_pexseq++; break; default: error = EINVAL; } break; case SOPT_SET: switch (sopt->sopt_name) { case SO_ALL_PACKETS: mask = LPXP_ALL_PACKETS; goto set_head; case SO_HEADERS_ON_INPUT: mask = LPXP_RAWIN; goto set_head; case SO_LPX_CHECKSUM: mask = LPXP_CHECKSUM; case SO_HEADERS_ON_OUTPUT: mask = LPXP_RAWOUT; set_head: error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); if (error) break; if (optval) lpxp->lpxp_flags |= mask; else lpxp->lpxp_flags &= ~mask; break; case SO_DEFAULT_HEADERS: error = sooptcopyin(sopt, &ioptval, sizeof ioptval, sizeof ioptval); if (error) break; lpxp->lpxp_dpt = ioptval.lpx_pt; break; #ifdef LPXIP /* Not supported */ case SO_LPXIP_ROUTE: error = lpxip_route(so, sopt); break; #endif /* LPXIP */ #ifdef IPTUNNEL #if 0 case SO_LPXTUNNEL_ROUTE: error = lpxtun_route(so, sopt); break; #endif #endif default: error = EINVAL; } break; } return (error); }