Binding Network Protocol Modules in io-net

Hi,

I know I’m a bit head of the documentation release for QRTP device drivers,
but does anyone know what I should use for the _io_net_registrant parameters
for a module filtering above an ethernet NIC module. I’m most clueless
about top_type, bot_type and func_hdl.

struct _io_net_registrant {
uint32_t flags;
char *name;
char *top_type;
char *bot_type;
void *func_hdl;
io_net_registrant_funcs_t funcs;
int ndependencies;
int reserved[2];
/
io_net_dependency_t [ndependencies]; */
};

Thanks

DAN

Daniel G. Waddington <dwaddington@lucent.com> wrote:
: Hi,

: I know I’m a bit head of the documentation release for QRTP device drivers,
: but does anyone know what I should use for the _io_net_registrant parameters
: for a module filtering above an ethernet NIC module. I’m most clueless
: about top_type, bot_type and func_hdl.

: struct _io_net_registrant {
: uint32_t flags;
: char *name;
: char *top_type;
: char *bot_type;
: void *func_hdl;
: io_net_registrant_funcs_t funcs;
: int ndependencies;
: int reserved[2];
: /
io_net_dependency_t [ndependencies]; */
: };

: Thanks

: DAN

Here’s a ‘dinky’ pass through filter. func_hdl is just passed to the callouts you
provide. ie it’s a convienent way to be passed a per registrant control struct.

-seanb


dinky.h

struct dinky_control {
int reg_hdl;
io_net_self_t *ion;
dispatch_t *dpp;
uint16_t endpoint;
};



dinky.c

#include <sys/io-net.h>
#include <net/if_ether.h>
#include <errno.h>
#include “dinky.h”

struct dinky_control dinky_ctrl;

int dinky_rx_up(npkt_t *npkt, void *func_hdl, int off, int len_sub, uint16_t cell, uint16_t endpoint, uint16_t iface);
int dinky_rx_down(npkt_t *npkt, void *rx_down_hdl);
int dinky_tx_done(npkt_t *npkt, void *done_hdl, void *func_hdl);
int dinky_shutdown1(int registrant_hdl, void *func_hdl);
int dinky_shutdown2(int registrant_hdl, void *func_hdl);
int dinky_devctl(void *hdl, int dcmd, void *data, size_t size, int *ret);

io_net_registrant_funcs_t dinky_funcs = {
8,
dinky_rx_up,
dinky_rx_down,
dinky_tx_done,
dinky_shutdown1,
dinky_shutdown2,
NULL, //advertise_ifaces
dinky_devctl,
NULL, //flush
NULL //raw_open
};

io_net_registrant_t dinky_reg = {_REG_FILTER_ABOVE, “ncm-dinky.so”, “en”, “en”, &dinky_ctrl, &dinky_funcs, 0};



int dinky_entry(void *dll_hdl, dispatch_t *dpp, io_net_self_t *n, char *options);

/* io-net does a dlsym on “io_net_dll_entry” so don’t change this name */
io_net_dll_entry_t io_net_dll_entry = {
2,
dinky_entry,
NULL
};

int
dinky_entry(void *dll_hdl, dispatch_t *dpp, io_net_self_t *n, char *options)
{
struct dinky_control *dc = &dinky_ctrl;

dc->ion = n;
dc->dpp = dpp;


if(dc->ion->reg(dll_hdl, &dinky_reg, &dc->reg_hdl, NULL, &dc->endpoint) == -1)
{
return -1;
}

/* To receive all up headed packets */
if(dc->ion->reg_byte_pat(dc->reg_hdl, 0, 0, NULL, _BYTE_PAT_ALL) == -1)
{
return -1;
}

return 0;
}



int
dinky_shutdown1(int registrant_hdl, void func_hdl)
{
/
Our last chance for this thread to tx (this thread has exclusive access) */
return 0;
}

int
dinky_shutdown2(int registrant_hdl, void func_hdl)
{
/
We now have shared access. This is where you would do most of your cleanup work */
return 0;
}

int
dinky_rx_down(npkt_t *npkt, void *func_hdl)
{
struct dinky_control *dc = func_hdl;
struct ether_header *eh;

if(npkt->flags & _NPKT_MSG)
{
/*

  • It’s a control packet of some sort.
  • Pass it on
    */
    return dc->ion->tx_down(dc->reg_hdl, npkt);
    }

#if 0
if(you_decide_not_to_pass_it_on)
{
dc->ion->tx_done(dc->reg_hdl, npkt);
return TX_DOWN_FAILED;
}
#endif

/*

  • arp always puts ethernet header in first buffer. ip stacks fragment thereafter. Of course
  • it could be from someone other than ip / arp.
    /
    eh = (struct ether_header )npkt->buffers.tqh_first->net_iov->iov_base;
    /
    Do your work here
    /

/* Then pass it on */
return dc->ion->tx_down(dc->reg_hdl, npkt);
}

int
dinky_rx_up(npkt_t *npkt, void *func_hdl, int off, int len_sub, uint16_t cell, uint16_t endpoint, uint16_t iface)
{
struct dinky_control *dc = func_hdl;
struct ether_header *eh;

if(npkt->flags & _NPKT_MSG)
{
/*

  • It’s a control packet of some sort.
  • You can learn about interfaces coming and going from below you this way
  • (see _IO_NET_MSG_DL_ADVERT and io_net_msg_dl_advert_t in <sys/io-net.h>).
  • You have to handle duplicate adverts. You get a npkt->flags & (_NPKT_MSG |_NPKT_MSG_DYING)
  • when cell endpoint is going away.
    */

/*

  • pass it on.
    /
    if(dc->ion->tx_up(dc->reg_hdl, npkt, off, len_sub, cell, endpoint, iface) == 0)
    {
    /
    noone above you took it */
    dc->ion->tx_done(dc->reg_hdl, npkt);
    }
    return 0;
    }
    #if 0
    if(you_decide_not_to_pass_it_on)
    {
    dc->ndi->tx_done(dc->reg_hdl, npkt);
    return 0;
    }
    #endif

/*

  • Should check how (if) the packet is fragmented.
    */
    eh = (struct ether_header *)npkt->buffers.tqh_first->net_iov->iov_base;

/* Do your work here */

/* Pass it on /
if(dc->ion->tx_up(dc->reg_hdl, npkt, off, len_sub, cell, endpoint, iface) == 0)
{
/
noone above you took it */
dc->ion->tx_done(dc->reg_hdl, npkt);
}

return 0;
}



int
dinky_tx_done(npkt_t *npkt, void *done_hdl, void *func_hdl)
{
struct dinky_control dc = func_hdl;
/

  • If you ever call dc->ion->reg_tx_done(dc->reg_hdl, npkt, done_hdl) (ever add something to
  • head or tail of down headed packet or ever originate your own up / down packet (don’t think
  • a sniffer would ever do this)), this func will be called when the packet is consumed so you
  • can undo / reclaim what you did. In this example it should never be called (we never call
  • dc->ion->reg_tx_done()).
    */

return 0;
}

int
dinky_devctl(void *hdl, int dcmd, void *data, size_t size, int ret)
{
/

  • Any devctl on /dev/io-net/en_enX where X is dc->endpoint (filters can be stacked)
  • will pop out here.
    */
    return EOPNOTSUPP;
    }

This is great, but I have one problem. How do I bind the npm to a specific
instance i.e just /dev/io-net/en1 as opposed to both en0 and en1? I guess I
can only have one instance of io-net?

DAN

“Sean Boudreau” <seanb@qnx.com> wrote in message
news:8s1q5e$n7t$1@nntp.qnx.com

Daniel G. Waddington <> dwaddington@lucent.com> > wrote:
: Hi,

: I know I’m a bit head of the documentation release for QRTP device
drivers,
: but does anyone know what I should use for the _io_net_registrant
parameters
: for a module filtering above an ethernet NIC module. I’m most clueless
: about top_type, bot_type and func_hdl.

: struct _io_net_registrant {
: uint32_t flags;
: char *name;
: char *top_type;
: char *bot_type;
: void *func_hdl;
: io_net_registrant_funcs_t funcs;
: int ndependencies;
: int reserved[2];
: /
io_net_dependency_t [ndependencies]; */
: };

: Thanks

: DAN

Here’s a ‘dinky’ pass through filter. func_hdl is just passed to the
callouts you
provide. ie it’s a convienent way to be passed a per registrant control
struct.

-seanb


dinky.h


struct dinky_control {
int reg_hdl;
io_net_self_t *ion;
dispatch_t *dpp;
uint16_t endpoint;
};




dinky.c


#include <sys/io-net.h
#include <net/if_ether.h
#include <errno.h
#include “dinky.h”

struct dinky_control dinky_ctrl;

int dinky_rx_up(npkt_t *npkt, void *func_hdl, int off, int len_sub,
uint16_t cell, uint16_t endpoint, uint16_t iface);
int dinky_rx_down(npkt_t *npkt, void *rx_down_hdl);
int dinky_tx_done(npkt_t *npkt, void *done_hdl, void *func_hdl);
int dinky_shutdown1(int registrant_hdl, void *func_hdl);
int dinky_shutdown2(int registrant_hdl, void *func_hdl);
int dinky_devctl(void *hdl, int dcmd, void *data, size_t size, int *ret);

io_net_registrant_funcs_t dinky_funcs = {
8,
dinky_rx_up,
dinky_rx_down,
dinky_tx_done,
dinky_shutdown1,
dinky_shutdown2,
NULL, file://advertise_ifaces
dinky_devctl,
NULL, file://flush
NULL file://raw_open
};

io_net_registrant_t dinky_reg = {_REG_FILTER_ABOVE, “ncm-dinky.so”, “en”,
“en”, &dinky_ctrl, &dinky_funcs, 0};



int dinky_entry(void *dll_hdl, dispatch_t *dpp, io_net_self_t *n, char
*options);

/* io-net does a dlsym on “io_net_dll_entry” so don’t change this name */
io_net_dll_entry_t io_net_dll_entry = {
2,
dinky_entry,
NULL
};

int
dinky_entry(void *dll_hdl, dispatch_t *dpp, io_net_self_t *n, char
*options)
{
struct dinky_control *dc = &dinky_ctrl;

dc->ion = n;
dc->dpp = dpp;


if(dc->ion->reg(dll_hdl, &dinky_reg, &dc->reg_hdl, NULL, &dc->endpoint)
== -1)
{
return -1;
}

/* To receive all up headed packets */
if(dc->ion->reg_byte_pat(dc->reg_hdl, 0, 0, NULL, _BYTE_PAT_ALL) == -1)
{
return -1;
}

return 0;
}



int
dinky_shutdown1(int registrant_hdl, void func_hdl)
{
/
Our last chance for this thread to tx (this thread has exclusive
access) */
return 0;
}

int
dinky_shutdown2(int registrant_hdl, void func_hdl)
{
/
We now have shared access. This is where you would do most of your
cleanup work */
return 0;
}

int
dinky_rx_down(npkt_t *npkt, void *func_hdl)
{
struct dinky_control *dc = func_hdl;
struct ether_header *eh;

if(npkt->flags & _NPKT_MSG)
{
/*

  • It’s a control packet of some sort.
  • Pass it on
    */
    return dc->ion->tx_down(dc->reg_hdl, npkt);
    }

#if 0
if(you_decide_not_to_pass_it_on)
{
dc->ion->tx_done(dc->reg_hdl, npkt);
return TX_DOWN_FAILED;
}
#endif

/*

  • arp always puts ethernet header in first buffer. ip stacks fragment
    thereafter. Of course
  • it could be from someone other than ip / arp.
    /
    eh = (struct ether_header )npkt->buffers.tqh_first->net_iov->iov_base;
    /
    Do your work here
    /

/* Then pass it on */
return dc->ion->tx_down(dc->reg_hdl, npkt);
}

int
dinky_rx_up(npkt_t *npkt, void *func_hdl, int off, int len_sub, uint16_t
cell, uint16_t endpoint, uint16_t iface)
{
struct dinky_control *dc = func_hdl;
struct ether_header *eh;

if(npkt->flags & _NPKT_MSG)
{
/*

  • It’s a control packet of some sort.
  • You can learn about interfaces coming and going from below you this way
  • (see _IO_NET_MSG_DL_ADVERT and io_net_msg_dl_advert_t in
    sys/io-net.h>).
  • You have to handle duplicate adverts. You get a npkt->flags &
    (_NPKT_MSG |_NPKT_MSG_DYING)
  • when cell endpoint is going away.
    */

/*

  • pass it on.
    /
    if(dc->ion->tx_up(dc->reg_hdl, npkt, off, len_sub, cell, endpoint, iface)
    == 0)
    {
    /
    noone above you took it */
    dc->ion->tx_done(dc->reg_hdl, npkt);
    }
    return 0;
    }
    #if 0
    if(you_decide_not_to_pass_it_on)
    {
    dc->ndi->tx_done(dc->reg_hdl, npkt);
    return 0;
    }
    #endif

/*

  • Should check how (if) the packet is fragmented.
    */
    eh = (struct ether_header *)npkt->buffers.tqh_first->net_iov->iov_base;

/* Do your work here */

/* Pass it on /
if(dc->ion->tx_up(dc->reg_hdl, npkt, off, len_sub, cell, endpoint, iface)
== 0)
{
/
noone above you took it */
dc->ion->tx_done(dc->reg_hdl, npkt);
}

return 0;
}



int
dinky_tx_done(npkt_t *npkt, void *done_hdl, void *func_hdl)
{
struct dinky_control dc = func_hdl;
/

  • If you ever call dc->ion->reg_tx_done(dc->reg_hdl, npkt, done_hdl) (ever
    add something to
  • head or tail of down headed packet or ever originate your own up /
    down packet (don’t think
  • a sniffer would ever do this)), this func will be called when the packet
    is consumed so you
  • can undo / reclaim what you did. In this example it should never be
    called (we never call
  • dc->ion->reg_tx_done()).
    */

return 0;
}

int
dinky_devctl(void *hdl, int dcmd, void *data, size_t size, int ret)
{
/

  • Any devctl on /dev/io-net/en_enX where X is dc->endpoint (filters can be
    stacked)
  • will pop out here.
    */
    return EOPNOTSUPP;
    }


A _REG_FILTER_ABOVE sits above all _REG_PRODUCER_UPs of its type (“en”
in this case). For up packets, the ‘endpoint’ argument to your rx_up
func tells you which ‘en’ it came from (endpoint == 0 → en0). You
can just pass through all endpoint != 0. For down packets, npkt->endpoint
tells you which en the upper layer is trying to send it out.

Hope that helps…

-seanb

Daniel G. Waddington <dwaddington@lucent.com> wrote:
: This is great, but I have one problem. How do I bind the npm to a specific
: instance i.e just /dev/io-net/en1 as opposed to both en0 and en1? I guess I
: can only have one instance of io-net?

: DAN

: “Sean Boudreau” <seanb@qnx.com> wrote in message
: news:8s1q5e$n7t$1@nntp.qnx.com
:> Daniel G. Waddington <dwaddington@lucent.com> wrote:
:> : Hi,
:>
:> : I know I’m a bit head of the documentation release for QRTP device
: drivers,
:> : but does anyone know what I should use for the _io_net_registrant
: parameters
:> : for a module filtering above an ethernet NIC module. I’m most clueless
:> : about top_type, bot_type and func_hdl.
:>
:> : struct _io_net_registrant {
:> : uint32_t flags;
:> : char *name;
:> : char *top_type;
:> : char *bot_type;
:> : void *func_hdl;
:> : io_net_registrant_funcs_t funcs;
:> : int ndependencies;
:> : int reserved[2];
:> : /
io_net_dependency_t [ndependencies]; */
:> : };
:>
:> : Thanks
:>
:> : DAN
:>
:> Here’s a ‘dinky’ pass through filter. func_hdl is just passed to the
: callouts you
:> provide. ie it’s a convienent way to be passed a per registrant control
: struct.
:>
:> -seanb
:>
:>
:> dinky.h
:> --------------------------------------------------------------------------
: -----------------------------
:> struct dinky_control {
:> int reg_hdl;
:> io_net_self_t *ion;
:> dispatch_t *dpp;
:> uint16_t endpoint;
:> };
:> --------------------------------------------------------------------------
: -----------------------------
:>
:>
:> dinky.c
:> --------------------------------------------------------------------------
: -----------------------------
:> #include <sys/io-net.h>
:> #include <net/if_ether.h>
:> #include <errno.h>
:> #include “dinky.h”
:>
:> struct dinky_control dinky_ctrl;
:>
:> int dinky_rx_up(npkt_t *npkt, void *func_hdl, int off, int len_sub,
: uint16_t cell, uint16_t endpoint, uint16_t iface);
:> int dinky_rx_down(npkt_t *npkt, void *rx_down_hdl);
:> int dinky_tx_done(npkt_t *npkt, void *done_hdl, void *func_hdl);
:> int dinky_shutdown1(int registrant_hdl, void *func_hdl);
:> int dinky_shutdown2(int registrant_hdl, void *func_hdl);
:> int dinky_devctl(void *hdl, int dcmd, void *data, size_t size, int *ret);
:>
:> io_net_registrant_funcs_t dinky_funcs = {
:> 8,
:> dinky_rx_up,
:> dinky_rx_down,
:> dinky_tx_done,
:> dinky_shutdown1,
:> dinky_shutdown2,
:> NULL, file://advertise_ifaces
:> dinky_devctl,
:> NULL, file://flush
:> NULL file://raw_open
:> };
:>
:> io_net_registrant_t dinky_reg = {_REG_FILTER_ABOVE, “ncm-dinky.so”, “en”,
: “en”, &dinky_ctrl, &dinky_funcs, 0};
:>
:>
:>
:> int dinky_entry(void *dll_hdl, dispatch_t *dpp, io_net_self_t *n, char
: options);
:>
:> /
io-net does a dlsym on “io_net_dll_entry” so don’t change this name */
:> io_net_dll_entry_t io_net_dll_entry = {
:> 2,
:> dinky_entry,
:> NULL
:> };
:>
:> int
:> dinky_entry(void *dll_hdl, dispatch_t *dpp, io_net_self_t *n, char
: *options)
:> {
:> struct dinky_control dc = &dinky_ctrl;
:>
:> dc->ion = n;
:> dc->dpp = dpp;
:>
:>
:> if(dc->ion->reg(dll_hdl, &dinky_reg, &dc->reg_hdl, NULL, &dc->endpoint)
: == -1)
:> {
:> return -1;
:> }
:>
:> /
To receive all up headed packets */
:> if(dc->ion->reg_byte_pat(dc->reg_hdl, 0, 0, NULL, _BYTE_PAT_ALL) == -1)
:> {
:> return -1;
:> }
:>
:> return 0;
:> }
:>
:>
:>
:> int
:> dinky_shutdown1(int registrant_hdl, void func_hdl)
:> {
:> /
Our last chance for this thread to tx (this thread has exclusive
: access) */
:> return 0;
:> }
:>
:> int
:> dinky_shutdown2(int registrant_hdl, void func_hdl)
:> {
:> /
We now have shared access. This is where you would do most of your
: cleanup work */
:> return 0;
:> }
:>
:> int
:> dinky_rx_down(npkt_t *npkt, void *func_hdl)
:> {
:> struct dinky_control dc = func_hdl;
:> struct ether_header eh;
:>
:> if(npkt->flags & _NPKT_MSG)
:> {
:> /

:> * It’s a control packet of some sort.
:> * Pass it on
:> /
:> return dc->ion->tx_down(dc->reg_hdl, npkt);
:> }
:>
:> #if 0
:> if(you_decide_not_to_pass_it_on)
:> {
:> dc->ion->tx_done(dc->reg_hdl, npkt);
:> return TX_DOWN_FAILED;
:> }
:> #endif
:>
:> /

:> * arp always puts ethernet header in first buffer. ip stacks fragment
: thereafter. Of course
:> * it could be from someone other than ip / arp.
:> /
:> eh = (struct ether_header )npkt->buffers.tqh_first->net_iov->iov_base;
:> /
Do your work here
/
:>
:> /
Then pass it on */
:> return dc->ion->tx_down(dc->reg_hdl, npkt);
:> }
:>
:> int
:> dinky_rx_up(npkt_t *npkt, void *func_hdl, int off, int len_sub, uint16_t
: cell, uint16_t endpoint, uint16_t iface)
:> {
:> struct dinky_control *dc = func_hdl;
:> struct ether_header eh;
:>
:> if(npkt->flags & _NPKT_MSG)
:> {
:> /

:> * It’s a control packet of some sort.
:> * You can learn about interfaces coming and going from below you this way
:> * (see _IO_NET_MSG_DL_ADVERT and io_net_msg_dl_advert_t in
: <sys/io-net.h>).
:> * You have to handle duplicate adverts. You get a npkt->flags &
: (_NPKT_MSG |_NPKT_MSG_DYING)
:> * when cell endpoint is going away.
:> /
:>
:> /

:> * pass it on.
:> /
:> if(dc->ion->tx_up(dc->reg_hdl, npkt, off, len_sub, cell, endpoint, iface)
: == 0)
:> {
:> /
noone above you took it /
:> dc->ion->tx_done(dc->reg_hdl, npkt);
:> }
:> return 0;
:> }
:> #if 0
:> if(you_decide_not_to_pass_it_on)
:> {
:> dc->ndi->tx_done(dc->reg_hdl, npkt);
:> return 0;
:> }
:> #endif
:>
:> /

:> * Should check how (if) the packet is fragmented.
:> */
:> eh = (struct ether_header )npkt->buffers.tqh_first->net_iov->iov_base;
:>
:> /
Do your work here /
:>
:> /
Pass it on /
:> if(dc->ion->tx_up(dc->reg_hdl, npkt, off, len_sub, cell, endpoint, iface)
: == 0)
:> {
:> /
noone above you took it */
:> dc->ion->tx_done(dc->reg_hdl, npkt);
:> }
:>
:> return 0;
:> }
:>
:>
:>
:> int
:> dinky_tx_done(npkt_t *npkt, void *done_hdl, void *func_hdl)
:> {
:> struct dinky_control dc = func_hdl;
:> /

:> * If you ever call dc->ion->reg_tx_done(dc->reg_hdl, npkt, done_hdl) (ever
: add something to
:> * head or tail of down headed packet or ever originate your own up /
: down packet (don’t think
:> * a sniffer would ever do this)), this func will be called when the packet
: is consumed so you
:> * can undo / reclaim what you did. In this example it should never be
: called (we never call
:> * dc->ion->reg_tx_done()).
:> */
:>
:> return 0;
:> }
:>
:> int
:> dinky_devctl(void *hdl, int dcmd, void *data, size_t size, int ret)
:> {
:> /

:> * Any devctl on /dev/io-net/en_enX where X is dc->endpoint (filters can be
: stacked)
:> * will pop out here.
:> */
:> return EOPNOTSUPP;
:> }
:> --------------------------------------------------------------------------
: -----------------------------