diff --git a/net/devif/devif_forward.c b/net/devif/devif_forward.c index 87e4ad07e58..25fd323be74 100644 --- a/net/devif/devif_forward.c +++ b/net/devif/devif_forward.c @@ -75,26 +75,18 @@ void devif_forward(FAR struct forward_s *fwd) unsigned int offset; int ret; - DEBUGASSERT(fwd != NULL && fwd->f_dev != NULL); + DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL); offset = NET_LL_HDRLEN(fwd->f_dev); - /* Copy the saved L2 + L3 header */ + /* Copy the IOB chain that contains the L3L3 headers and any data payload */ - DEBUGASSERT(offset + fwd->f_hdrsize <= NET_DEV_MTU(fwd->f_dev)); - memcpy(&fwd->f_dev->d_buf[offset], &fwd->f_hdr, fwd->f_hdrsize); - offset += fwd->f_hdrsize; + DEBUGASSERT(fwd->f_iob->io_pktlen >= fwd->f_hdrsize); + DEBUGASSERT(offset + fwd->f_iob->io_pktlen <= NET_DEV_MTU(fwd->f_dev)); + ret = iob_copyout(&fwd->f_dev->d_buf[offset], fwd->f_iob, + fwd->f_iob->io_pktlen, 0); - /* Copy the IOB chain that contains the payload */ - - if (fwd->f_iob != NULL && fwd->f_iob->io_pktlen > 0) - { - DEBUGASSERT(offset + fwd->f_iob->io_pktlen <= NET_DEV_MTU(fwd->f_dev)); - ret = iob_copyout(&fwd->f_dev->d_buf[offset], fwd->f_iob, - fwd->f_iob->io_pktlen, 0); - - DEBUGASSERT(ret == fwd->f_iob->io_pktlen); - offset += fwd->f_iob->io_pktlen; - } + DEBUGASSERT(ret == fwd->f_iob->io_pktlen); + offset += fwd->f_iob->io_pktlen; fwd->f_dev->d_sndlen = offset; } diff --git a/net/devif/ip_forward.h b/net/devif/ip_forward.h index 5eed4d8bb3f..3180f16ac71 100644 --- a/net/devif/ip_forward.h +++ b/net/devif/ip_forward.h @@ -73,6 +73,8 @@ # define CONFIG_NET_IPFORWARD_NSTRUCT 4 #endif +#define FWD_HEADER(fwd) (FAR union fwd_iphdr_u *)((fwd)->f_iob->io_data) + /**************************************************************************** * Public Types ****************************************************************************/ @@ -158,10 +160,9 @@ struct forward_s { FAR struct forward_s *f_flink; /* Supports a singly linked list */ FAR struct net_driver_s *f_dev; /* Forwarding device */ - FAR struct iob_s *f_iob; /* IOBs containing the data payload */ + FAR struct iob_s *f_iob; /* IOB chain containing the packet */ FAR struct devif_callback_s *f_cb; /* Reference to callback instance */ - union fwd_iphdr_u f_hdr; /* Copy of original L2+L3 headers */ - union fwd_conn_u f_conn; /* Protocol-specific connectin struct */ + union fwd_conn_u f_conn; /* Protocol-specific connection struct */ uint8_t f_hdrsize; /* The size of the L2+L3 headers */ }; diff --git a/net/devif/ipv4_forward.c b/net/devif/ipv4_forward.c index 6487a5fff87..20077493136 100644 --- a/net/devif/ipv4_forward.c +++ b/net/devif/ipv4_forward.c @@ -267,8 +267,6 @@ static int ipv4_dev_forward(FAR struct net_driver_s *dev, FAR struct ipv4_hdr_s *ipv4) { FAR struct forward_s *fwd = NULL; - FAR uint8_t *payload; - unsigned int paysize; int hdrsize; int ret; @@ -318,73 +316,58 @@ static int ipv4_dev_forward(FAR struct net_driver_s *dev, goto errout_with_fwd; } - /* Save the entire L2 and L3 headers in the state structure */ + /* The L2/L3 headers must fit within one, contiguous IOB. */ - if (hdrsize > sizeof(union fwd_iphdr_u)) + if (hdrsize > CONFIG_IOB_BUFSIZE) { nwarn("WARNING: Header is too big for pre-allocated structure\n"); ret = -E2BIG; goto errout_with_fwd; } - memcpy(&fwd->f_hdr.ipv4, ipv4, hdrsize); fwd->f_hdrsize = hdrsize; - /* Decrement the TTL in the copy of the IPv4 header (retaining the - * original TTL in the source). If it decrements to zero, then drop - * the packet. + /* Try to allocate the head of an IOB chain. If this fails, the + * packet will be dropped; we are not operating in a context + * where waiting for an IOB is a good idea */ - ret = ipv4_decr_ttl(&fwd->f_hdr.ipv4.l2); - if (ret < 1) + fwd->f_iob = iob_tryalloc(false); + if (fwd->f_iob == NULL) { - nwarn("WARNING: Hop limit exceeded... Dropping!\n"); - ret = -EMULTIHOP; + nwarn("WARNING: iob_tryalloc() failed\n"); + ret = -ENOMEM; goto errout_with_fwd; } - /* Use the L2 + L3 header size to determine start and size of the data - * payload. - * - * Remember that the size of the L1 header has already been subtracted - * from dev->d_len. - */ - - payload = (FAR uint8_t *)ipv4 + hdrsize; - paysize = dev->d_len - hdrsize; - - /* If there is a payload, then copy it into an IOB chain. + /* Copy the L2/L3 headers plus any following payload into an IOB chain. + * iob_trycopin() will not wait, but will fail there are no available + * IOBs. * * REVISIT: Consider an alternative design that does not require data * copying. This would require a pool of d_buf's that are managed by * the network rather than the network device. */ - if (paysize > 0) + ret = iob_trycopyin(fwd->f_iob, (FAR const uint8_t *)ipv4, + dev->d_len, 0, false); + if (ret < 0) { - /* Try to allocate the head of an IOB chain. If this fails, the - * packet will be dropped; we are not operating in a context - * where waiting for an IOB is a good idea - */ + nwarn("WARNING: iob_trycopyin() failed: %d\n", ret); + goto errout_with_iobchain; + } - fwd->f_iob = iob_tryalloc(false); - if (fwd->f_iob == NULL) - { - nwarn("WARNING: iob_tryalloc() failed\n"); - ret = -ENOMEM; - goto errout_with_fwd; - } + /* Decrement the TTL in the copy of the IPv4 header (retaining the + * original TTL in the source to handle the broadcast case). If the + * TLL decrements to zero, then do not forward the packet. + */ - /* Copy the packet data payload into an IOB chain. iob_trycopin() will - * not wait, but will fail there are no available IOBs. - */ - - ret = iob_trycopyin(fwd->f_iob, payload, paysize, 0, false); - if (ret < 0) - { - nwarn("WARNING: iob_trycopyin() failed: %d\n", ret); - goto errout_with_iobchain; - } + ret = ipv4_decr_ttl((FAR struct ipv4_hdr_s *)fwd->f_iob->io_data); + if (ret < 1) + { + nwarn("WARNING: Hop limit exceeded... Dropping!\n"); + ret = -EMULTIHOP; + goto errout_with_iobchain; } /* Then set up to forward the packet according to the protocol. diff --git a/net/devif/ipv6_forward.c b/net/devif/ipv6_forward.c index 055968c7fbb..1ece8ccee76 100644 --- a/net/devif/ipv6_forward.c +++ b/net/devif/ipv6_forward.c @@ -381,9 +381,6 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev, } else if (ret == PACKET_NOT_FORWARDED) { - FAR uint8_t *payload; - unsigned int paysize; - /* Verify that the full packet will fit within the forwarding devices * MTU. We provide no support for fragmenting forwarded packets. */ @@ -430,74 +427,58 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev, goto errout_with_fwd; } - /* Save the entire L2 and L3 headers in the state structure */ + /* The L2/L3 headers must fit within one, contiguous IOB. */ - if (hdrsize > sizeof(union fwd_iphdr_u)) + if (hdrsize > CONFIG_IOB_BUFSIZE) { nwarn("WARNING: Header is too big for pre-allocated structure\n"); ret = -E2BIG; goto errout_with_fwd; } - memcpy(&fwd->f_hdr.ipv6, ipv6, hdrsize); fwd->f_hdrsize = hdrsize; - /* Decrement the TTL in the copy of the IPv6 header (retaining the - * original TTL in the source). If it decrements to zero, then drop - * the packet. + /* Try to allocate the head of an IOB chain. If this fails, the + * packet will be dropped; we are not operating in a context where + * waiting for an IOB is a good idea */ - ret = ipv6_decr_ttl(&fwd->f_hdr.ipv6.l2); - if (ret < 1) + fwd->f_iob = iob_tryalloc(false); + if (fwd->f_iob == NULL) { - nwarn("WARNING: Hop limit exceeded... Dropping!\n"); - ret = -EMULTIHOP; + nwarn("WARNING: iob_tryalloc() failed\n"); + ret = -ENOMEM; goto errout_with_fwd; } - /* Use the L2 + L3 header size to determine start and size of the data - * payload. - * - * Remember that the size of the L1 header has already been subtracted - * from dev->d_len. - */ - - payload = (FAR uint8_t *)ipv6 + hdrsize; - paysize = dev->d_len - hdrsize; - - /* If there is a payload, then copy it into an IOB chain. + /* Copy the L2/L3 headers plus any following payload into an IOB + * chain. iob_trycopin() will not wait, but will fail there are no + * available IOBs. * * REVISIT: Consider an alternative design that does not require data * copying. This would require a pool of d_buf's that are managed by * the network rather than the network device. */ - if (paysize > 0) + ret = iob_trycopyin(fwd->f_iob, (FAR const uint8_t *)ipv6, + dev->d_len, 0, false); + if (ret < 0) { - /* Try to allocate the head of an IOB chain. If this fails, - * the packet will be dropped; we are not operating in a - * context where waiting for an IOB is a good idea - */ + nwarn("WARNING: iob_trycopyin() failed: %d\n", ret); + goto errout_with_iobchain; + } - fwd->f_iob = iob_tryalloc(false); - if (fwd->f_iob == NULL) - { - nwarn("WARNING: iob_tryalloc() failed\n"); - ret = -ENOMEM; - goto errout_with_fwd; - } + /* Decrement the TTL in the copy of the IPv6 header (retaining the + * original TTL in the sourcee to handle the broadcast case). If the + * TTL decrements to zero, then do not forward the packet. + */ - /* Copy the packet data payload into an IOB chain. - * iob_trycopin() will not wait, but will fail there are no - * available IOBs. - */ - - ret = iob_trycopyin(fwd->f_iob, payload, paysize, 0, false); - if (ret < 0) - { - nwarn("WARNING: iob_trycopyin() failed: %d\n", ret); - goto errout_with_iobchain; - } + ret = ipv6_decr_ttl((FAR struct ipv6_hdr_s *)fwd->f_iob->io_data); + if (ret < 1) + { + nwarn("WARNING: Hop limit exceeded... Dropping!\n"); + ret = -EMULTIHOP; + goto errout_with_iobchain; } /* Then set up to forward the packet according to the protocol. diff --git a/net/icmp/icmp_foward.c b/net/icmp/icmp_foward.c index c46b626889a..e1423907d64 100644 --- a/net/icmp/icmp_foward.c +++ b/net/icmp/icmp_foward.c @@ -96,6 +96,12 @@ #ifdef CONFIG_NET_ETHERNET static inline bool icmp_forward_addrchck(FAR struct forward_s *fwd) { +#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND) + FAR union fwd_iphdr_u *iphdr; +#endif + + DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL); + /* REVISIT: Could the MAC address not also be in a routing table? */ #ifdef CONFIG_NET_MULTILINK @@ -106,7 +112,8 @@ static inline bool icmp_forward_addrchck(FAR struct forward_s *fwd) #endif #if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND) - return (arp_find(fwd->f_hdr.ipv4.l2.destipaddr) != NULL); + iphdr = FWD_HEADER(fwd); + return (arp_find(iphdr->ipv4.l2.destipaddr) != NULL); #else return true; #endif @@ -164,13 +171,13 @@ static inline void icmp_dropstats(FAR struct forward_s *fwd) ****************************************************************************/ static uint16_t icmp_forward_interrupt(FAR struct net_driver_s *dev, - FAR void *conn, FAR void *pvpriv, - uint16_t flags) + FAR void *conn, FAR void *pvpriv, + uint16_t flags) { FAR struct forward_s *fwd = (FAR struct forward_s *)pvpriv; ninfo("flags: %04x\n", flags); - DEBUGASSERT(fwd != NULL); + DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL); /* Make sure that this is from the forwarding device */ @@ -274,7 +281,7 @@ static uint16_t icmp_forward_interrupt(FAR struct net_driver_s *dev, int icmp_forward(FAR struct forward_s *fwd) { - DEBUGASSERT(fwd != NULL && fwd->f_dev != NULL); + DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL); /* Set up the callback in the connection */ diff --git a/net/icmpv6/icmpv6_forward.c b/net/icmpv6/icmpv6_forward.c index f1a6f8cb3de..17f35f2dd62 100644 --- a/net/icmpv6/icmpv6_forward.c +++ b/net/icmpv6/icmpv6_forward.c @@ -92,6 +92,12 @@ #ifdef CONFIG_NET_ETHERNET static inline bool icmpv6_forward_addrchck(FAR struct forward_s *fwd) { +#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND) + FAR union fwd_iphdr_u *iphdr; +#endif + + DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL); + /* REVISIT: Could the MAC address not also be in a routing table? */ #ifdef CONFIG_NET_MULTILINK @@ -102,7 +108,8 @@ static inline bool icmpv6_forward_addrchck(FAR struct forward_s *fwd) #endif #if !defined(CONFIG_NET_ICMPv6_NEIGHBOR) - return (neighbor_findentry(fwd->f_hdr.ipv6.l2.destipaddr) != NULL); + iphdr = FWD_HEADER(fwd); + return (arp_find(iphdr->ipv6.l2.destipaddr) != NULL); #else return true; #endif @@ -166,7 +173,7 @@ static uint16_t icmpv6_forward_interrupt(FAR struct net_driver_s *dev, FAR struct forward_s *fwd = (FAR struct forward_s *)pvpriv; ninfo("flags: %04x\n", flags); - DEBUGASSERT(fwd != NULL); + DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL); /* Make sure that this is from the forwarding device */ @@ -270,7 +277,7 @@ static uint16_t icmpv6_forward_interrupt(FAR struct net_driver_s *dev, int icmpv6_forward(FAR struct forward_s *fwd) { - DEBUGASSERT(fwd != NULL && fwd->f_dev != NULL); + DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL); /* Set up the callback in the connection */ diff --git a/net/neighbor/neighbor_add.c b/net/neighbor/neighbor_add.c index 61fe2ac7dd8..f5c04872783 100644 --- a/net/neighbor/neighbor_add.c +++ b/net/neighbor/neighbor_add.c @@ -47,6 +47,9 @@ #include #include +#include + +#include #include #include "neighbor/neighbor.h" @@ -117,7 +120,7 @@ void neighbor_add(FAR net_ipv6addr_t ipaddr, uint8_t lltype, } #ifdef CONFIG_NET_MULTILINK - if (g_neighbors[i].ne_addr.na_lltype == lltype && + if (g_neighbors[i].ne_addr.u.na_lltype == lltype && net_ipv6addr_cmp(g_neighbors[i].ne_ipaddr, ipaddr)) #else if (net_ipv6addr_cmp(g_neighbors[i].ne_ipaddr, ipaddr)) @@ -142,7 +145,7 @@ void neighbor_add(FAR net_ipv6addr_t ipaddr, uint8_t lltype, net_ipv6addr_copy(g_neighbors[oldest_ndx].ne_ipaddr, ipaddr); #ifdef CONFIG_NET_MULTILINK - g_neighbors[oldest_ndx].ne_addr.na_lltype = lltype; + g_neighbors[oldest_ndx].ne_addr.u.na_lltype = lltype; #endif memcpy(&g_neighbors[oldest_ndx].ne_addr.u, addr, addrlen); diff --git a/net/neighbor/neighbor_dumpentry.c b/net/neighbor/neighbor_dumpentry.c index c66d9982851..78369f09172 100644 --- a/net/neighbor/neighbor_dumpentry.c +++ b/net/neighbor/neighbor_dumpentry.c @@ -39,6 +39,8 @@ #include +#include + #include "neighbor/neighbor.h" #ifdef CONFIG_DEBUG_NET_INFO @@ -74,7 +76,7 @@ void neighbor_dumpentry(FAR const char *msg, #ifdef CONFIG_NET_ETHERNET #ifdef CONFIG_NET_6LOWPAN - if (neighbor->ne_addr.na_lltype == NET_LL_ETHERNET) + if (neighbor->ne_addr.u.na_lltype == NET_LL_ETHERNET) #endif { ninfo(" at: %02x:%02x:%02x:%02x:%02x:%02x\n", diff --git a/net/tcp/tcp_forward.c b/net/tcp/tcp_forward.c index c67cac7a6e7..cc85f05eb63 100644 --- a/net/tcp/tcp_forward.c +++ b/net/tcp/tcp_forward.c @@ -259,7 +259,7 @@ static uint16_t tcp_forward_interrupt(FAR struct net_driver_s *dev, FAR struct forward_s *fwd = (FAR struct forward_s *)pvpriv; ninfo("flags: %04x\n", flags); - DEBUGASSERT(fwd != NULL); + DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL); /* Make sure that this is from the forwarding device */ @@ -375,22 +375,25 @@ static uint16_t tcp_forward_interrupt(FAR struct net_driver_s *dev, int tcp_forward(FAR struct forward_s *fwd) { - DEBUGASSERT(fwd != NULL && fwd->f_dev != NULL); FAR struct tcp_conn_s *conn = &fwd->f_conn.tcp; + FAR union fwd_iphdr_u *iphdr; + + DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL); /* Set up some minimal connection structure so that we appear to be a * real TCP connection. */ conn->dev = fwd->f_dev; + iphdr = FWD_HEADER(fwd); #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 - if ((fwd->f_hdr.ipv4.l2.vhl & IP_VERSION_MASK) == IPv4_VERSION) + if ((iphdr->ipv4.l2.vhl & IP_VERSION_MASK) == IPv4_VERSION) #endif { - FAR struct ipv4_hdr_s *ipv4 = &fwd->f_hdr.ipv4.l2; - FAR struct tcp_hdr_s *tcp = &fwd->f_hdr.ipv4.l3.tcp; + FAR struct ipv4_hdr_s *ipv4 = &iphdr->ipv4.l2; + FAR struct tcp_hdr_s *tcp = &iphdr->ipv4.l3.tcp; #if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) conn->domain = PF_INET; @@ -406,8 +409,8 @@ int tcp_forward(FAR struct forward_s *fwd) else #endif { - FAR struct ipv6_hdr_s *ipv6 = &fwd->f_hdr.ipv6.l2; - FAR struct tcp_hdr_s *tcp = &fwd->f_hdr.ipv6.l3.tcp; + FAR struct ipv6_hdr_s *ipv6 = &iphdr->ipv6.l2; + FAR struct tcp_hdr_s *tcp = &iphdr->ipv6.l3.tcp; #if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) conn->domain = PF_INET6; diff --git a/net/udp/udp_forward.c b/net/udp/udp_forward.c index b2c1363ab05..8c0473592d9 100644 --- a/net/udp/udp_forward.c +++ b/net/udp/udp_forward.c @@ -86,9 +86,11 @@ #if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) static inline void forward_ipselect(FAR struct forward_s *fwd) { + FAR union fwd_iphdr_u *iphdr = FWD_HEADER(fwd); + /* Select IPv4 or IPv6 */ - if ((fwd->f_hdr.ipv4.l2.vhl & IP_VERSION_MASK) == IPv4_VERSION) + if ((iphdr->ipv4.l2.vhl & IP_VERSION_MASK) == IPv4_VERSION) { udp_ipv4_select(fwd->f_dev); } @@ -132,6 +134,10 @@ static inline void forward_ipselect(FAR struct forward_s *fwd) #ifdef CONFIG_NET_ETHERNET static inline bool udp_forward_addrchk(FAR struct forward_s *fwd) { + FAR union fwd_iphdr_u *iphdr; + + DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL); + /* REVISIT: Could the MAC address not also be in a routing table? */ #ifdef CONFIG_NET_MULTILINK @@ -141,13 +147,15 @@ static inline bool udp_forward_addrchk(FAR struct forward_s *fwd) } #endif + iphdr = FWD_HEADER(fwd); + #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 - if ((fwd->f_hdr.ipv4.l2.vhl & IP_VERSION_MASK) == IPv4_VERSION) + if ((iphdr->ipv4.l2.vhl & IP_VERSION_MASK) == IPv4_VERSION) #endif { #if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND) - return (arp_find(fwd->f_hdr.ipv4.l2.destipaddr) != NULL); + return (arp_find(iphdr->ipv4.l2.destipaddr) != NULL); #else return true; #endif @@ -160,7 +168,7 @@ static inline bool udp_forward_addrchk(FAR struct forward_s *fwd) #endif { #if !defined(CONFIG_NET_ICMPv6_NEIGHBOR) - return (neighbor_findentry(fwd->f_hdr.ipv6.l2.destipaddr) != NULL); + return (neighbor_findentry(iphdr->ipv6.l2.destipaddr) != NULL); #else return true; #endif @@ -189,6 +197,10 @@ static inline bool udp_forward_addrchk(FAR struct forward_s *fwd) #ifdef CONFIG_NET_STATISTICS static void udp_dropstats(FAR struct forward_s *fwd) { +#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) + FAR union fwd_iphdr_u *iphdr = FWD_HEADER(fwd); +#endif + /* Increment the count of dropped UDP packets */ g_netstats.udp.drop++; @@ -197,7 +209,7 @@ static void udp_dropstats(FAR struct forward_s *fwd) #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 - if ((fwd->f_hdr.ipv4.l2.vhl & IP_VERSION_MASK) == IPv4_VERSION) + if ((iphdr->ipv4.l2.vhl & IP_VERSION_MASK) == IPv4_VERSION) #endif { g_netstats.ipv4.drop++; @@ -244,7 +256,7 @@ static uint16_t udp_forward_interrupt(FAR struct net_driver_s *dev, FAR struct forward_s *fwd = (FAR struct forward_s *)pvpriv; ninfo("flags: %04x\n", flags); - DEBUGASSERT(fwd != NULL); + DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL); /* Make sure that this is from the forwarding device */ @@ -357,7 +369,7 @@ static uint16_t udp_forward_interrupt(FAR struct net_driver_s *dev, int udp_forward(FAR struct forward_s *fwd) { - DEBUGASSERT(fwd != NULL && fwd->f_dev != NULL); + DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL); /* Set up the callback in the connection */