static void nc_handler(void *ctx, char *pkt, unsigned len) { struct nc_priv *priv = g_priv; unsigned char *packet = net_eth_to_udp_payload(pkt); kfifo_put(priv->fifo, packet, net_eth_to_udplen(pkt)); }
static void nfs_handler(void *ctx, char *packet, unsigned len) { char *pkt = net_eth_to_udp_payload(packet); nfs_state = STATE_DONE; nfs_packet = pkt; nfs_len = len; }
/* * Handle DHCP received packets. */ static void dhcp_handler(void *ctx, char *packet, unsigned int len) { char *pkt = net_eth_to_udp_payload(packet); struct udphdr *udp = net_eth_to_udphdr(packet); struct bootp *bp = (struct bootp *)pkt; len = net_eth_to_udplen(packet); debug("DHCPHandler: got packet: (len=%d) state: %d\n", len, dhcp_state); if (bootp_check_packet(pkt, ntohs(udp->uh_sport), len)) /* Filter out pkts we don't want */ return; switch (dhcp_state) { case SELECTING: /* * Wait an appropriate time for any potential DHCPOFFER packets * to arrive. Then select one, and generate DHCPREQUEST response. * If filename is in format we recognize, assume it is a valid * OFFER from a server we want. */ debug ("%s: state SELECTING, bp_file: \"%s\"\n", __func__, bp->bp_file); dhcp_state = REQUESTING; if (net_read_uint32((uint32_t *)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC)) dhcp_options_process((u8 *)&bp->bp_vend[4], bp); bootp_copy_net_params(bp); /* Store net params from reply */ dhcp_start = get_time_ns(); dhcp_send_request_packet(bp); break; case REQUESTING: debug ("%s: State REQUESTING\n", __func__); if (dhcp_message_type((u8 *)bp->bp_vend) == DHCP_ACK ) { if (net_read_uint32((uint32_t *)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC)) dhcp_options_process((u8 *)&bp->bp_vend[4], bp); bootp_copy_net_params(bp); /* Store net params from reply */ dhcp_state = BOUND; puts ("DHCP client bound to address "); print_IPaddr(net_get_ip()); putchar('\n'); return; } break; default: debug("%s: INVALID STATE\n", __func__); break; } }
static void tftp_handler(void *ctx, char *packet, unsigned len) { struct file_priv *priv = ctx; uint16_t proto; uint16_t *s; char *pkt = net_eth_to_udp_payload(packet); struct udphdr *udp = net_eth_to_udphdr(packet); len = net_eth_to_udplen(packet); if (len < 2) return; len -= 2; s = (uint16_t *)pkt; proto = *s++; pkt = (unsigned char *)s; debug("%s: proto 0x%04x\n", __func__, proto); switch (ntohs(proto)) { case TFTP_RRQ: case TFTP_WRQ: default: break; case TFTP_ACK: if (!priv->push) break; priv->block = ntohs(*(uint16_t *)pkt); if (priv->block != priv->last_block) { debug("ack %d != %d\n", priv->block, priv->last_block); break; } priv->block++; tftp_timer_reset(priv); if (priv->state == STATE_LAST) { priv->state = STATE_DONE; break; } priv->tftp_con->udp->uh_dport = udp->uh_sport; priv->state = STATE_WDATA; break; case TFTP_OACK: tftp_parse_oack(priv, pkt, len); priv->server_port = ntohs(udp->uh_sport); priv->tftp_con->udp->uh_dport = udp->uh_sport; if (priv->push) { /* send first block */ priv->state = STATE_WDATA; priv->block = 1; } else { /* send ACK */ priv->state = STATE_OACK; priv->block = 0; tftp_send(priv); } break; case TFTP_DATA: if (len < 2) return; len -= 2; priv->block = ntohs(*(uint16_t *)pkt); if (priv->state == STATE_RRQ || priv->state == STATE_OACK) { /* first block received */ priv->state = STATE_RDATA; priv->tftp_con->udp->uh_dport = udp->uh_sport; priv->server_port = ntohs(udp->uh_sport); priv->last_block = 0; if (priv->block != 1) { /* Assertion */ printf("error: First block is not block 1 (%d)\n", priv->block); priv->err = -EINVAL; priv->state = STATE_DONE; break; } } if (priv->block == priv->last_block) /* Same block again; ignore it. */ break; priv->last_block = priv->block; tftp_timer_reset(priv); kfifo_put(priv->fifo, pkt + 2, len); if (len < priv->blocksize) { tftp_send(priv); priv->err = 0; priv->state = STATE_DONE; } break; case TFTP_ERROR: debug("\nTFTP error: '%s' (%d)\n", pkt + 2, ntohs(*(uint16_t *)pkt)); switch (ntohs(*(uint16_t *)pkt)) { case 1: priv->err = -ENOENT; break; case 2: priv->err = -EACCES; break; default: priv->err = -EINVAL; break; } priv->state = STATE_DONE; break; } }
static void dns_handler(void *ctx, char *packet, unsigned len) { struct header *header; unsigned char *p, *e, *s; u16 type; int found, stop, dlen; short tmp; debug("%s\n", __func__); /* We sent 1 query. We want to see more that 1 answer. */ header = (struct header *)net_eth_to_udp_payload(packet);; if (ntohs(header->nqueries) != 1) return; /* Received 0 answers */ if (header->nanswers == 0) { dns_state = STATE_DONE; debug("DNS server returned no answers\n"); return; } /* Skip host name */ s = &header->data[0]; e = packet + len; for (p = s; p < e && *p != '\0'; p++) continue; /* We sent query class 1, query type 1 */ tmp = p[1] | (p[2] << 8); if (&p[5] > e || ntohs(tmp) != DNS_A_RECORD) { debug("DNS response was not A record\n"); return; } /* Go to the first answer section */ p += 5; /* Loop through the answers, we want A type answer */ for (found = stop = 0; !stop && &p[12] < e; ) { /* Skip possible name in CNAME answer */ if (*p != 0xc0) { while (*p && &p[12] < e) p++; p--; } debug("Name (Offset in header): %d\n", p[1]); tmp = p[2] | (p[3] << 8); type = ntohs(tmp); debug("type = %d\n", type); if (type == DNS_CNAME_RECORD) { /* CNAME answer. shift to the next section */ debug("Found canonical name\n"); tmp = p[10] | (p[11] << 8); dlen = ntohs(tmp); debug("dlen = %d\n", dlen); p += 12 + dlen; } else if (type == DNS_A_RECORD) { debug("Found A-record\n"); found = stop = 1; } else { debug("Unknown type\n"); stop = 1; } } if (found && &p[12] < e) { tmp = p[10] | (p[11] << 8); dlen = ntohs(tmp); p += 12; dns_ip = net_read_ip(p); dns_state = STATE_DONE; } }
static void dns_handler(void *ctx, char *packet, unsigned len) { (void)ctx; dns_recv((struct header *)net_eth_to_udp_payload(packet), net_eth_to_udplen(packet)); }
static void nfs_handler(void *ctx, char *packet, unsigned len) { char *pkt = net_eth_to_udp_payload(packet); int ret; debug("%s\n", __func__); switch (nfs_state) { case STATE_PRCLOOKUP_PROG_MOUNT_REQ: ret = rpc_lookup_reply(PROG_MOUNT, pkt, len); if (ret) goto err_out; nfs_state = STATE_PRCLOOKUP_PROG_NFS_REQ; break; case STATE_PRCLOOKUP_PROG_NFS_REQ: ret = rpc_lookup_reply(PROG_NFS, pkt, len); if (ret) goto err_out; nfs_state = STATE_MOUNT_REQ; break; case STATE_MOUNT_REQ: ret = nfs_mount_reply(pkt, len); if (ret) goto err_out; nfs_state = STATE_LOOKUP_REQ; break; case STATE_UMOUNT_REQ: ret = nfs_umountall_reply(pkt, len); if (ret) nfs_err = ret; nfs_state = STATE_DONE; return; case STATE_LOOKUP_REQ: ret = nfs_lookup_reply(pkt, len); if (ret) goto err_umount; nfs_state = STATE_READ_REQ; nfs_offset = 0; break; case STATE_READLINK_REQ: ret = nfs_readlink_reply(pkt, len); if (ret) goto err_umount; debug("Symlink --> %s\n", nfs_path); nfs_filename = basename(nfs_path); nfs_path = dirname(nfs_path); nfs_state = STATE_MOUNT_REQ; break; case STATE_READ_REQ: ret = nfs_read_reply(pkt, len); nfs_timer_start = get_time_ns(); if (ret > 0) nfs_offset += ret; else if (ret == -EISDIR || ret == -EINVAL) /* symbolic link */ nfs_state = STATE_READLINK_REQ; else goto err_umount; show_progress(nfs_offset); break; } nfs_send(); return; err_umount: nfs_state = STATE_UMOUNT_REQ; nfs_err = ret; nfs_send(); return; err_out: nfs_state = STATE_DONE; nfs_err = ret; }