diff --git a/apps/dhcp_bitbanger.c b/apps/dhcp_bitbanger.c index cc70172..cf722b4 100644 --- a/apps/dhcp_bitbanger.c +++ b/apps/dhcp_bitbanger.c @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #include @@ -10,7 +12,7 @@ struct ethernet_packet { uint8_t source[6]; uint16_t type; uint8_t payload[]; -} __attribute__((packed)); +} __attribute__((packed)) __attribute__((aligned(2))); struct ipv4_packet { uint8_t version_ihl; @@ -24,7 +26,7 @@ struct ipv4_packet { uint32_t source; uint32_t destination; uint8_t payload[]; -} __attribute__ ((packed)); +} __attribute__ ((packed)) __attribute__((aligned(2))); struct udp_packet { uint16_t source_port; @@ -32,7 +34,7 @@ struct udp_packet { uint16_t length; uint16_t checksum; uint8_t payload[]; -} __attribute__ ((packed)); +} __attribute__ ((packed)) __attribute__((aligned(2))); struct dhcp_packet { uint8_t op; @@ -58,7 +60,7 @@ struct dhcp_packet { uint32_t magic; uint8_t options[]; -} __attribute__ ((packed)); +} __attribute__ ((packed)) __attribute__((aligned(2))); struct dns_packet { uint16_t qid; @@ -68,7 +70,7 @@ struct dns_packet { uint16_t authorities; uint16_t additional; uint8_t data[]; -} __attribute__ ((packed)); +} __attribute__ ((packed)) __attribute__((aligned(2))); struct tcp_header { uint16_t source_port; @@ -83,7 +85,7 @@ struct tcp_header { uint16_t urgent; uint8_t payload[]; -} __attribute__((packed)); +} __attribute__((packed)) __attribute__((aligned(2))); struct tcp_check_header { uint32_t source; @@ -135,6 +137,60 @@ struct payload { uint8_t payload[32]; }; +static void eth_ntoa(const uint8_t addr[6], char * out) { + /* XX:XX:XX:XX:XX:XX */ + snprintf(out, 18, "%02x:%02x:%02x:%02x:%02x:%02x", + addr[0], addr[1], addr[2], + addr[3], addr[4], addr[5]); +} + +static void ip_ntoa(const uint32_t src_addr, char * out) { + snprintf(out, 16, "%d.%d.%d.%d", + (src_addr & 0xFF000000) >> 24, + (src_addr & 0xFF0000) >> 16, + (src_addr & 0xFF00) >> 8, + (src_addr & 0xFF)); +} + +static const char * eth_type_str(uint16_t type) { + switch(type) { + case ETHERNET_TYPE_IPV4: return "IPv4"; + case ETHERNET_TYPE_ARP: return "ARP"; + default: return "unknown"; + } +} + +static void print_ipv4_header(struct ipv4_packet * packet) { + /* get addresses, type... */ + char dest_addr[16]; + char src_addr[16]; + ip_ntoa(ntohl(packet->destination), dest_addr); + ip_ntoa(ntohl(packet->source), src_addr); + fprintf(stderr, "%s -> %s %d (%s) ", + src_addr, dest_addr, packet->protocol, + packet->protocol == IPV4_PROT_UDP ? "udp" : + packet->protocol == IPV4_PROT_TCP ? "tcp" : "?"); +} + +void print_header(const struct payload * header) { + /* Assume it's at least an Ethernet frame */ + char dest_addr[18]; + char src_addr[18]; + eth_ntoa(header->eth_header.destination, dest_addr); + eth_ntoa(header->eth_header.source, src_addr); + fprintf(stderr, "%s -> %s %d (%s) ", + src_addr, dest_addr, ntohs(header->eth_header.type), eth_type_str(ntohs(header->eth_header.type))); + switch (ntohs(header->eth_header.type)) { + case ETHERNET_TYPE_IPV4: + print_ipv4_header((void*)&header->eth_header.payload); + break; + case ETHERNET_TYPE_ARP: + //print_arp_header(&header->eth_header.payload); + break; + } + fprintf(stderr, "\n"); +} + uint16_t calculate_ipv4_checksum(struct ipv4_packet * p) { uint32_t sum = 0; uint16_t * s = (uint16_t *)p; @@ -151,14 +207,6 @@ uint16_t calculate_ipv4_checksum(struct ipv4_packet * p) { return ~(sum & 0xFFFF) & 0xFFFF; } -void ip_ntoa(uint32_t src_addr, char * out) { - sprintf(out, "%d.%d.%d.%d", - (src_addr & 0xFF000000) >> 24, - (src_addr & 0xFF0000) >> 16, - (src_addr & 0xFF00) >> 8, - (src_addr & 0xFF)); -} - uint8_t mac_addr[6]; void fill(struct payload *it, size_t payload_size) { @@ -221,12 +269,14 @@ void fill(struct payload *it, size_t payload_size) { int main(int argc, char * argv[]) { +#if 0 /* Let's make a socket. */ int sockfd = socket(AF_INET, SOCK_DGRAM, 0); - //if (sockfd < 0) { perror("socket"); return 1; } + if (sockfd < 0) { perror("socket"); return 1; } /* Bind the socket to the requested device. */ //if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, +#endif char * if_name = "enp0s4"; char if_path[100]; @@ -262,50 +312,19 @@ int main(int argc, char * argv[]) { } uint32_t yiaddr; + int stage = 1; do { char buf[8092] = {0}; - ssize_t rsize = read(netdev, &buf, 8092); - if (rsize <= 0) { - printf("bad size? %zd\n", rsize); + struct pollfd fds[1]; + fds[0].fd = netdev; + fds[0].events = POLLIN; + int ret = poll(fds,1,2000); + if (ret <= 0) { + printf("...\n"); continue; } - - struct payload * response = (void*)buf; - - if (ntohs(response->udp_header.destination_port) != 68) { - printf("not what I was expecting\n"); - continue; - } - - yiaddr = response->dhcp_header.yiaddr; - char yiaddr_ip[16]; - ip_ntoa(ntohl(yiaddr), yiaddr_ip); - - printf("Response from DHCP Discover: %s\n", yiaddr_ip); - - break; - } while (1); - - { - printf("Writing request\n"); - struct payload thething = { - .payload = {53,1,3,50,4, - (yiaddr) & 0xFF, - (yiaddr >> 8) & 0xFF, - (yiaddr >> 16) & 0xFF, - (yiaddr >> 24) & 0xFF, - 55,2,3,6,255,0} - }; - - fill(&thething, 14); - - write(netdev, &thething, sizeof(struct payload)); - } - - do { - char buf[8092] = {0}; ssize_t rsize = read(netdev, &buf, 8092); if (rsize <= 0) { @@ -315,19 +334,41 @@ int main(int argc, char * argv[]) { struct payload * response = (void*)buf; + print_header(response); + if (ntohs(response->udp_header.destination_port) != 68) { - printf("not what I was expecting\n"); continue; } - yiaddr = response->dhcp_header.yiaddr; - char yiaddr_ip[16]; - ip_ntoa(ntohl(yiaddr), yiaddr_ip); - - printf("ACK returns: %s\n", yiaddr_ip); - - break; + if (stage == 1) { + yiaddr = response->dhcp_header.yiaddr; + char yiaddr_ip[16]; + ip_ntoa(ntohl(yiaddr), yiaddr_ip); + + printf("Response from DHCP Discover: %s\n", yiaddr_ip); + struct payload thething = { + .payload = {53,1,3,50,4, + (yiaddr) & 0xFF, + (yiaddr >> 8) & 0xFF, + (yiaddr >> 16) & 0xFF, + (yiaddr >> 24) & 0xFF, + 55,2,3,6,255,0} + }; + + fill(&thething, 14); + write(netdev, &thething, sizeof(struct payload)); + + stage = 2; + } else if (stage == 2) { + yiaddr = response->dhcp_header.yiaddr; + char yiaddr_ip[16]; + ip_ntoa(ntohl(yiaddr), yiaddr_ip); + + printf("ACK returns: %s\n", yiaddr_ip); + printf("Address is configured, continuing trace mode.\n"); + + stage = 3; + } } while (1); - return 0; } diff --git a/kernel/net/e1000.c b/kernel/net/e1000.c index 413d77d..1d30826 100644 --- a/kernel/net/e1000.c +++ b/kernel/net/e1000.c @@ -45,8 +45,10 @@ struct e1000_nic { int link_status; spin_lock_t net_queue_lock; + spin_lock_t alert_lock; list_t * net_queue; list_t * rx_wait; + list_t * alert_wait; uint8_t * rx_virt[E1000_NUM_RX_DESC]; uint8_t * tx_virt[E1000_NUM_TX_DESC]; @@ -157,6 +159,19 @@ static void read_mac(struct e1000_nic * device) { } } +static void e1000_alert_waiters(struct e1000_nic * nic) { + spin_lock(nic->alert_lock); + while (nic->alert_wait->head) { + node_t * node = list_dequeue(nic->alert_wait); + process_t * p = node->value; + free(node); + spin_unlock(nic->alert_lock); + process_alert_node(p, nic->device_node); + spin_lock(nic->alert_lock); + } + spin_unlock(nic->alert_lock); +} + static void e1000_handle(struct e1000_nic * nic, uint32_t status) { if (status & ICR_LSC) { /* TODO: Change interface link status. */ @@ -194,6 +209,7 @@ static void e1000_handle(struct e1000_nic * nic, uint32_t status) { } } while (1); wakeup_queue(nic->rx_wait); + e1000_alert_waiters(nic); } } @@ -296,6 +312,22 @@ static uint64_t read_e1000(fs_node_t *node, uint64_t offset, uint64_t size, uint return 8092; } +static int check_e1000(fs_node_t *node) { + struct e1000_nic * nic = node->device; + return nic->net_queue->head ? 0 : 1; +} + +static int wait_e1000(fs_node_t *node, void * process) { + struct e1000_nic * nic = node->device; + spin_lock(nic->alert_lock); + if (!list_find(nic->alert_wait, process)) { + list_insert(nic->alert_wait, process); + } + list_insert(((process_t *)process)->node_waits, nic->device_node); + spin_unlock(nic->alert_lock); + return 0; +} + static void e1000_init(void * data) { struct e1000_nic * nic = data; uint32_t e1000_device_pci = nic->pci_device; @@ -388,6 +420,7 @@ static void e1000_init(void * data) { nic->net_queue = list_create("e1000 net queue", nic); nic->rx_wait = list_create("e1000 rx sem", nic); + nic->alert_wait = list_create("e1000 select waiters", nic); nic->irq_number = pci_get_interrupt(e1000_device_pci); @@ -419,6 +452,8 @@ static void e1000_init(void * data) { nic->device_node->ioctl = ioctl_e1000; nic->device_node->write = write_e1000; nic->device_node->read = read_e1000; + nic->device_node->selectcheck = check_e1000; + nic->device_node->selectwait = wait_e1000; nic->device_node->device = nic; char tmp[100];