Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 18 Jan 1999 22:07:09 -0800 (PST)
From:      Julian Elischer <julian@whistle.com>
To:        Christian Kuhtz <ck@adsu.bellsouth.com>
Cc:        hackers@FreeBSD.ORG
Subject:   Re: protocol implementation
Message-ID:  <Pine.BSF.3.95.990118213616.9336B-100000@current1.whistle.com>
In-Reply-To: <19990119000654.K5878@oreo.adsu.bellsouth.com>

next in thread | previous in thread | raw e-mail | index | archive | help


On Tue, 19 Jan 1999, Christian Kuhtz wrote:

> 
> Hello:
> 
> I am in the process of coding a new protocol stack and it is time to start
> mating the higher layers to media access layer.
> 
> The question is: How is this done best in FreeBSD?

Each media-type driver needs to know how to detect that protocol.
e,g for ethernet,
the file if_ethersubr.c needs to be modified so that incoming
packets of your protocol are recognised. The output routine there needs to
know about your sockaddr type so that it can encode it witht eh right
header before sending it. This is the only place where you need
to actually edit code.

The very existance of (your equivalent of) the following code
will create the linkages needed fo rth ekernel to find your protocol
stack from the socket end of things.
(this is taken from some code here)
Thisimplements a protocol family woth two different sub-protocols
(e.g similar to udp and tcp as sub protocols of the ip family)


/*
 * Control and data socket type descriptors
 */

static struct pr_usrreqs ngc_usrreqs = {
        NULL,                   /* abort */
        pru_accept_notsupp,
        ngc_attach,
        ngc_bind,
        ngc_connect,
        pru_connect2_notsupp,
        pru_control_notsupp,
        ngc_detach,
        NULL,                   /* disconnect */
        pru_listen_notsupp,
        NULL,                   /* setpeeraddr */
        pru_rcvd_notsupp,
        pru_rcvoob_notsupp,
        ngc_send,
        pru_sense_null,
        NULL,                   /* shutdown */
        ng_setsockaddr,
        sosend,
        soreceive,
        sopoll
};

static struct pr_usrreqs ngd_usrreqs = {
        NULL,                   /* abort */
        pru_accept_notsupp,
        ngd_attach,
        NULL,                   /* bind */
        ngd_connect,
        pru_connect2_notsupp,
        pru_control_notsupp,
        ngd_detach,
        NULL,                   /* disconnect */
        pru_listen_notsupp,
        NULL,                   /* setpeeraddr */
        pru_rcvd_notsupp,
        pru_rcvoob_notsupp,
        ngd_send,
        pru_sense_null,
        NULL,                   /* shutdown */
        ng_setsockaddr,
        sosend,
        soreceive,
        sopoll
};


/*
 * Definitions of protocols supported in the NETGRAPH domain.
 */

extern struct domain ngdomain;          /* stop compiler warnings */

static struct protosw ngsw[] = {
        {
                SOCK_DGRAM,
                &ngdomain,
                NG_CONTROL,
                PR_ATOMIC | PR_ADDR | PR_RIGHTS,
                0, 0, 0, 0,
                NULL,
                0, 0, 0, 0,
                &ngc_usrreqs
        },
        {
                SOCK_DGRAM,
                &ngdomain,
                NG_DATA,
                PR_ATOMIC | PR_ADDR,
                0, 0, 0, 0,
                NULL,
                0, 0, 0, 0,
                &ngd_usrreqs
        }
};

struct domain ngdomain = {
        AF_NETGRAPH,
        "netgraph",
        0,
        NULL,
        NULL,
        ngsw,
        &ngsw[sizeof(ngsw) / sizeof(ngsw[0])],
        0,
        NULL,
        0,
        0
};

DOMAIN_SET(ng);

In addition you need to add code to link in your ISR code.
Once again here is our version of that code..
alter to taste..
/*
 * Pick an item off the queue, process it, and dispose of the queue entry.
 * Should be running at splnet.
 */
static void
ngintr(void)
{
        hook_p  hook;
        struct ng_queue_entry *ngq;
        struct mbuf *m;
        meta_p  meta;
        void   *retaddr;
        struct ng_mesg *msg;
        node_p  node;
        int     error = 0;
        int     s;

        while (1) {
                s = splhigh();
                if ((ngq = ngqbase)) {
                        ngqbase = ngq->next;
                        ngqsize--;
                }
                splx(s);
                if (ngq == NULL)
                        return;
                switch (ngq->flags) {
                case NGQF_DATA:
                        hook = ngq->body.data.da_hook;
                        m = ngq->body.data.da_m;
                        meta = ngq->body.data.da_meta;
                        RETURN_QBLK(ngq);
                        NG_SEND_DATA(error, hook, m, meta);
                        ng_unref_hook(hook);
                        break;
                case NGQF_MESG:
                        node = ngq->body.msg.msg_node;
                        msg = ngq->body.msg.msg_msg;
                        retaddr = ngq->body.msg.msg_retaddr;
                        RETURN_QBLK(ngq);
                        if (node->flags & NG_INVALID) {
                                FREE(msg, M_NETGRAPH);
                        } else {
                                CALL_MSG_HANDLER(error, node, msg,
                                                 retaddr, NULL);
                        }
                        ng_unref(node);
                        if (retaddr)
                                FREE(retaddr, M_NETGRAPH);
                        break;
                default:
                        RETURN_QBLK(ngq);
                }
        }
}

NETISR_SET(NETISR_NG, ngintr);

Once again.. the very inclusion of this code links itself in on linking. 
the trick is the NETISR_SET macro. This code uses our own queue, and is
queuing structures wich point to the mbufs. You would but probably use a
normal interface queue as you will see in if_ethersubr.c and ipintr()
(ip_input.c from memory) instead, and queue the mbufs directly usinghte
IF_QUEUE() macro. (and it's friends). (IF_DEQUEUE())

The code snippet for queing the packets is as follows..
this is run in the driver code, where the code above is in the protocol
stack and recieves the packets.

        /* queue the data for packup by hte protocol stack */
        s = splhigh();
        if (ngqbase) {
                ngqlast->next = q;
        } else {
                ngqbase = q;
        }
        ngqlast = q;
        ngqsize++;
        splx(s);

        /* Schedule software interrupt to handle it later */
        schednetisr(NETISR_NG);



> 
> The stack components are coded as klds.  And I need to be able to create
> frames on the Ethernet (which is the primary media target, but not 
> exclusively) and pick up frames.  The system will run IP and well as this
> new stack in parallel.

Unfortunatly, at this time you can't add a protocol entirely by KLD, as
you still need to change in-line code in if_ethersubr.c

that is being worked on, but may take a while to coome to light.

julian


> 
> Can somebody shed some light on this?
> 
> Thanks in advance,
> Chris
> 
> -- 
>   "We are not bound by any concept, we are just bound to make any concept work 
>    better than others."                                  --  Dr. Ferry Porsche
> 
> [Disclaimer: I speak for myself and my views are my own and not in any way to
>              be construed as the views of BellSouth Corporation. ]
> 
> To Unsubscribe: send mail to majordomo@FreeBSD.org
> with "unsubscribe freebsd-hackers" in the body of the message
> 


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.3.95.990118213616.9336B-100000>