Exemple #1
0
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);
}
Exemple #2
0
/*
 * 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);
}
Exemple #3
0
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);
}
Exemple #4
0
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);
}
Exemple #5
0
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);
}
Exemple #6
0
/* -----------------------------------------------------------------------------
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;
}
Exemple #7
0
/*
 * 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);
}
Exemple #8
0
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);
}