/* Tries to decode 'oh', which should be an OpenFlow OFPT_ERROR message. * Returns an OFPERR_* constant on success, 0 on failure. * * If 'payload' is nonnull, on success '*payload' is initialized with a copy of * the error's payload (copying is required because the payload is not properly * aligned). The caller must free the payload (with ofpbuf_uninit()) when it * is no longer needed. On failure, '*payload' is cleared. */ enum ofperr ofperr_decode_msg(const struct ofp_header *oh, struct ofpbuf *payload) { const struct ofp_error_msg *oem; enum ofpraw raw; uint16_t type, code; enum ofperr error; uint32_t vendor; struct ofpbuf b; if (payload) { memset(payload, 0, sizeof *payload); } /* Pull off the error message. */ ofpbuf_use_const(&b, oh, ntohs(oh->length)); error = ofpraw_pull(&raw, &b); if (error) { return 0; } oem = ofpbuf_pull(&b, sizeof *oem); /* Get the error type and code. */ vendor = 0; type = ntohs(oem->type); code = ntohs(oem->code); if (type == NXET_VENDOR && code == NXVC_VENDOR_ERROR) { const struct nx_vendor_error *nve = ofpbuf_try_pull(&b, sizeof *nve); if (!nve) { return 0; } vendor = ntohl(nve->vendor); type = ntohs(nve->type); code = ntohs(nve->code); } else if (type == OFPET12_EXPERIMENTER) { const ovs_be32 *vendorp = ofpbuf_try_pull(&b, sizeof *vendorp); if (!vendorp) { return 0; } vendor = ntohl(*vendorp); type = code; code = 0; } /* Translate the error type and code into an ofperr. */ error = ofperr_decode(oh->version, vendor, type, code); if (error && payload) { ofpbuf_init(payload, b.size); ofpbuf_push(payload, b.data, b.size); } return error; }
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (size < sizeof(struct ofp_header)) { return 0; } static bool isInit = false; if (!isInit) { vlog_set_verbosity("off"); isInit = true; } struct ofpbuf b; ofpbuf_use_const(&b, data, size); for (;;) { /* Check if ofpbuf contains ofp header. */ struct ofp_header *oh = ofpbuf_at(&b, 0, sizeof *oh); if (!oh) { break; } /* Check if length is geq than lower bound. */ size_t length = ntohs(oh->length); if (length < sizeof *oh) { break; } /* Check if ofpbuf contains payload. */ size_t tail_len = length - sizeof *oh; void *tail = ofpbuf_at(&b, sizeof *oh, tail_len); if (!tail) { break; } ofp_print(stdout, ofpbuf_pull(&b, length), length, NULL, NULL, 2); } ofpbuf_uninit(&b); return 0; }
/* Initializes l3 and higher 'flow' members from 'packet' * * This should be called by or after flow_extract() * * Initializes 'packet' header pointers as follows: * * - packet->l4 to just past the IPv4 header, if one is present and has a * correct length, and otherwise NULL. * * - packet->l7 to just past the TCP or UDP or ICMP header, if one is * present and has a correct length, and otherwise NULL. */ void flow_extract_l3_onwards(struct ofpbuf *packet, struct flow *flow, ovs_be16 dl_type) { struct ofpbuf b; ofpbuf_use_const(&b, packet->l3, packet->size - (size_t)((char *)packet->l3 - (char *)packet->l2)); /* Network layer. */ if (dl_type == htons(ETH_TYPE_IP)) { const struct ip_header *nh = pull_ip(&b); if (nh) { packet->l4 = b.data; flow->nw_src = get_unaligned_be32(&nh->ip_src); flow->nw_dst = get_unaligned_be32(&nh->ip_dst); flow->nw_proto = nh->ip_proto; flow->nw_tos = nh->ip_tos; if (IP_IS_FRAGMENT(nh->ip_frag_off)) { flow->nw_frag = FLOW_NW_FRAG_ANY; if (nh->ip_frag_off & htons(IP_FRAG_OFF_MASK)) { flow->nw_frag |= FLOW_NW_FRAG_LATER; } } flow->nw_ttl = nh->ip_ttl; if (!(nh->ip_frag_off & htons(IP_FRAG_OFF_MASK))) { if (flow->nw_proto == IPPROTO_TCP) { parse_tcp(packet, &b, flow); } else if (flow->nw_proto == IPPROTO_UDP) { parse_udp(packet, &b, flow); } else if (flow->nw_proto == IPPROTO_ICMP) { const struct icmp_header *icmp = pull_icmp(&b); if (icmp) { flow->tp_src = htons(icmp->icmp_type); flow->tp_dst = htons(icmp->icmp_code); packet->l7 = b.data; } } } } } else if (dl_type == htons(ETH_TYPE_IPV6)) { if (parse_ipv6(&b, flow)) { return; } packet->l4 = b.data; if (flow->nw_proto == IPPROTO_TCP) { parse_tcp(packet, &b, flow); } else if (flow->nw_proto == IPPROTO_UDP) { parse_udp(packet, &b, flow); } else if (flow->nw_proto == IPPROTO_ICMPV6) { if (parse_icmpv6(&b, flow)) { packet->l7 = b.data; } } } else if (dl_type == htons(ETH_TYPE_ARP) || dl_type == htons(ETH_TYPE_RARP)) { const struct arp_eth_header *arp = pull_arp(&b); if (arp && arp->ar_hrd == htons(1) && arp->ar_pro == htons(ETH_TYPE_IP) && arp->ar_hln == ETH_ADDR_LEN && arp->ar_pln == 4) { /* We only match on the lower 8 bits of the opcode. */ if (ntohs(arp->ar_op) <= 0xff) { flow->nw_proto = ntohs(arp->ar_op); } flow->nw_src = arp->ar_spa; flow->nw_dst = arp->ar_tpa; memcpy(flow->arp_sha, arp->ar_sha, ETH_ADDR_LEN); memcpy(flow->arp_tha, arp->ar_tha, ETH_ADDR_LEN); } } }