tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Socket options KPI



On Sun, 27 Jan 2008, Iain Hibbert wrote:

> > What you're suggesting implies we will be changing the KPI that way,
> > which, at the moment, is not necessarily true. I would very much like
> > for the first sweep to be close to what is done in FreeBSD.
>
> Ah, I see - I did not notice they changed it that way.

I'm looking into this some more but finding some trouble. Its not really
possible to separate the 'sockopt' from the netbt protocol layers because
it is necessary to know the length of the data before you extract
anything. So, the sockopt will have to be passed down.

I don't see sockopt_get/sockopt_set in the FreeBSD code (that I have), are
you willing to consider changing sockopt_get() from

void *
sockopt_get(const struct sockopt *sopt, size_t len)
{
        if (sopt->sopt_un == NULL || sopt->sopt_size != len)
                return NULL;

        return (void *)sopt->sopt_un;
}

to

int
sockopt_get(const struct sockopt *sopt, void *buf, size_t len)
{

        if (sopt->sopt_un == NULL || sopt->sopt_size != len)
                return EINVAL;

        memcpy(buf, sopt->sopt_un, sopt->sopt_size);
        return 0;
}

?

IMHO this results in cleaner code (see below for what I've made in the
L2CAP case). It also mirrors sockopt_set() which also does the copy and
returns an errno(2). It means that you have to have a (probably stack
based) variable but I prefer to do that as it removes any alignment
issues. (If you wanted to provide a sockopt_getptr() also I would not
object)

iain

/* sys/netbt/l2cap_socket.c */
int
l2cap_ctloutput(struct socket *so, struct sockopt *sopt)
{
        struct l2cap_channel *pcb = so->so_pcb;
        int err = 0;

        if (pcb == NULL)
                return EINVAL;

        if (sopt->sopt_level != BTPROTO_L2CAP)
                return ENOPROTOOPT;

        switch(sopt->sopt_dir) {
        case SOPT_GET:
                err = l2cap_getopt(pcb, sopt);
                break;

        case SOPT_SET:
                err = l2cap_setopt(pcb, sopt);
                break;

        default:
                err = EINVAL;
                break;
        }

        return err;
}

/* sys/netbt/l2cap_upper.c */
int
l2cap_setopt(struct l2cap_channel *chan, struct sockopt *sopt)
{
        uint16_t mtu;
        int mode, err = 0;

        switch (sopt->sopt_name) {
        case SO_L2CAP_IMTU:     /* set Incoming MTU */
                err = sockopt_get(sopt, &mtu, sizeof(uint16_t)):
                if (err)
                        break;

                if (mtu < L2CAP_MTU_MINIMUM)
                        err = EINVAL;
                else if (chan->lc_state == L2CAP_CLOSED)
                        chan->lc_imtu = mtu;
                else
                        err = EBUSY;

                break;

        case SO_L2CAP_LM:       /* set link mode */
                err = sockopt_get(sopt, &mode, sizeof(int));
                if (err)
                        break;

                mode &= (L2CAP_LM_SECURE | L2CAP_LM_ENCRYPT | L2CAP_LM_AUTH);

                if (mode & L2CAP_LM_SECURE)
                        mode |= L2CAP_LM_ENCRYPT;

                if (mode & L2CAP_LM_ENCRYPT)
                        mode |= L2CAP_LM_AUTH;

                chan->lc_mode = mode;

                if (chan->lc_state == L2CAP_OPEN)
                        err = l2cap_setmode(chan);

                break;

        case SO_L2CAP_OQOS:     /* set Outgoing QoS flow spec */
        case SO_L2CAP_FLUSH:    /* set Outgoing Flush Timeout */
        default:
                err = ENOPROTOOPT;
                break;
        }

        return err;
}

int
l2cap_getopt(struct l2cap_channel *chan, struct sockopt *sopt)
{

        switch (sopt->sopt_name) {
        case SO_L2CAP_IMTU:     /* get Incoming MTU */
                return sockopt_set(sopt, &chan->lc_imtu, sizeof(uint16_t));

        case SO_L2CAP_OMTU:     /* get Outgoing MTU */
                return sockopt_set(sopt, &chan->lc_omtu, sizeof(uint16_t));

        case SO_L2CAP_IQOS:     /* get Incoming QoS flow spec */
                return sockopt_set(sopt, &chan->lc_iqos, sizeof(l2cap_qos_t));

        case SO_L2CAP_OQOS:     /* get Outgoing QoS flow spec */
                return sockopt_set(sopt, &chan->lc_oqos, sizeof(l2cap_qos_t));

        case SO_L2CAP_FLUSH:    /* get Flush Timeout */
                return sockopt_set(sopt, &chan->lc_flush, sizeof(uint16_t));

        case SO_L2CAP_LM:       /* get link mode */
                return sockopt_set(sopt, &chan->lc_mode, sizeof(int));

        default:
                break;
        }

        return EPROTONOOPT;
}



Home | Main Index | Thread Index | Old Index