/* * 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; } }