/** * Complete interrupt transfer * * @v ep USB endpoint * @v iobuf I/O buffer * @v rc Completion status code */ static void acm_intr_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf, int rc ) { struct acm_device *acm = container_of ( ep, struct acm_device, usbnet.intr ); struct rndis_device *rndis = acm->rndis; struct usb_setup_packet *message; /* Profile completions */ profile_start ( &acm_intr_profiler ); /* Ignore packets cancelled when the endpoint closes */ if ( ! ep->open ) goto ignore; /* Drop packets with errors */ if ( rc != 0 ) { DBGC ( acm, "ACM %p interrupt failed: %s\n", acm, strerror ( rc ) ); DBGC_HDA ( acm, 0, iobuf->data, iob_len ( iobuf ) ); goto error; } /* Extract message header */ if ( iob_len ( iobuf ) < sizeof ( *message ) ) { DBGC ( acm, "ACM %p underlength interrupt:\n", acm ); DBGC_HDA ( acm, 0, iobuf->data, iob_len ( iobuf ) ); rc = -EINVAL; goto error; } message = iobuf->data; /* Parse message header */ switch ( message->request ) { case cpu_to_le16 ( CDC_RESPONSE_AVAILABLE ) : case cpu_to_le16 ( 0x0001 ) : /* qemu seems to use this value */ acm->responded = 1; break; default: DBGC ( acm, "ACM %p unrecognised interrupt:\n", acm ); DBGC_HDA ( acm, 0, iobuf->data, iob_len ( iobuf ) ); rc = -ENOTSUP; goto error; } /* Free I/O buffer */ free_iob ( iobuf ); profile_stop ( &acm_intr_profiler ); return; error: rndis_rx_err ( rndis, iob_disown ( iobuf ), rc ); ignore: free_iob ( iobuf ); return; }
/** * Concatenate I/O buffers into a single buffer * * @v list List of I/O buffers * @ret iobuf Concatenated I/O buffer, or NULL on allocation failure * * After a successful concatenation, the list will be empty. */ struct io_buffer * iob_concatenate ( struct list_head *list ) { struct io_buffer *iobuf; struct io_buffer *tmp; struct io_buffer *concatenated; size_t len = 0; /* If the list contains only a single entry, avoid an * unnecessary additional allocation. */ if ( list_is_singular ( list ) ) { iobuf = list_first_entry ( list, struct io_buffer, list ); INIT_LIST_HEAD ( list ); return iobuf; } /* Calculate total length */ list_for_each_entry ( iobuf, list, list ) len += iob_len ( iobuf ); /* Allocate new I/O buffer */ concatenated = alloc_iob_raw ( len, __alignof__ ( *iobuf ), 0 ); if ( ! concatenated ) return NULL; /* Move data to new I/O buffer */ list_for_each_entry_safe ( iobuf, tmp, list, list ) { list_del ( &iobuf->list ); memcpy ( iob_put ( concatenated, iob_len ( iobuf ) ), iobuf->data, iob_len ( iobuf ) ); free_iob ( iobuf ); }
/** * Handle SRP login rejection * * @v srp SRP device * @v iobuf I/O buffer * @ret rc Return status code */ static int srp_login_rej ( struct srp_device *srp, struct io_buffer *iobuf ) { struct srp_login_rej *login_rej = iobuf->data; int rc; DBGC2 ( srp, "SRP %p RX login rejection tag %08x%08x\n", srp, ntohl ( login_rej->tag.dwords[0] ), ntohl ( login_rej->tag.dwords[1] ) ); /* Sanity check */ if ( iob_len ( iobuf ) < sizeof ( *login_rej ) ) { DBGC ( srp, "SRP %p RX login rejection too short (%zd " "bytes)\n", srp, iob_len ( iobuf ) ); rc = -EINVAL; goto out; } /* Login rejection always indicates an error */ DBGC ( srp, "SRP %p login rejected (reason %08x)\n", srp, ntohl ( login_rej->reason ) ); rc = -EPERM; out: free_iob ( iobuf ); return rc; }
/** * Handle received data * * @v downloader Downloader * @v iobuf Datagram I/O buffer * @v meta Data transfer metadata * @ret rc Return status code */ static int downloader_xfer_deliver ( struct downloader *downloader, struct io_buffer *iobuf, struct xfer_metadata *meta ) { size_t len; size_t max; int rc; /* Calculate new buffer position */ if ( meta->flags & XFER_FL_ABS_OFFSET ) downloader->pos = 0; downloader->pos += meta->offset; /* Ensure that we have enough buffer space for this data */ len = iob_len ( iobuf ); max = ( downloader->pos + len ); if ( ( rc = downloader_ensure_size ( downloader, max ) ) != 0 ) goto done; /* Copy data to buffer */ copy_to_user ( downloader->image->data, downloader->pos, iobuf->data, len ); /* Update current buffer position */ downloader->pos += len; done: free_iob ( iobuf ); if ( rc != 0 ) downloader_finished ( downloader, rc ); return rc; }
/** * Deliver datagram * * @v intf Data transfer interface * @v iobuf Datagram I/O buffer * @v meta Data transfer metadata * @ret rc Return status code */ int xfer_deliver ( struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta ) { struct interface *dest; xfer_deliver_TYPE ( void * ) *op = intf_get_dest_op ( intf, xfer_deliver, &dest ); void *object = intf_object ( dest ); int rc; DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " deliver %zd\n", INTF_INTF_DBG ( intf, dest ), iob_len ( iobuf ) ); if ( op ) { rc = op ( object, iobuf, meta ); } else { /* Default is to discard the I/O buffer */ free_iob ( iobuf ); rc = -EPIPE; } if ( rc != 0 ) { DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " deliver failed: %s\n", INTF_INTF_DBG ( intf, dest ), strerror ( rc ) ); } intf_put ( dest ); return rc; }
/** * Handle SRP login response * * @v srp SRP device * @v iobuf I/O buffer * @ret rc Return status code */ static int srp_login_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) { struct srp_login_rsp *login_rsp = iobuf->data; int rc; DBGC2 ( srp, "SRP %p RX login response tag %08x%08x\n", srp, ntohl ( login_rsp->tag.dwords[0] ), ntohl ( login_rsp->tag.dwords[1] ) ); /* Sanity check */ if ( iob_len ( iobuf ) < sizeof ( *login_rsp ) ) { DBGC ( srp, "SRP %p RX login response too short (%zd bytes)\n", srp, iob_len ( iobuf ) ); rc = -EINVAL; goto out; } DBGC ( srp, "SRP %p logged in\n", srp ); /* Mark as logged in */ srp->state |= SRP_STATE_LOGGED_IN; /* Reset error counter */ srp->retry_count = 0; /* Issue pending command */ srp_cmd ( srp ); rc = 0; out: free_iob ( iobuf ); return rc; }
/** * Close network device * * @v netdev Network device */ static void snpnet_close ( struct net_device *netdev ) { struct snp_nic *snp = netdev->priv; EFI_STATUS efirc; int rc; /* Shut down NIC */ if ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( snp, "SNP %s could not shut down: %s\n", netdev->name, strerror ( rc ) ); /* Nothing we can do about this */ } /* Discard transmit buffer, if applicable */ if ( snp->txbuf ) { netdev_tx_complete_err ( netdev, snp->txbuf, -ECANCELED ); snp->txbuf = NULL; } /* Discard receive buffer, if applicable */ if ( snp->rxbuf ) { free_iob ( snp->rxbuf ); snp->rxbuf = NULL; } }
/** * Add received data to data transfer buffer * * @v xferbuf Data transfer buffer * @v iobuf I/O buffer * @v meta Data transfer metadata * @ret rc Return status code */ int xferbuf_deliver ( struct xfer_buffer *xferbuf, struct io_buffer *iobuf, struct xfer_metadata *meta ) { size_t len = iob_len ( iobuf ); size_t pos; int rc; /* Start profiling */ profile_start ( &xferbuf_deliver_profiler ); /* Calculate new buffer position */ pos = xferbuf->pos; if ( meta->flags & XFER_FL_ABS_OFFSET ) pos = 0; pos += meta->offset; /* Write data to buffer */ if ( ( rc = xferbuf_write ( xferbuf, pos, iobuf->data, len ) ) != 0 ) goto done; /* Update current buffer position */ xferbuf->pos = ( pos + len ); done: free_iob ( iobuf ); profile_stop ( &xferbuf_deliver_profiler ); return rc; }
/** * Process received data * * @v file Data transfer file * @v iobuf I/O buffer * @v meta Data transfer metadata * @ret rc Return status code */ static int efi_download_deliver_iob ( struct efi_download_file *file, struct io_buffer *iobuf, struct xfer_metadata *meta ) { EFI_STATUS efirc; size_t len = iob_len ( iobuf ); int rc; /* Calculate new buffer position */ if ( meta->flags & XFER_FL_ABS_OFFSET ) file->pos = 0; file->pos += meta->offset; /* Call out to the data handler */ if ( ( efirc = file->data_callback ( file->context, iobuf->data, len, file->pos ) ) != 0 ) { rc = -EEFI ( efirc ); goto err_callback; } /* Update current buffer position */ file->pos += len; /* Success */ rc = 0; err_callback: free_iob ( iobuf ); return rc; }
/** * Complete bulk IN transfer * * @v ep USB endpoint * @v iobuf I/O buffer * @v rc Completion status code */ static void acm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf, int rc ) { struct acm_device *acm = container_of ( ep, struct acm_device, usbnet.in ); struct rndis_device *rndis = acm->rndis; /* Profile receive completions */ profile_start ( &acm_in_profiler ); /* Ignore packets cancelled when the endpoint closes */ if ( ! ep->open ) goto ignore; /* Record USB errors against the RNDIS device */ if ( rc != 0 ) { DBGC ( acm, "ACM %p bulk IN failed: %s\n", acm, strerror ( rc ) ); goto error; } /* Hand off to RNDIS */ rndis_rx ( rndis, iob_disown ( iobuf ) ); profile_stop ( &acm_in_profiler ); return; error: rndis_rx_err ( rndis, iob_disown ( iobuf ), rc ); ignore: free_iob ( iobuf ); }
/** * Complete bulk IN transfer * * @v ep USB endpoint * @v iobuf I/O buffer * @v rc Completion status code */ static void smsc95xx_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf, int rc ) { struct smsc95xx_device *smsc95xx = container_of ( ep, struct smsc95xx_device, usbnet.in ); struct net_device *netdev = smsc95xx->netdev; struct smsc95xx_rx_header *header; /* Profile completions */ profile_start ( &smsc95xx_in_profiler ); /* Ignore packets cancelled when the endpoint closes */ if ( ! ep->open ) { free_iob ( iobuf ); return; } /* Record USB errors against the network device */ if ( rc != 0 ) { DBGC ( smsc95xx, "SMSC95XX %p bulk IN failed: %s\n", smsc95xx, strerror ( rc ) ); goto err; } /* Sanity check */ if ( iob_len ( iobuf ) < ( sizeof ( *header ) + 4 /* CRC */ ) ) { DBGC ( smsc95xx, "SMSC95XX %p underlength bulk IN\n", smsc95xx ); DBGC_HDA ( smsc95xx, 0, iobuf->data, iob_len ( iobuf ) ); rc = -EINVAL; goto err; } /* Strip header and CRC */ header = iobuf->data; iob_pull ( iobuf, sizeof ( *header ) ); iob_unput ( iobuf, 4 /* CRC */ ); /* Check for errors */ if ( header->command & cpu_to_le32 ( SMSC95XX_RX_RUNT | SMSC95XX_RX_LATE | SMSC95XX_RX_CRC ) ) { DBGC ( smsc95xx, "SMSC95XX %p receive error (%08x):\n", smsc95xx, le32_to_cpu ( header->command ) ); DBGC_HDA ( smsc95xx, 0, iobuf->data, iob_len ( iobuf ) ); rc = -EIO; goto err; } /* Hand off to network stack */ netdev_rx ( netdev, iob_disown ( iobuf ) ); profile_stop ( &smsc95xx_in_profiler ); return; err: /* Hand off to network stack */ netdev_rx_err ( netdev, iob_disown ( iobuf ), rc ); }
/** * Handle SRP unrecognised response * * @v srp SRP device * @v iobuf I/O buffer * @ret rc Returns status code */ static int srp_unrecognised ( struct srp_device *srp, struct io_buffer *iobuf ) { struct srp_common *common = iobuf->data; DBGC ( srp, "SRP %p RX unrecognised IU tag %08x%08x type %02x\n", srp, ntohl ( common->tag.dwords[0] ), ntohl ( common->tag.dwords[1] ), common->type ); free_iob ( iobuf ); return -ENOTSUP; }
static void e1000e_free_rx_resources ( struct e1000_adapter *adapter ) { int i; DBGP ( "e1000_free_rx_resources\n" ); free_dma ( adapter->rx_base, adapter->rx_ring_size ); for ( i = 0; i < NUM_RX_DESC; i++ ) { free_iob ( adapter->rx_iobuf[i] ); } }
static void b44_free_rx_ring(struct b44_private *bp) { u32 i; if (bp->rx) { for (i = 0; i < B44_RING_SIZE; i++) { free_iob(bp->rx_iobuf[i]); bp->rx_iobuf[i] = NULL; } free_dma(bp->rx, B44_RX_RING_LEN_BYTES); bp->rx = NULL; } }
static void rtl818x_free_rx_ring(struct net80211_device *dev) { struct rtl818x_priv *priv = dev->priv; int i; for (i = 0; i < RTL818X_RX_RING_SIZE; i++) { free_iob(priv->rx_buf[i]); priv->rx_buf[i] = NULL; } free_dma(priv->rx_ring, sizeof(*priv->rx_ring) * RTL818X_RX_RING_SIZE); priv->rx_ring = NULL; }
/** * Complete bulk IN transfer * * @v ep USB endpoint * @v iobuf I/O buffer * @v rc Completion status code */ static void dm96xx_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf, int rc ) { struct dm96xx_device *dm96xx = container_of ( ep, struct dm96xx_device, usbnet.in ); struct net_device *netdev = dm96xx->netdev; struct dm96xx_rx_header *header; /* Ignore packets cancelled when the endpoint closes */ if ( ! ep->open ) { free_iob ( iobuf ); return; } /* Record USB errors against the network device */ if ( rc != 0 ) { DBGC ( dm96xx, "DM96XX %p bulk IN failed: %s\n", dm96xx, strerror ( rc ) ); goto err; } /* Sanity check */ if ( iob_len ( iobuf ) < ( sizeof ( *header ) + 4 /* CRC */ ) ) { DBGC ( dm96xx, "DM96XX %p underlength bulk IN\n", dm96xx ); DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) ); rc = -EINVAL; goto err; } /* Strip header and CRC */ header = iobuf->data; iob_pull ( iobuf, sizeof ( *header ) ); iob_unput ( iobuf, 4 /* CRC */ ); /* Check status */ if ( header->rsr & ~DM96XX_RSR_MF ) { DBGC ( dm96xx, "DM96XX %p receive error %02x:\n", dm96xx, header->rsr ); DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) ); rc = -EIO; goto err; } /* Hand off to network stack */ netdev_rx ( netdev, iob_disown ( iobuf ) ); return; err: /* Hand off to network stack */ netdev_rx_err ( netdev, iob_disown ( iobuf ), rc ); }
/** * Transmit a TCP/IP packet * * @v iobuf I/O buffer * @v tcpip_protocol Transport-layer protocol * @v st_src Source address, or NULL to use route default * @v st_dest Destination address * @v netdev Network device to use if no route found, or NULL * @v trans_csum Transport-layer checksum to complete, or NULL * @ret rc Return status code */ int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol, struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, struct net_device *netdev, uint16_t *trans_csum ) { struct tcpip_net_protocol *tcpip_net; /* Hand off packet to the appropriate network-layer protocol */ tcpip_net = tcpip_net_protocol ( st_dest->st_family ); if ( tcpip_net ) { DBG ( "TCP/IP sending %s packet\n", tcpip_net->name ); return tcpip_net->tx ( iobuf, tcpip_protocol, st_src, st_dest, netdev, trans_csum ); } free_iob ( iobuf ); return -EAFNOSUPPORT; }
/** * Handle SRP SCSI response * * @v srp SRP device * @v iobuf I/O buffer * @ret rc Returns status code */ static int srp_rsp ( struct srp_device *srp, struct io_buffer *iobuf ) { struct srp_rsp *rsp = iobuf->data; int rc; DBGC2 ( srp, "SRP %p RX SCSI response tag %08x%08x\n", srp, ntohl ( rsp->tag.dwords[0] ), ntohl ( rsp->tag.dwords[1] ) ); /* Sanity check */ if ( iob_len ( iobuf ) < sizeof ( *rsp ) ) { DBGC ( srp, "SRP %p RX SCSI response too short (%zd bytes)\n", srp, iob_len ( iobuf ) ); rc = -EINVAL; goto out; } /* Report SCSI errors */ if ( rsp->status != 0 ) { DBGC ( srp, "SRP %p response status %02x\n", srp, rsp->status ); if ( srp_rsp_sense_data ( rsp ) ) { DBGC ( srp, "SRP %p sense data:\n", srp ); DBGC_HDA ( srp, 0, srp_rsp_sense_data ( rsp ), srp_rsp_sense_data_len ( rsp ) ); } } if ( rsp->valid & ( SRP_RSP_VALID_DOUNDER | SRP_RSP_VALID_DOOVER ) ) { DBGC ( srp, "SRP %p response data-out %srun by %#x bytes\n", srp, ( ( rsp->valid & SRP_RSP_VALID_DOUNDER ) ? "under" : "over" ), ntohl ( rsp->data_out_residual_count ) ); } if ( rsp->valid & ( SRP_RSP_VALID_DIUNDER | SRP_RSP_VALID_DIOVER ) ) { DBGC ( srp, "SRP %p response data-in %srun by %#x bytes\n", srp, ( ( rsp->valid & SRP_RSP_VALID_DIUNDER ) ? "under" : "over" ), ntohl ( rsp->data_in_residual_count ) ); } srp->command->status = rsp->status; /* Mark SCSI command as complete */ srp_scsi_done ( srp, 0 ); rc = 0; out: free_iob ( iobuf ); return rc; }
/** * Receive control packet * * @v acm USB RNDIS device * @ret rc Return status code */ static int acm_control_receive ( struct acm_device *acm ) { struct rndis_device *rndis = acm->rndis; struct usb_device *usb = acm->usb; struct io_buffer *iobuf; struct rndis_header *header; size_t mtu = ACM_RESPONSE_MTU; size_t len; int rc; /* Allocate I/O buffer */ iobuf = alloc_iob ( mtu ); if ( ! iobuf ) { rc = -ENOMEM; goto err_alloc; } /* Get encapsulated response */ if ( ( rc = cdc_get_encapsulated_response ( usb, acm->usbnet.comms, iobuf->data, mtu ) ) != 0 ){ DBGC ( acm, "ACM %p could not get encapsulated response: %s\n", acm, strerror ( rc ) ); goto err_get_response; } /* Fix up buffer length */ header = iobuf->data; len = le32_to_cpu ( header->len ); if ( len > mtu ) { DBGC ( acm, "ACM %p overlength encapsulated response\n", acm ); DBGC_HDA ( acm, 0, iobuf->data, mtu ); rc = -EPROTO; goto err_len; } iob_put ( iobuf, len ); /* Hand off to RNDIS */ rndis_rx ( rndis, iob_disown ( iobuf ) ); return 0; err_len: err_get_response: free_iob ( iobuf ); err_alloc: return rc; }
static void legacy_poll ( struct net_device *netdev ) { struct nic *nic = netdev->priv; struct io_buffer *iobuf; iobuf = alloc_iob ( ETH_FRAME_LEN ); if ( ! iobuf ) return; nic->packet = iobuf->data; if ( nic->nic_op->poll ( nic, 1 ) ) { DBG ( "Received %d bytes\n", nic->packetlen ); iob_put ( iobuf, nic->packetlen ); netdev_rx ( netdev, iobuf ); } else { free_iob ( iobuf ); } }
/** * Receive PXE UDP data * * @v pxe_udp PXE UDP connection * @v iobuf I/O buffer * @v meta Data transfer metadata * @ret rc Return status code * * Receives a packet as part of the current pxenv_udp_read() * operation. */ static int pxe_udp_deliver ( struct pxe_udp_connection *pxe_udp, struct io_buffer *iobuf, struct xfer_metadata *meta ) { struct s_PXENV_UDP_READ *pxenv_udp_read = pxe_udp->pxenv_udp_read; struct sockaddr_in *sin_src; struct sockaddr_in *sin_dest; userptr_t buffer; size_t len; int rc = 0; if ( ! pxenv_udp_read ) { DBG ( "PXE discarded UDP packet\n" ); rc = -ENOBUFS; goto done; } /* Copy packet to buffer and record length */ buffer = real_to_user ( pxenv_udp_read->buffer.segment, pxenv_udp_read->buffer.offset ); len = iob_len ( iobuf ); if ( len > pxenv_udp_read->buffer_size ) len = pxenv_udp_read->buffer_size; copy_to_user ( buffer, 0, iobuf->data, len ); pxenv_udp_read->buffer_size = len; /* Fill in source/dest information */ assert ( meta ); sin_src = ( struct sockaddr_in * ) meta->src; assert ( sin_src ); assert ( sin_src->sin_family == AF_INET ); pxenv_udp_read->src_ip = sin_src->sin_addr.s_addr; pxenv_udp_read->s_port = sin_src->sin_port; sin_dest = ( struct sockaddr_in * ) meta->dest; assert ( sin_dest ); assert ( sin_dest->sin_family == AF_INET ); pxenv_udp_read->dest_ip = sin_dest->sin_addr.s_addr; pxenv_udp_read->d_port = sin_dest->sin_port; /* Mark as received */ pxe_udp->pxenv_udp_read = NULL; done: free_iob ( iobuf ); return rc; }
/** * e1000_setup_rx_resources - allocate Rx resources (Descriptors) * * @v adapter e1000 private structure * * @ret rc Returns 0 on success, negative on failure **/ static int e1000_setup_rx_resources ( struct e1000_adapter *adapter ) { int i, j; struct e1000_rx_desc *rx_curr_desc; DBG ( "e1000_setup_rx_resources\n" ); /* Allocate receive descriptor ring memory. It must not cross a 64K boundary because of hardware errata */ adapter->rx_base = malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size ); if ( ! adapter->rx_base ) { return -ENOMEM; } memset ( adapter->rx_base, 0, adapter->rx_ring_size ); for ( i = 0; i < NUM_RX_DESC; i++ ) { adapter->rx_iobuf[i] = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE ); /* If unable to allocate all iobufs, free any that * were successfully allocated, and return an error */ if ( ! adapter->rx_iobuf[i] ) { for ( j = 0; j < i; j++ ) { free_iob ( adapter->rx_iobuf[j] ); } return -ENOMEM; } rx_curr_desc = ( void * ) ( adapter->rx_base ) + ( i * sizeof ( *adapter->rx_base ) ); rx_curr_desc->buffer_addr = virt_to_bus ( adapter->rx_iobuf[i]->data ); DBG ( "i = %d rx_curr_desc->buffer_addr = %#16llx\n", i, rx_curr_desc->buffer_addr ); } return 0; }
/** * Close network device * * @v netdev Network device */ static void nii_close ( struct net_device *netdev ) { struct nii_nic *nii = netdev->priv; /* Shut down NIC */ nii_shutdown ( nii ); /* Discard transmit buffer, if applicable */ if ( nii->txbuf ) { netdev_tx_complete_err ( netdev, nii->txbuf, -ECANCELED ); nii->txbuf = NULL; } /* Discard receive buffer, if applicable */ if ( nii->rxbuf ) { free_iob ( nii->rxbuf ); nii->rxbuf = NULL; } }
/** Transmit a TCP/IP packet * * @v iobuf I/O buffer * @v tcpip_protocol Transport-layer protocol * @v st_src Source address, or NULL to use route default * @v st_dest Destination address * @v netdev Network device to use if no route found, or NULL * @v trans_csum Transport-layer checksum to complete, or NULL * @ret rc Return status code */ int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol, struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, struct net_device *netdev, uint16_t *trans_csum ) { struct tcpip_net_protocol *tcpip_net; /* Hand off packet to the appropriate network-layer protocol */ for_each_table_entry ( tcpip_net, TCPIP_NET_PROTOCOLS ) { if ( tcpip_net->sa_family == st_dest->st_family ) { DBG ( "TCP/IP sending %s packet\n", tcpip_net->name ); return tcpip_net->tx ( iobuf, tcpip_protocol, st_src, st_dest, netdev, trans_csum ); } } DBG ( "Unrecognised TCP/IP address family %d\n", st_dest->st_family ); free_iob ( iobuf ); return -EAFNOSUPPORT; }
/** Process a received TCP/IP packet * * @v iobuf I/O buffer * @v tcpip_proto Transport-layer protocol number * @v st_src Partially-filled source address * @v st_dest Partially-filled destination address * @v pshdr_csum Pseudo-header checksum * @ret rc Return status code * * This function expects a transport-layer segment from the network * layer. The network layer should fill in as much as it can of the * source and destination addresses (i.e. it should fill in the * address family and the network-layer addresses, but leave the ports * and the rest of the structures as zero). */ int tcpip_rx ( struct io_buffer *iobuf, uint8_t tcpip_proto, struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) { struct tcpip_protocol *tcpip; /* Hand off packet to the appropriate transport-layer protocol */ for_each_table_entry ( tcpip, TCPIP_PROTOCOLS ) { if ( tcpip->tcpip_proto == tcpip_proto ) { DBG ( "TCP/IP received %s packet\n", tcpip->name ); return tcpip->rx ( iobuf, st_src, st_dest, pshdr_csum ); } } DBG ( "Unrecognised TCP/IP protocol %d\n", tcpip_proto ); free_iob ( iobuf ); return -EPROTONOSUPPORT; }
/** * Process incoming marker packet * * @v iobuf I/O buffer * @v netdev Network device * @ret rc Return status code */ static int eth_slow_marker_rx ( struct io_buffer *iobuf, struct net_device *netdev ) { union eth_slow_packet *eth_slow = iobuf->data; struct eth_slow_marker *marker = ð_slow->marker; eth_slow_marker_dump ( iobuf, netdev, "RX" ); if ( marker->marker.tlv.type == ETH_SLOW_TLV_MARKER_REQUEST ) { /* Send marker response */ marker->marker.tlv.type = ETH_SLOW_TLV_MARKER_RESPONSE; eth_slow_marker_dump ( iobuf, netdev, "TX" ); return net_tx ( iobuf, netdev, ð_slow_protocol, eth_slow_address, netdev->ll_addr ); } else { /* Discard all other marker packets */ free_iob ( iobuf ); return -EINVAL; } }
/** * Complete interrupt transfer * * @v ep USB endpoint * @v iobuf I/O buffer * @v rc Completion status code */ static void smsc95xx_intr_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf, int rc ) { struct smsc95xx_device *smsc95xx = container_of ( ep, struct smsc95xx_device, usbnet.intr ); struct net_device *netdev = smsc95xx->netdev; struct smsc95xx_interrupt *intr; /* Profile completions */ profile_start ( &smsc95xx_intr_profiler ); /* Ignore packets cancelled when the endpoint closes */ if ( ! ep->open ) goto done; /* Record USB errors against the network device */ if ( rc != 0 ) { DBGC ( smsc95xx, "SMSC95XX %p interrupt failed: %s\n", smsc95xx, strerror ( rc ) ); DBGC_HDA ( smsc95xx, 0, iobuf->data, iob_len ( iobuf ) ); netdev_rx_err ( netdev, NULL, rc ); goto done; } /* Extract interrupt data */ if ( iob_len ( iobuf ) != sizeof ( *intr ) ) { DBGC ( smsc95xx, "SMSC95XX %p malformed interrupt\n", smsc95xx ); DBGC_HDA ( smsc95xx, 0, iobuf->data, iob_len ( iobuf ) ); netdev_rx_err ( netdev, NULL, rc ); goto done; } intr = iobuf->data; /* Record interrupt status */ smsc95xx->int_sts = le32_to_cpu ( intr->int_sts ); profile_stop ( &smsc95xx_intr_profiler ); done: /* Free I/O buffer */ free_iob ( iobuf ); }
/** Poll for new packets */ static void af_packet_nic_poll ( struct net_device *netdev ) { struct af_packet_nic * nic = netdev->priv; struct pollfd pfd; struct io_buffer * iobuf; int r; pfd.fd = nic->fd; pfd.events = POLLIN; if (linux_poll(&pfd, 1, 0) == -1) { DBGC(nic, "af_packet %p poll failed (%s)\n", nic, linux_strerror(linux_errno)); return; } if ((pfd.revents & POLLIN) == 0) return; /* At this point we know there is at least one new packet to be read */ iobuf = alloc_iob(RX_BUF_SIZE); if (! iobuf) goto allocfail; while ((r = linux_read(nic->fd, iobuf->data, RX_BUF_SIZE)) > 0) { DBGC2(nic, "af_packet %p read %d bytes\n", nic, r); iob_put(iobuf, r); netdev_rx(netdev, iobuf); iobuf = alloc_iob(RX_BUF_SIZE); if (! iobuf) goto allocfail; } free_iob(iobuf); return; allocfail: DBGC(nic, "af_packet %p alloc_iob failed\n", nic); }
/** * Close network device * * @v netdev Network device */ static void myson_close ( struct net_device *netdev ) { struct myson_nic *myson = netdev->priv; unsigned int i; /* Disable receiver and transmitter */ writel ( 0, myson->regs + MYSON_TCR_RCR ); /* Allow time for receiver and transmitter to become idle */ myson_wait_idle ( myson ); /* Destroy receive descriptor ring */ myson_destroy_ring ( myson, &myson->rx ); /* Discard any unused receive buffers */ for ( i = 0 ; i < MYSON_NUM_RX_DESC ; i++ ) { if ( myson->rx_iobuf[i] ) free_iob ( myson->rx_iobuf[i] ); myson->rx_iobuf[i] = NULL; } /* Destroy transmit descriptor ring */ myson_destroy_ring ( myson, &myson->tx ); }
/** * Complete interrupt transfer * * @v ep USB endpoint * @v iobuf I/O buffer * @v rc Completion status code */ static void dm96xx_intr_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf, int rc ) { struct dm96xx_device *dm96xx = container_of ( ep, struct dm96xx_device, usbnet.intr ); struct net_device *netdev = dm96xx->netdev; struct dm96xx_interrupt *intr; size_t len = iob_len ( iobuf ); /* Ignore packets cancelled when the endpoint closes */ if ( ! ep->open ) goto done; /* Record USB errors against the network device */ if ( rc != 0 ) { DBGC ( dm96xx, "DM96XX %p interrupt failed: %s\n", dm96xx, strerror ( rc ) ); DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) ); netdev_rx_err ( netdev, NULL, rc ); goto done; } /* Extract message header */ if ( len < sizeof ( *intr ) ) { DBGC ( dm96xx, "DM96XX %p underlength interrupt:\n", dm96xx ); DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) ); netdev_rx_err ( netdev, NULL, -EINVAL ); goto done; } intr = iobuf->data; /* Update link status */ dm96xx_link_nsr ( dm96xx, intr->nsr ); done: /* Free I/O buffer */ free_iob ( iobuf ); }