/** * Parse a READLINK reply * * @v readlink_reply A structure where the data will be saved * @v reply The ONC RPC reply to get data from * @ret rc Return status code */ int nfs_get_readlink_reply ( struct nfs_readlink_reply *readlink_reply, struct oncrpc_reply *reply ) { if ( ! readlink_reply || ! reply ) return -EINVAL; readlink_reply->status = oncrpc_iob_get_int ( reply->data ); switch ( readlink_reply->status ) { case NFS3_OK: break; case NFS3ERR_IO: return -EIO; case NFS3ERR_ACCES: return -EACCES; case NFS3ERR_INVAL: return -EINVAL; case NFS3ERR_NOTSUPP: return -ENOTSUP; case NFS3ERR_STALE: return -ESTALE; case NFS3ERR_BADHANDLE: case NFS3ERR_SERVERFAULT: default: return -EPROTO; } if ( oncrpc_iob_get_int ( reply->data ) == 1 ) iob_pull ( reply->data, 5 * sizeof ( uint32_t ) + 8 * sizeof ( uint64_t ) ); readlink_reply->path_len = oncrpc_iob_get_int ( reply->data ); readlink_reply->path = reply->data->data; return 0; }
/** * Parse a READ reply * * @v read_reply A structure where the data will be saved * @v reply The ONC RPC reply to get data from * @ret rc Return status code */ int nfs_get_read_reply ( struct nfs_read_reply *read_reply, struct oncrpc_reply *reply ) { if ( ! read_reply || ! reply ) return -EINVAL; read_reply->status = oncrpc_iob_get_int ( reply->data ); switch ( read_reply->status ) { case NFS3_OK: break; case NFS3ERR_PERM: return -EPERM; case NFS3ERR_NOENT: return -ENOENT; case NFS3ERR_IO: return -EIO; case NFS3ERR_NXIO: return -ENXIO; case NFS3ERR_ACCES: return -EACCES; case NFS3ERR_INVAL: return -EINVAL; case NFS3ERR_STALE: return -ESTALE; case NFS3ERR_BADHANDLE: case NFS3ERR_SERVERFAULT: default: return -EPROTO; } if ( oncrpc_iob_get_int ( reply->data ) == 1 ) { iob_pull ( reply->data, 5 * sizeof ( uint32_t ) ); read_reply->filesize = oncrpc_iob_get_int64 ( reply->data ); iob_pull ( reply->data, 7 * sizeof ( uint64_t ) ); } read_reply->count = oncrpc_iob_get_int ( reply->data ); read_reply->eof = oncrpc_iob_get_int ( reply->data ); read_reply->data_len = oncrpc_iob_get_int ( reply->data ); read_reply->data = reply->data->data; if ( read_reply->count != read_reply->data_len ) return -EPROTO; return 0; }
/** * 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 ); }
/** * Extract a file handle from the beginning of an I/O buffer * * @v io_buf I/O buffer * @v fh File handle * @ret size Size of the data read */ size_t nfs_iob_get_fh ( struct io_buffer *io_buf, struct nfs_fh *fh ) { fh->size = oncrpc_iob_get_int ( io_buf ); if ( fh->size > 64 ) return sizeof ( uint32_t ); memcpy (fh->fh, io_buf->data, fh->size ); iob_pull ( io_buf, fh->size ); return fh->size + sizeof ( uint32_t ); }
static int legacy_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct nic *nic = netdev->priv; struct ethhdr *ethhdr; DBG ( "Transmitting %zd bytes\n", iob_len ( iobuf ) ); iob_pad ( iobuf, ETH_ZLEN ); ethhdr = iobuf->data; iob_pull ( iobuf, sizeof ( *ethhdr ) ); nic->nic_op->transmit ( nic, ( const char * ) ethhdr->h_dest, ntohs ( ethhdr->h_protocol ), iob_len ( iobuf ), iobuf->data ); netdev_tx_complete ( netdev, iobuf ); return 0; }
/** * 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 ); }
static size_t gdbudp_recv ( char *buf, size_t len ) { struct io_buffer *iob; struct ethhdr *ethhdr; struct arphdr *arphdr; struct iphdr *iphdr; struct udp_header *udphdr; size_t payload_len; gdbudp_ensure_netdev_open ( netdev ); for ( ; ; ) { netdev_poll ( netdev ); while ( ( iob = netdev_rx_dequeue ( netdev ) ) != NULL ) { /* Ethernet header */ if ( iob_len ( iob ) < sizeof ( *ethhdr ) ) { goto bad_packet; } ethhdr = iob->data; iob_pull ( iob, sizeof ( *ethhdr ) ); /* Handle ARP requests so the client can find our MAC */ if ( ethhdr->h_protocol == htons ( ETH_P_ARP ) ) { arphdr = iob->data; if ( iob_len ( iob ) < sizeof ( *arphdr ) + 2 * ( ETH_ALEN + sizeof ( struct in_addr ) ) || arphdr->ar_hrd != htons ( ARPHRD_ETHER ) || arphdr->ar_pro != htons ( ETH_P_IP ) || arphdr->ar_hln != ETH_ALEN || arphdr->ar_pln != sizeof ( struct in_addr ) || arphdr->ar_op != htons ( ARPOP_REQUEST ) || * ( uint32_t * ) arp_target_pa ( arphdr ) != source_addr.sin_addr.s_addr ) { goto bad_packet; } /* Generate an ARP reply */ arphdr->ar_op = htons ( ARPOP_REPLY ); memswap ( arp_sender_pa ( arphdr ), arp_target_pa ( arphdr ), sizeof ( struct in_addr ) ); memcpy ( arp_target_ha ( arphdr ), arp_sender_ha ( arphdr ), ETH_ALEN ); memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, ETH_ALEN ); /* Fix up ethernet header */ ethhdr = iob_push ( iob, sizeof ( *ethhdr ) ); memcpy ( ethhdr->h_dest, ethhdr->h_source, ETH_ALEN ); memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN ); netdev_tx ( netdev, iob ); continue; /* no need to free iob */ } if ( ethhdr->h_protocol != htons ( ETH_P_IP ) ) { goto bad_packet; } /* IP header */ if ( iob_len ( iob ) < sizeof ( *iphdr ) ) { goto bad_packet; } iphdr = iob->data; iob_pull ( iob, sizeof ( *iphdr ) ); if ( iphdr->protocol != IP_UDP || iphdr->dest.s_addr != source_addr.sin_addr.s_addr ) { goto bad_packet; } /* UDP header */ if ( iob_len ( iob ) < sizeof ( *udphdr ) ) { goto bad_packet; } udphdr = iob->data; if ( udphdr->dest != source_addr.sin_port ) { goto bad_packet; } /* Learn the remote connection details */ memcpy ( dest_eth, ethhdr->h_source, ETH_ALEN ); dest_addr.sin_addr.s_addr = iphdr->src.s_addr; dest_addr.sin_port = udphdr->src; /* Payload */ payload_len = ntohs ( udphdr->len ); if ( payload_len < sizeof ( *udphdr ) || payload_len > iob_len ( iob ) ) { goto bad_packet; } payload_len -= sizeof ( *udphdr ); iob_pull ( iob, sizeof ( *udphdr ) ); if ( payload_len > len ) { goto bad_packet; } memcpy ( buf, iob->data, payload_len ); free_iob ( iob ); return payload_len; bad_packet: free_iob ( iob ); } cpu_nap(); } }