diff --git a/include/nuttx/net/netdev.h b/include/nuttx/net/netdev.h index fe61124e7c..bcc14ede5d 100644 --- a/include/nuttx/net/netdev.h +++ b/include/nuttx/net/netdev.h @@ -382,7 +382,8 @@ struct net_driver_s * NETDEV_DOWN - The network is down */ - FAR struct devif_callback_s *d_conncb; + FAR struct devif_callback_s *d_conncb; /* This is the list head */ + FAR struct devif_callback_s *d_conncb_tail; /* This is the list tail */ FAR struct devif_callback_s *d_devcb; /* Driver callbacks */ diff --git a/net/arp/arp.h b/net/arp/arp.h index 41153a0a8f..e0aec9f3ef 100644 --- a/net/arp/arp.h +++ b/net/arp/arp.h @@ -75,7 +75,9 @@ /* Allocate a new ARP data callback */ -#define arp_callback_alloc(dev) devif_callback_alloc(dev, &(dev)->d_conncb) +#define arp_callback_alloc(dev) devif_callback_alloc(dev, \ + &(dev)->d_conncb, \ + &(dev)->d_conncb_tail) #define arp_callback_free(dev,cb) devif_dev_callback_free(dev, cb) /**************************************************************************** diff --git a/net/bluetooth/bluetooth.h b/net/bluetooth/bluetooth.h index 44167b219d..f4b5051819 100644 --- a/net/bluetooth/bluetooth.h +++ b/net/bluetooth/bluetooth.h @@ -42,9 +42,9 @@ /* Allocate a new Bluetooth socket data callback */ #define bluetooth_callback_alloc(dev,conn) \ - devif_callback_alloc(dev, &conn->bc_list) + devif_callback_alloc(dev, &conn->bc_list, &conn->bc_list_tail) #define bluetooth_callback_free(dev,conn,cb) \ - devif_conn_callback_free(dev, cb, &conn->bc_list) + devif_conn_callback_free(dev, cb, &conn->bc_list, &conn->bc_list_tail) /* Memory Pools */ @@ -85,6 +85,7 @@ struct bluetooth_conn_s */ FAR struct devif_callback_s *bc_list; /* Bluetooth callbacks */ + FAR struct devif_callback_s *bc_list_tail; /* Bluetooth callbacks */ /* Bluetooth-specific content follows. */ diff --git a/net/can/can.h b/net/can/can.h index b2b51b778d..0927942269 100644 --- a/net/can/can.h +++ b/net/can/can.h @@ -51,9 +51,9 @@ /* Allocate a new packet socket data callback */ #define can_callback_alloc(dev,conn) \ - devif_callback_alloc(dev, &conn->list) + devif_callback_alloc(dev, &conn->list, &conn->list_tail) #define can_callback_free(dev,conn,cb) \ - devif_conn_callback_free(dev, cb, &conn->list) + devif_conn_callback_free(dev, cb, &conn->list, &conn->list_tail) /**************************************************************************** * Public Type Definitions @@ -82,7 +82,8 @@ struct can_conn_s * event. */ - FAR struct devif_callback_s *list; /* NetLink callbacks */ + FAR struct devif_callback_s *list; /* NetLink callbacks */ + FAR struct devif_callback_s *list_tail; /* NetLink callbacks */ FAR struct net_driver_s *dev; /* Reference to CAN device */ diff --git a/net/devif/devif.h b/net/devif/devif.h index deb7d9c29a..fc01466333 100644 --- a/net/devif/devif.h +++ b/net/devif/devif.h @@ -330,7 +330,8 @@ void devif_callback_init(void); FAR struct devif_callback_s * devif_callback_alloc(FAR struct net_driver_s *dev, - FAR struct devif_callback_s **list); + FAR struct devif_callback_s **list_head, + FAR struct devif_callback_s **list_tail); /**************************************************************************** * Name: devif_conn_callback_free @@ -352,7 +353,8 @@ FAR struct devif_callback_s * void devif_conn_callback_free(FAR struct net_driver_s *dev, FAR struct devif_callback_s *cb, - FAR struct devif_callback_s **list); + FAR struct devif_callback_s **list_head, + FAR struct devif_callback_s **list_tail); /**************************************************************************** * Name: devif_dev_callback_free diff --git a/net/devif/devif_callback.c b/net/devif/devif_callback.c index 1d49a7c09c..69a8b249c1 100644 --- a/net/devif/devif_callback.c +++ b/net/devif/devif_callback.c @@ -62,7 +62,8 @@ static FAR struct devif_callback_s *g_cbfreelist = NULL; static void devif_callback_free(FAR struct net_driver_s *dev, FAR struct devif_callback_s *cb, - FAR struct devif_callback_s **list) + FAR struct devif_callback_s **list_head, + FAR struct devif_callback_s **list_tail) { FAR struct devif_callback_s *prev; FAR struct devif_callback_s *curr; @@ -116,11 +117,11 @@ static void devif_callback_free(FAR struct net_driver_s *dev, * it is supposed to be in the data notification list. */ - if (list) + if (list_head) { /* Find the callback structure in the connection event list */ - for (prev = NULL, curr = *list; + for (prev = NULL, curr = *list_head; curr && curr != cb; prev = curr, curr = curr->nxtconn) { @@ -133,11 +134,25 @@ static void devif_callback_free(FAR struct net_driver_s *dev, { if (prev) { + /* The found item to be removed is not in the head. */ + prev->nxtconn = cb->nxtconn; } else { - *list = cb->nxtconn; + /* The found item to be removed is in the head. */ + + *list_head = cb->nxtconn; + } + + if (!cb->nxtconn) + { + /* If the tail item is being removed, + * update the tail pointer. + */ + + DEBUGASSERT(list_tail); + *list_tail = prev; } } } @@ -235,11 +250,12 @@ void devif_callback_init(void) FAR struct devif_callback_s * devif_callback_alloc(FAR struct net_driver_s *dev, - FAR struct devif_callback_s **list) + FAR struct devif_callback_s **list_head, + FAR struct devif_callback_s **list_tail) { FAR struct devif_callback_s *ret; - /* Check the head of the free list */ + /* Check the head of the free list */ net_lock(); ret = g_cbfreelist; @@ -267,7 +283,7 @@ FAR struct devif_callback_s * { /* No.. release the callback structure and fail */ - devif_callback_free(NULL, NULL, list); + devif_callback_free(NULL, NULL, list_head, list_tail); net_unlock(); return NULL; } @@ -276,12 +292,28 @@ FAR struct devif_callback_s * dev->d_devcb = ret; } - /* Add the newly allocated instance to the head of the specified list */ + /* Add the newly allocated instance to the tail of the specified list */ - if (list) + if (list_head && list_tail) { - ret->nxtconn = *list; - *list = ret; + ret->nxtconn = NULL; + + if (*list_tail) + { + /* If the list is not empty, add the item to the tail. */ + + (*list_tail)->nxtconn = ret; + } + else + { + /* If the list is empty, add the first item to the list. */ + + *list_head = ret; + } + + /* Update the tail pointer */ + + *list_tail = ret; } } #ifdef CONFIG_DEBUG_FEATURES @@ -315,7 +347,8 @@ FAR struct devif_callback_s * void devif_conn_callback_free(FAR struct net_driver_s *dev, FAR struct devif_callback_s *cb, - FAR struct devif_callback_s **list) + FAR struct devif_callback_s **list_head, + FAR struct devif_callback_s **list_tail) { /* Check if the device pointer is still valid. It could be invalid if, for * example, the device were unregistered between the time when the callback @@ -331,7 +364,7 @@ void devif_conn_callback_free(FAR struct net_driver_s *dev, /* Then free the callback */ - devif_callback_free(dev, cb, list); + devif_callback_free(dev, cb, list_head, list_tail); } /**************************************************************************** @@ -357,7 +390,8 @@ void devif_conn_callback_free(FAR struct net_driver_s *dev, void devif_dev_callback_free(FAR struct net_driver_s *dev, FAR struct devif_callback_s *cb) { - FAR struct devif_callback_s **list; + FAR struct devif_callback_s **list_head; + FAR struct devif_callback_s **list_tail; /* Check if the device pointer is still valid. It could be invalid if, for * example, the device were unregistered between the time when the callback @@ -366,23 +400,25 @@ void devif_dev_callback_free(FAR struct net_driver_s *dev, if (dev != NULL && netdev_verify(dev)) { - /* The device reference is valid.. the use the list pointer in the + /* The device reference is valid. Then use the list pointer in the * device structure as well. */ - list = &dev->d_conncb; + list_head = &dev->d_conncb; + list_tail = &dev->d_conncb_tail; } else { /* The device reference is longer valid */ dev = NULL; - list = NULL; + list_head = NULL; + list_tail = NULL; } /* Then free the callback */ - devif_callback_free(dev, cb, list); + devif_callback_free(dev, cb, list_head, list_tail); } /**************************************************************************** diff --git a/net/icmp/icmp.h b/net/icmp/icmp.h index 5375e4b8b5..031ac453f8 100644 --- a/net/icmp/icmp.h +++ b/net/icmp/icmp.h @@ -47,9 +47,9 @@ /* Allocate/free an ICMP data callback */ #define icmp_callback_alloc(dev, conn) \ - devif_callback_alloc((dev), &(conn)->list) + devif_callback_alloc((dev), &(conn)->list, &(conn)->list_tail) #define icmp_callback_free(dev, conn, cb) \ - devif_conn_callback_free((dev), (cb), &(conn)->list) + devif_conn_callback_free((dev), (cb), &(conn)->list, &(conn)->list_tail) /**************************************************************************** * Public types @@ -84,6 +84,7 @@ struct icmp_conn_s */ FAR struct devif_callback_s *list; + FAR struct devif_callback_s *list_tail; /* ICMP-specific content follows */ diff --git a/net/icmpv6/icmpv6.h b/net/icmpv6/icmpv6.h index 549aaeab1a..42bc4051a9 100644 --- a/net/icmpv6/icmpv6.h +++ b/net/icmpv6/icmpv6.h @@ -48,9 +48,9 @@ /* Allocate a new ICMPv6 data callback */ #define icmpv6_callback_alloc(dev, conn) \ - devif_callback_alloc((dev), &(conn)->list) + devif_callback_alloc((dev), &(conn)->list, &(conn)->list_tail) #define icmpv6_callback_free(dev, conn, cb) \ - devif_conn_callback_free((dev), (cb), &(conn)->list) + devif_conn_callback_free((dev), (cb), &(conn)->list, &(conn)->list_tail) /**************************************************************************** * Public Type Definitions @@ -86,6 +86,7 @@ struct icmpv6_conn_s */ FAR struct devif_callback_s *list; + FAR struct devif_callback_s *list_tail; /* ICMPv6-specific content follows */ diff --git a/net/icmpv6/icmpv6_autoconfig.c b/net/icmpv6/icmpv6_autoconfig.c index 968fe24848..8cf0c85c9e 100644 --- a/net/icmpv6/icmpv6_autoconfig.c +++ b/net/icmpv6/icmpv6_autoconfig.c @@ -198,7 +198,9 @@ static int icmpv6_send_message(FAR struct net_driver_s *dev, bool advertise) * want anything to happen until we are ready. */ - state.snd_cb = devif_callback_alloc(dev, &dev->d_conncb); + state.snd_cb = devif_callback_alloc(dev, + &dev->d_conncb, + &dev->d_conncb_tail); if (!state.snd_cb) { nerr("ERROR: Failed to allocate a cllback\n"); diff --git a/net/icmpv6/icmpv6_neighbor.c b/net/icmpv6/icmpv6_neighbor.c index 089ee343c3..8c175bdc75 100644 --- a/net/icmpv6/icmpv6_neighbor.c +++ b/net/icmpv6/icmpv6_neighbor.c @@ -240,7 +240,9 @@ int icmpv6_neighbor(const net_ipv6addr_t ipaddr) */ net_lock(); - state.snd_cb = devif_callback_alloc((dev), &(dev)->d_conncb); + state.snd_cb = devif_callback_alloc((dev), + &(dev)->d_conncb, + &(dev)->d_conncb_tail); if (!state.snd_cb) { nerr("ERROR: Failed to allocate a callback\n"); diff --git a/net/ieee802154/ieee802154.h b/net/ieee802154/ieee802154.h index 19c7d542df..104f66a4ed 100644 --- a/net/ieee802154/ieee802154.h +++ b/net/ieee802154/ieee802154.h @@ -40,9 +40,9 @@ /* Allocate a new IEEE 802.15.4 socket data callback */ #define ieee802154_callback_alloc(dev,conn) \ - devif_callback_alloc(dev, &conn->list) + devif_callback_alloc(dev, &conn->list, &conn->list_tail) #define ieee802154_callback_free(dev,conn,cb) \ - devif_conn_callback_free(dev, cb, &conn->list) + devif_conn_callback_free(dev, cb, &conn->list, &conn->list_tail) /* Memory Pools */ @@ -104,6 +104,7 @@ struct ieee802154_conn_s */ FAR struct devif_callback_s *list; + FAR struct devif_callback_s *list_tail; /* IEEE 802.15.4-specific content follows */ diff --git a/net/ipforward/ipforward.h b/net/ipforward/ipforward.h index ae9b95a651..ebc65519c0 100644 --- a/net/ipforward/ipforward.h +++ b/net/ipforward/ipforward.h @@ -44,7 +44,9 @@ /* Allocate a new IP forwarding data callback */ -#define ipfwd_callback_alloc(dev) devif_callback_alloc(dev, &(dev)->d_conncb) +#define ipfwd_callback_alloc(dev) devif_callback_alloc(dev, \ + &(dev)->d_conncb, \ + &(dev)->d_conncb_tail) #define ipfwd_callback_free(dev,cb) devif_dev_callback_free(dev, cb) /**************************************************************************** diff --git a/net/netdev/netdev_register.c b/net/netdev/netdev_register.c index cc70c2afa4..c4ade6f611 100644 --- a/net/netdev/netdev_register.c +++ b/net/netdev/netdev_register.c @@ -364,6 +364,7 @@ int netdev_register(FAR struct net_driver_s *dev, enum net_lltype_e lltype) /* There are no clients of the device yet */ dev->d_conncb = NULL; + dev->d_conncb_tail = NULL; dev->d_devcb = NULL; /* We need exclusive access for the following operations */ diff --git a/net/pkt/pkt.h b/net/pkt/pkt.h index 2a65519f24..56b8a2d7bb 100644 --- a/net/pkt/pkt.h +++ b/net/pkt/pkt.h @@ -39,9 +39,9 @@ /* Allocate a new packet socket data callback */ #define pkt_callback_alloc(dev,conn) \ - devif_callback_alloc(dev, &conn->list) + devif_callback_alloc(dev, &conn->list, &conn->list_tail) #define pkt_callback_free(dev,conn,cb) \ - devif_conn_callback_free(dev, cb, &conn->list) + devif_conn_callback_free(dev, cb, &conn->list, &conn->list_tail) /**************************************************************************** * Public Type Definitions @@ -62,6 +62,7 @@ struct pkt_conn_s */ struct devif_callback_s *list; + struct devif_callback_s *list_tail; /* Pkt socket-specific content follows */ diff --git a/net/sixlowpan/sixlowpan_internal.h b/net/sixlowpan/sixlowpan_internal.h index f250ebe979..c70f7ef185 100644 --- a/net/sixlowpan/sixlowpan_internal.h +++ b/net/sixlowpan/sixlowpan_internal.h @@ -284,6 +284,7 @@ struct iob_s; /* Forward reference */ int sixlowpan_send(FAR struct net_driver_s *dev, FAR struct devif_callback_s **list, + FAR struct devif_callback_s **list_tail, FAR const struct ipv6_hdr_s *ipv6hdr, FAR const void *buf, size_t len, FAR const struct netdev_varaddr_s *destmac, unsigned int timeout); diff --git a/net/sixlowpan/sixlowpan_send.c b/net/sixlowpan/sixlowpan_send.c index b2c6456021..5587797398 100644 --- a/net/sixlowpan/sixlowpan_send.c +++ b/net/sixlowpan/sixlowpan_send.c @@ -203,6 +203,7 @@ end_wait: int sixlowpan_send(FAR struct net_driver_s *dev, FAR struct devif_callback_s **list, + FAR struct devif_callback_s **list_tail, FAR const struct ipv6_hdr_s *ipv6hdr, FAR const void *buf, size_t len, FAR const struct netdev_varaddr_s *destmac, unsigned int timeout) @@ -231,7 +232,7 @@ int sixlowpan_send(FAR struct net_driver_s *dev, * device related events, no connect-related events. */ - sinfo.s_cb = devif_callback_alloc(dev, list); + sinfo.s_cb = devif_callback_alloc(dev, list, list_tail); if (sinfo.s_cb != NULL) { int ret; @@ -265,7 +266,7 @@ int sixlowpan_send(FAR struct net_driver_s *dev, /* Make sure that no further events are processed */ - devif_conn_callback_free(dev, sinfo.s_cb, list); + devif_conn_callback_free(dev, sinfo.s_cb, list, list_tail); } } diff --git a/net/sixlowpan/sixlowpan_udpsend.c b/net/sixlowpan/sixlowpan_udpsend.c index ea376f1309..4a2850c72c 100644 --- a/net/sixlowpan/sixlowpan_udpsend.c +++ b/net/sixlowpan/sixlowpan_udpsend.c @@ -292,7 +292,9 @@ ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock, * packet. */ - ret = sixlowpan_send(dev, &conn->list, + ret = sixlowpan_send(dev, + &conn->list, + &conn->list_tail, (FAR const struct ipv6_hdr_s *)&ipv6udp, buf, buflen, &destmac, _SO_TIMEOUT(psock->s_sndtimeo)); diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index f9e806cd76..0be73a1b80 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -54,9 +54,9 @@ */ #define tcp_callback_alloc(conn) \ - devif_callback_alloc((conn)->dev, &(conn)->list) + devif_callback_alloc((conn)->dev, &(conn)->list, &(conn)->list_tail) #define tcp_callback_free(conn,cb) \ - devif_conn_callback_free((conn)->dev, (cb), &(conn)->list) + devif_conn_callback_free((conn)->dev, (cb), &(conn)->list, &(conn)->list_tail) #ifdef CONFIG_NET_TCP_WRITE_BUFFERS /* TCP write buffer access macros */ @@ -164,6 +164,7 @@ struct tcp_conn_s */ FAR struct devif_callback_s *list; + FAR struct devif_callback_s *list_tail; /* TCP-specific content follows */ @@ -289,6 +290,7 @@ struct tcp_conn_s */ FAR struct devif_callback_s *connevents; + FAR struct devif_callback_s *connevents_tail; /* accept() is called when the TCP logic has created a connection * diff --git a/net/tcp/tcp_monitor.c b/net/tcp/tcp_monitor.c index 3ee5f08456..04a1e7b12c 100644 --- a/net/tcp/tcp_monitor.c +++ b/net/tcp/tcp_monitor.c @@ -213,7 +213,8 @@ static void tcp_shutdown_monitor(FAR struct tcp_conn_s *conn, uint16_t flags) while (conn->connevents != NULL) { devif_conn_callback_free(conn->dev, conn->connevents, - &conn->connevents); + &conn->connevents, + &conn->connevents_tail); } net_unlock(); @@ -284,7 +285,9 @@ int tcp_start_monitor(FAR struct socket *psock) * the network goes down. */ - cb = devif_callback_alloc(conn->dev, &conn->connevents); + cb = devif_callback_alloc(conn->dev, + &conn->connevents, + &conn->connevents_tail); if (cb != NULL) { cb->event = tcp_monitor_event; @@ -372,7 +375,10 @@ void tcp_close_monitor(FAR struct socket *psock) if (cb != NULL) { - devif_conn_callback_free(conn->dev, cb, &conn->connevents); + devif_conn_callback_free(conn->dev, + cb, + &conn->connevents, + &conn->connevents_tail); } /* Make sure that this socket is explicitly marked as closed */ diff --git a/net/udp/udp.h b/net/udp/udp.h index fef9c9f778..868ea6ddd3 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -61,9 +61,9 @@ /* Allocate a new UDP data callback */ #define udp_callback_alloc(dev,conn) \ - devif_callback_alloc((dev), &(conn)->list) + devif_callback_alloc((dev), &(conn)->list, &(conn)->list_tail) #define udp_callback_free(dev,conn,cb) \ - devif_conn_callback_free((dev), (cb), &(conn)->list) + devif_conn_callback_free((dev), (cb), &(conn)->list, &(conn)->list_tail) /* Definitions for the UDP connection struct flag field */ @@ -106,6 +106,7 @@ struct udp_conn_s */ FAR struct devif_callback_s *list; + FAR struct devif_callback_s *list_tail; /* UDP-specific content follows */ diff --git a/net/usrsock/usrsock.h b/net/usrsock/usrsock.h index 314d91c043..cf0bdcd041 100644 --- a/net/usrsock/usrsock.h +++ b/net/usrsock/usrsock.h @@ -105,6 +105,7 @@ struct usrsock_conn_s */ FAR struct devif_callback_s *list; /* Usersock callbacks */ + FAR struct devif_callback_s *list_tail; /* usrsock-specific content follows */ diff --git a/net/usrsock/usrsock_conn.c b/net/usrsock/usrsock_conn.c index 0d79124913..44d638fd3c 100644 --- a/net/usrsock/usrsock_conn.c +++ b/net/usrsock/usrsock_conn.c @@ -254,7 +254,7 @@ int usrsock_setup_request_callback(FAR struct usrsock_conn_s *conn, /* Set up the callback in the connection */ - pstate->cb = devif_callback_alloc(NULL, &conn->list); + pstate->cb = devif_callback_alloc(NULL, &conn->list, &conn->list_tail); if (pstate->cb) { /* Take a lock since only one outstanding request is allowed */ @@ -308,7 +308,7 @@ void usrsock_teardown_request_callback(FAR struct usrsock_reqstate_s *pstate) /* Make sure that no further events are processed */ - devif_conn_callback_free(NULL, pstate->cb, &conn->list); + devif_conn_callback_free(NULL, pstate->cb, &conn->list, &conn->list_tail); nxsem_destroy(&pstate->recvsem); pstate->cb = NULL; diff --git a/net/usrsock/usrsock_poll.c b/net/usrsock/usrsock_poll.c index c6cda3afe9..e6a9f9658b 100644 --- a/net/usrsock/usrsock_poll.c +++ b/net/usrsock/usrsock_poll.c @@ -187,7 +187,7 @@ static int usrsock_pollsetup(FAR struct socket *psock, /* Allocate a usrsock callback structure */ - cb = devif_callback_alloc(NULL, &conn->list); + cb = devif_callback_alloc(NULL, &conn->list, &conn->list_tail); if (cb == NULL) { ret = -EBUSY; @@ -331,7 +331,10 @@ static int usrsock_pollteardown(FAR struct socket *psock, { /* Release the callback */ - devif_conn_callback_free(NULL, info->cb, &conn->list); + devif_conn_callback_free(NULL, + info->cb, + &conn->list, + &conn->list_tail); /* Release the poll/select data slot */