In the interest of time, here are my first high-level commments on
libdlpi.c.  I'd like these to be resolved before doing a more thorough
review.  I'd hope that applying these comments could reduce libdlpi.c
by at least 300 lines.

 * Most of libdlpi.c consists of functions with this form:

        1. Figure out size of request and reply buffers.
        2. Allocate buffers.
        3. Do some function-specific setup.
        4. Call dlpi_msg_common().
        5. Do some function-specific and generic processing of the results
           of dlpi_msg_common().
        6. Free buffers.

    Much more care needs to be put into minimizing redundant code, and
    streamlining code that is not redundant.  In most cases, simply
    allocating buffers on the stack and defining helper routines would
    greatly reduce code sprawl.  For instance, dlpi_unbind() is currently
    57 lines of fairly boilerplate code -- but with some helper functions
    and more careful allocation, could be reduced to 21 lines:

    int
    dlpi_unbind(dlpi_handle_t dh)
    {
        int                     retval;
        dl_unbind_req_t         *dlubrp;
        union DL_primitives     *replyp;
        dlpi_impl_t             *dip = (dlpi_impl_t *)dh;
     
        if (dip == NULL)
                return (DLPI_EINHANDLE);
     
        replyp = alloca(DLPI_ACK_REPLY_SIZE);
        dlubrp = alloca(DL_UNBIND_REQ_SIZE);
        dlubrp->dl_primitive = DL_UNBIND_REQ;
    
        retval = dlpi_msg_common(dip, dlubrp, DL_UNBIND_REQ_SIZE, replyp,
            DL_OK_ACK, DLPI_ACK_REPLY_SIZE, DL_OK_ACK_SIZE, NULL);
        if (retval != DLPI_SUCCESS)
                return (retval);
        
        return (dlpi_retval(replyp));
    }

    ... where dlpi_retval() is defined as:

    int
    dlpi_retval(union DL_primitives *replyp)
    {
        dl_error_ack_t *dleap = (dl_error_ack_t *)replyp;
        
        switch (replyp->dl_primitive) {
        case DL_OK_ACK:
                return (DLPI_SUCCESS);
     
        case DL_ERROR_ACK:
                errno = dleap->dl_unix_errno;
                return (dleap->dl_errno);
     
        default:
                errno = EBADMSG;
                return (DL_SYSERR);
        }
    }

    ... and DLPI_ACK_REPLY_SIZE is a #define for MAX(sizeof (dl_ok_ack_t),
    sizeof (dl_error_ack_t).

    This same pattern can be repeated for i_dlpi_passive(),
    i_dlpi_multi(), i_dlpi_promisc(), dlpi_info(), dlpi_bind(),
    dlpi_get_physaddr(), dlpi_set_physaddr(), dlpi_attach(), and
    dlpi_detach().  You should be able to haul out over many hundreds of
    lines of code.

  * There appear to be needless extra type indirections.  For instance,
    the code has:

        typedef enum dlpi_multi_op {
                DLPI_MULTI_DISABLE = 0,
                DLPI_MULTI_ENABLE
        } dlpi_multi_op_t;

    ... but there's no advantage to this over just directly passing the
    primitive to i_dlpi_multi().  In fact, i_dlpi_multi() can be made
    simpler because you can simply assign `reqprimp->dl_primitive = op'.

  * There's a fair amount of strange code associated with determining the
    request and reply buffer size.  For instance, i_dlpi_promisc()
    includes this:

        opsize = (op == DLPI_PROMISC_ON) ? sizeof (dl_promiscon_req_t) :
                  sizeof (dl_promiscoff_req_t);

        size = 0;
        size = MAX(opsize, size);
        size = MAX(sizeof (dl_ok_ack_t), size);
        size = MAX(sizeof (dl_error_ack_t), size);

        if ((reqprimp = malloc(size)) == NULL)
                return (DLPI_ENOMEM);

        if ((repprimp = malloc(size)) == NULL) {
                free(reqprimp);
                return (DLPI_ENOMEM);
        }

    ... but as per the DLPI spec, only dl_ok_ack_t or dl_error_ack_t will
    be returned in a reply -- so I cannot figure out why the reply is
    allocated to potentially holda dl_promiscon_req_t.  Further, as per my
    previous comments, alloca() can be used to allocate small stack-local
    buffers of dynamic size (you could also use some C99 features to do
    this, but I'm not sure if those are generall allowed in ON at this
    point).  So, I'd expect the above code to simply be:

        if (op == DL_PROMISCON_REQ)
                reqprimp = alloca(dl_promiscon_req_t);
        else
                reqprimp = alloca(dl_promiscoff_req_t);         

        repprimp = alloca(DLPI_ACK_REPLY_SIZE);

  * I'm not sure why dli_passive and dli_raw are stored in separate
    fields.  The code would be simpler if you had a dli_oflags field
    that was assigned to `flags' at open time.

--
meem

Reply via email to