static int af_packet_update_properties ( struct net_device *netdev ) { struct af_packet_nic *nic = netdev->priv; struct ifreq if_data; int ret; /* retrieve default MAC address */ int fd = linux_socket(LINUX_AF_PACKET, LINUX_SOCK_RAW, 0); if (fd < 0) { DBGC(nic, "af_packet %p cannot create raw socket (%s)\n", nic, linux_strerror(linux_errno)); return fd; } /* retrieve host's MAC address */ memset(&if_data, 0, sizeof(if_data)); strncpy(if_data.ifr_name, nic->ifname, sizeof(if_data.ifr_name)); ret = linux_ioctl(fd, LINUX_SIOCGIFHWADDR, &if_data); if (ret < 0) { DBGC(nic, "af_packet %p cannot get mac addr (%s)\n", nic, linux_strerror(linux_errno)); linux_close(fd); return ret; } linux_close(fd); /* struct sockaddr = { u16 family, u8 pad[14] (equiv. sa_data) }; */ memcpy(netdev->ll_addr, if_data.ifr_hwaddr.pad, ETH_ALEN); return 0; }
/** * Open PCI configuration space * * @v pci PCI device * @v flags Access mode flags * @v where Address within configuration space * @ret fd File handle, or negative error */ static int linux_pci_open ( struct pci_device *pci, int flags, unsigned long where ) { char filename[ 22 /* "/proc/bus/pci/xx/xx.x" + NUL */ ]; int fd; int rc; /* Construct filename */ snprintf ( filename, sizeof ( filename ), "/proc/bus/pci/%02x/%02x.%x", PCI_BUS ( pci->busdevfn ), PCI_SLOT ( pci->busdevfn ), PCI_FUNC ( pci->busdevfn ) ); /* Open file */ fd = linux_open ( filename, flags ); if ( fd < 0 ) { DBGC ( pci, "PCI could not open %s: %s\n", filename, linux_strerror ( linux_errno ) ); rc = -ELINUX ( linux_errno ); goto err_open; } /* Seek to location */ if ( linux_lseek ( fd, where, SEEK_SET ) < 0 ) { DBGC ( pci, "PCI could not seek to %s offset %#02lx: %s\n", filename, where, linux_strerror ( linux_errno ) ); rc = -ELINUX ( linux_errno ); goto err_seek; } return fd; err_seek: linux_close ( fd ); err_open: return rc; }
/** Open the linux interface */ static int af_packet_nic_open ( struct net_device * netdev ) { struct af_packet_nic * nic = netdev->priv; struct sockaddr_ll socket_address; struct ifreq if_data; int ret; nic->fd = linux_socket(LINUX_AF_PACKET, LINUX_SOCK_RAW, htons(ETH_P_ALL)); if (nic->fd < 0) { DBGC(nic, "af_packet %p socket(AF_PACKET) = %d (%s)\n", nic, nic->fd, linux_strerror(linux_errno)); return nic->fd; } /* resolve ifindex of ifname */ memset(&if_data, 0, sizeof(if_data)); strncpy(if_data.ifr_name, nic->ifname, sizeof(if_data.ifr_name)); ret = linux_ioctl(nic->fd, LINUX_SIOCGIFINDEX, &if_data); if (ret < 0) { DBGC(nic, "af_packet %p ioctl(SIOCGIFINDEX) = %d (%s)\n", nic, ret, linux_strerror(linux_errno)); linux_close(nic->fd); return ret; } nic->ifindex = if_data.ifr_ifindex; /* bind to interface */ memset(&socket_address, 0, sizeof(socket_address)); socket_address.sll_family = LINUX_AF_PACKET; socket_address.sll_ifindex = nic->ifindex; socket_address.sll_protocol = htons(ETH_P_ALL); ret = linux_bind(nic->fd, (void *) &socket_address, sizeof(socket_address)); if (ret == -1) { DBGC(nic, "af_packet %p bind() = %d (%s)\n", nic, ret, linux_strerror(linux_errno)); linux_close(nic->fd); return ret; } /* Set nonblocking mode to make af_packet_nic_poll() easier */ ret = linux_fcntl(nic->fd, F_SETFL, O_NONBLOCK); if (ret != 0) { DBGC(nic, "af_packet %p fcntl(%d, ...) = %d (%s)\n", nic, nic->fd, ret, linux_strerror(linux_errno)); linux_close(nic->fd); return ret; } return 0; }
/** Setup the terminal for our use */ static void linux_console_startup(void) { struct termios t; if (linux_tcgetattr(0, &t)) { DBG("linux_console tcgetattr failed (%s)", linux_strerror(linux_errno)); return; } saved_termios = t; /* Disable canonical mode and echo. Let readline handle that */ t.c_lflag &= ~(ECHO | ICANON); /* stop ^C from sending a signal */ t.c_cc[VINTR] = 0; if (linux_tcsetattr(0, TCSAFLUSH, &t)) DBG("linux_console tcsetattr failed (%s)", linux_strerror(linux_errno)); }
/** * Get noise sample * * @ret noise Noise sample * @ret rc Return status code */ static int linux_get_noise ( noise_sample_t *noise ) { uint8_t byte; ssize_t len; /* Read a single byte from entropy source */ len = linux_read ( entropy_fd, &byte, sizeof ( byte ) ); if ( len < 0 ) { DBGC ( &entropy_fd, "ENTROPY could not read from %s: %s\n", entropy_filename, linux_strerror ( linux_errno ) ); return len; } if ( len == 0 ) { DBGC ( &entropy_fd, "ENTROPY EOF on reading from %s: %s\n", entropy_filename, linux_strerror ( linux_errno ) ); return -EPIPE; } *noise = byte; return 0; }
/** * Enable entropy gathering * * @ret rc Return status code */ static int linux_entropy_enable ( void ) { /* Open entropy source */ entropy_fd = linux_open ( entropy_filename, O_RDONLY ); if ( entropy_fd < 0 ) { DBGC ( &entropy_fd, "ENTROPY could not open %s: %s\n", entropy_filename, linux_strerror ( linux_errno ) ); return entropy_fd; } return 0; }
static int linux_console_getchar() { char c; /* read from stdin */ if (linux_read(0, &c, 1) < 0) { DBG("linux_console read failed (%s)\n", linux_strerror(linux_errno)); return 0; } /* backspace seems to be returned as ascii del, map it here */ if (c == 0x7f) return KEY_BACKSPACE; else return c; }
static int linux_console_iskey() { struct pollfd pfd; pfd.fd = 0; pfd.events = POLLIN; /* poll for data to be read on stdin */ if (linux_poll(&pfd, 1, 0) == -1) { DBG("linux_console poll failed (%s)\n", linux_strerror(linux_errno)); return 0; } if (pfd.revents & POLLIN) return 1; else return 0; }
/** * Read from PCI configuration space * * @v pci PCI device * @v where Address within configuration space * @v value Data buffer * @v len Length to read * @ret rc Return status code */ int linux_pci_read ( struct pci_device *pci, unsigned long where, unsigned long *value, size_t len ) { uint32_t tmp = 0; int fd; int check_len; int rc; /* Return "missing device" in case of error */ *value = -1UL; /* Open configuration space */ fd = linux_pci_open ( pci, O_RDONLY, where ); if ( fd < 0 ) { rc = fd; goto err_open; } /* Read value */ check_len = linux_read ( fd, &tmp, len ); if ( check_len < 0 ) { DBGC ( pci, "PCI could not read from " PCI_FMT " %#02lx+%#zx: " "%s\n", PCI_ARGS ( pci ), where, len, linux_strerror ( linux_errno ) ); rc = -ELINUX ( linux_errno ); goto err_read; } if ( ( size_t ) check_len != len ) { DBGC ( pci, "PCI read only %#x bytes from " PCI_FMT " %#02lx+%#zx\n", check_len, PCI_ARGS ( pci ), where, len ); rc = -EIO; goto err_read; } /* Return value */ *value = le32_to_cpu ( tmp ); /* Success */ rc = 0; err_read: linux_close ( fd ); err_open: return rc; }
/** * Write to PCI configuration space * * @v pci PCI device * @v where Address within configuration space * @v value Value to write * @v len Length of value * @ret rc Return status code */ int linux_pci_write ( struct pci_device *pci, unsigned long where, unsigned long value, size_t len ) { uint32_t tmp; int fd; int check_len; int rc; /* Open configuration space */ fd = linux_pci_open ( pci, O_WRONLY, where ); if ( fd < 0 ) { rc = fd; goto err_open; } /* Prepare value for writing */ tmp = cpu_to_le32 ( value ); assert ( len <= sizeof ( tmp ) ); /* Write value */ check_len = linux_write ( fd, &tmp, len ); if ( check_len < 0 ) { DBGC ( pci, "PCI could not write to " PCI_FMT " %#02lx+%#zx: " "%s\n", PCI_ARGS ( pci ), where, len, linux_strerror ( linux_errno ) ); rc = -ELINUX ( linux_errno ); goto err_write; } if ( ( size_t ) check_len != len ) { DBGC ( pci, "PCI wrote only %#x bytes to " PCI_FMT " %#02lx+%#zx\n", check_len, PCI_ARGS ( pci ), where, len ); rc = -EIO; goto err_write; } /* Success */ rc = 0; err_write: linux_close ( fd ); err_open: return rc; }
/** 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); }
static void linux_console_putchar(int c) { /* write to stdout */ if (linux_write(1, &c, 1) != 1) DBG("linux_console write failed (%s)\n", linux_strerror(linux_errno)); }
/** Restores original terminal attributes on shutdown */ static void linux_console_shutdown(int flags __unused) { if (linux_tcsetattr(0, TCSAFLUSH, &saved_termios)) DBG("linux_console tcsetattr failed (%s)", linux_strerror(linux_errno)); }