(before you start reading, sorry for my English…I think it’s


I just would like to replace the TCP/IP protocole with this down producer
(code below).

  1. So, like with the TCP/IP sockets , from an executable file, I call my
    broadcast_packet( ) function (which is in the down_producer…)
    With TCP/IP, we just need to include <sys/socket.h> which contains the
    function’s declarations…
    So, I just have to declare the functions in the executable file?
    (I guess it’s not so easy…)

  2. On the way down, after the executable file and the down producer, do I
    have to write a converter to add the ethernet header? Or is it correct when
    I just write “en” for the bottom type of my down_producer
    (io_net_registrant_t) ?

  3. Is there something special to do with the shutdown1, shutdown2 and flush

  4. Can you see memory leaks problems with this code?

  5. how do I have to compile this code? ("qcc /home/down_producer.c " gives
    no compilation error )
    I read this in news:
    qcc -Vgcc_nto86x -c -Wc, -Wall -Wc, -Wno-parentheses -O -DNDEBUG

I’m really sorry for these niewby questions, I know I got some problems to
understand the io-net philosophy and I got some gaps in global
But , please, I would be really, really thankful with a little bit of

Arnaud Stoumont


#include <sys/io-net.h>
#include <net/if_types.h>
#include <stdio.h>
#include <errno.h>

// Forward declaration of our initialization function:
int my_init (void *dll_hdl,
dispatch_t *dpp,
io_net_self_t *ion,
char *options);

static int client_register_device (void);

int broadcast_packet();

int client_shutdown1(int registrant_hdl, void *func_hdl);
int client_shutdown2(int registrant_hdl, void *func_hdl);
int client_flush (int registrant_hdl, void *func_hdl);

/*int (*reg) (void *dll_hdl,
io_net_registrant_t *registrant,
int *reg_hdlp, //The registrant handle, which is filled in
if the registration succeeds.
Use it as the registrant_hdl parameter to subsequent calls into io_net.
uint16_t *cell,
uint16_t *endpoint) */


void *client_dll_hdl;
io_net_self_t *client_ion; // to call the io_net functions from the
driver (io_net_self_t)

npkt_t *npkt;
net_buf_t *buf;
net_iov_t *iov;

int client_reg_hdl;
uint16_t client_cell;
uint16_t client_lan;


// Global symbol:
io_net_dll_entry_t io_net_dll_entry =
2, // Number of functions
my_init, // init()
NULL // “master” shutdown()

int my_init (void *dll_hdl, dispatch_t *dpp, io_net_self_t *ion, char
client_dll_hdl = dll_hdl;
client_ion = ion;

if (!client_register_device ()) // Register with io-net
return (-1); // couldn’t register, fail;
// errno says why

// Advertise our driver’s capabilities
// null_advertise (null_reg_hdl, null_entry.func_hdl); //don’t need
because it’s a down producer

return (0); // success

// functions that io_net can call from this driver
io_net_registrant_funcs_t client_funcs =
9, // nfuncs
NULL, // rx_up()
NULL, // rx_down()
NULL, // tx_done() (we need the tx_done
frome io_net, not from the driver)
client_shutdown1, // shutdown1()
client_shutdown2, // shutdown2()
NULL, // dl_advert() (don’t need because down producer)
NULL, // devctl()
client_flush, // flush()
NULL // raw_open()

// a description of our driver
io_net_registrant_t client_entry =
_REG_PRODUCER_DOWN, // we’re an “down” producer
“”, // our name
NULL, // our top type (none)
“en”, // our bottom type
NULL, // function handle (see the note below)
&client_funcs, // pointer to our functions
0 // #dependencies

static int client_register_device (void)
if ((*client_ion → reg)
&client_lan) < 0) {

return (0); // failed

return (1); // success
// At this point, you’ve registered your device driver with io-net.


int client_shutdown1(int registrant_hdl, void *func_hdl)

int client_shutdown2(int registrant_hdl, void *func_hdl)

int client_flush (int registrant_hdl, void *func_hdl)

// The packet

int broadcast_packet()

// 1) Allocate a packet, we’ll use this for communications with io-net.
if ((npkt = client_ion->alloc_down_npkt (client_reg_hdl, sizeof (*buf)

  • sizeof (*iov), (void *) &buf)) == NULL)
    return (0);
    } //don’t reserve room for the data because it’s just a pointer in
    the packet (avoid to copy it)

    // /
    2) Allocate room for the data.
    // if ((data = client_ion->alloc (sizeof (data), 0)) == NULL)
    // {
    // data_ion->free (npkt);
    // return (0);
    // }

    // 2) Set up the packet into the queue.
    TAILQ_INSERT_HEAD (&npkt → buffers, buf, ptrs);

iov = (net_iov_t *) (buf + 1);

buf → niov = 1;
buf → net_iov = iov;
iov → iov_base = data;
iov → iov_len = sizeof (*data);

// 5) Bind the data to the packet; and define it as a broadcast packet

npkt → org_data = data;
npkt → flags |= _NPKT_BCAST;
npkt → iface = 0; //The interface within the endpoint.
npkt → framelen = sizeof (*data);

// 6) Complete the transaction.
if(client_ion->tx_down (client_reg_hdl, npkt) == TX_DOWN_OK) {
client_ion->tx_done (client_reg_hdl, npkt);
return (0);

For the next lost QNX user :slight_smile:

  1. a thread inside the down producer works fine…

something like that:

void *tx_thread(void *argv)
npkt_t *npkt;

while(1) {
// build/send our pkt
npkt = alloc_pkt();

if(npkt != NULL)
ion->tx_down(reg_hdl, npkt);

start the thread in the init function

  1. write a convertor to convert from the bot_type of the down_producer to
    “en” type

3)don’t seems to need them for a down producer or a convertor…

4)compile : qcc -shared -o driver_name.c

try this code:
(just need some little corrections)

Chris, Sean, xtang, all this worked for me but, if I’m not right… please,
adjust the firing… Thanks :slight_smile:

Arnaud Stoumont