/* Creates and returns a new dp_packet that initially contains 'headroom' bytes of * headroom followed by a copy of the 'size' bytes of data starting at * 'data'. */ struct dp_packet * dp_packet_clone_data_with_headroom(const void *data, size_t size, size_t headroom) { struct dp_packet *b = dp_packet_new_with_headroom(size, headroom); dp_packet_put(b, data, size); return b; }
/* Called on a sorted complete list of v6 fragments to reassemble them into * a single packet that can be processed, such as passing through conntrack. */ static struct dp_packet * ipf_reassemble_v6_frags(struct ipf_list *ipf_list) /* OVS_REQUIRES(ipf_lock) */ { struct ipf_frag *frag_list = ipf_list->frag_list; struct dp_packet *pkt = dp_packet_clone(frag_list[0].pkt); dp_packet_set_size(pkt, dp_packet_size(pkt) - dp_packet_l2_pad_size(pkt)); struct ovs_16aligned_ip6_hdr *l3 = dp_packet_l3(pkt); int pl = ntohs(l3->ip6_plen) - sizeof(struct ovs_16aligned_ip6_frag); int rest_len = frag_list[ipf_list->last_inuse_idx].end_data_byte - frag_list[1].start_data_byte + 1; if (pl + rest_len > IPV6_PACKET_MAX_DATA) { ipf_print_reass_packet( "Unsupported big reassembled v6 packet; v6 hdr:", l3); dp_packet_delete(pkt); return NULL; } dp_packet_prealloc_tailroom(pkt, rest_len); for (int i = 1; i <= ipf_list->last_inuse_idx; i++) { size_t add_len = frag_list[i].end_data_byte - frag_list[i].start_data_byte + 1; const char *l4 = dp_packet_l4(frag_list[i].pkt); dp_packet_put(pkt, l4, add_len); } pl += rest_len; l3 = dp_packet_l3(pkt); uint8_t nw_proto = l3->ip6_nxt; uint8_t nw_frag = 0; const void *data = l3 + 1; size_t datasize = pl; const struct ovs_16aligned_ip6_frag *frag_hdr = NULL; if (!parse_ipv6_ext_hdrs(&data, &datasize, &nw_proto, &nw_frag, &frag_hdr) || !nw_frag || !frag_hdr) { ipf_print_reass_packet("Unparsed reassembled v6 packet; v6 hdr:", l3); dp_packet_delete(pkt); return NULL; } struct ovs_16aligned_ip6_frag *fh = CONST_CAST(struct ovs_16aligned_ip6_frag *, frag_hdr); fh->ip6f_offlg = 0; l3->ip6_plen = htons(pl); l3->ip6_ctlun.ip6_un1.ip6_un1_nxt = nw_proto; dp_packet_set_l2_pad_size(pkt, 0); return pkt; }
/* Called on a sorted complete list of v4 fragments to reassemble them into * a single packet that can be processed, such as passing through conntrack. */ static struct dp_packet * ipf_reassemble_v4_frags(struct ipf_list *ipf_list) /* OVS_REQUIRES(ipf_lock) */ { struct ipf_frag *frag_list = ipf_list->frag_list; struct dp_packet *pkt = dp_packet_clone(frag_list[0].pkt); dp_packet_set_size(pkt, dp_packet_size(pkt) - dp_packet_l2_pad_size(pkt)); struct ip_header *l3 = dp_packet_l3(pkt); int len = ntohs(l3->ip_tot_len); int rest_len = frag_list[ipf_list->last_inuse_idx].end_data_byte - frag_list[1].start_data_byte + 1; if (len + rest_len > IPV4_PACKET_MAX_SIZE) { ipf_print_reass_packet( "Unsupported big reassembled v4 packet; v4 hdr:", l3); dp_packet_delete(pkt); return NULL; } dp_packet_prealloc_tailroom(pkt, rest_len); for (int i = 1; i <= ipf_list->last_inuse_idx; i++) { size_t add_len = frag_list[i].end_data_byte - frag_list[i].start_data_byte + 1; const char *l4 = dp_packet_l4(frag_list[i].pkt); dp_packet_put(pkt, l4, add_len); } len += rest_len; l3 = dp_packet_l3(pkt); ovs_be16 new_ip_frag_off = l3->ip_frag_off & ~htons(IP_MORE_FRAGMENTS); l3->ip_csum = recalc_csum16(l3->ip_csum, l3->ip_frag_off, new_ip_frag_off); l3->ip_csum = recalc_csum16(l3->ip_csum, l3->ip_tot_len, htons(len)); l3->ip_tot_len = htons(len); l3->ip_frag_off = new_ip_frag_off; dp_packet_set_l2_pad_size(pkt, 0); return pkt; }
/* Parses as many pairs of hex digits as possible (possibly separated by * spaces) from the beginning of 's', appending bytes for their values to 'b'. * Returns the first character of 's' that is not the first of a pair of hex * digits. If 'n' is nonnull, stores the number of bytes added to 'b' in * '*n'. */ char * dp_packet_put_hex(struct dp_packet *b, const char *s, size_t *n) { size_t initial_size = dp_packet_size(b); for (;;) { uint8_t byte; bool ok; s += strspn(s, " \t\r\n"); byte = hexits_value(s, 2, &ok); if (!ok) { if (n) { *n = dp_packet_size(b) - initial_size; } return CONST_CAST(char *, s); } dp_packet_put(b, &byte, 1); s += 2; } }
static void lldp_tlv_put_u32(struct dp_packet *p, uint32_t x) { ovs_be32 nx = htonl(x); dp_packet_put(p, &nx, sizeof nx); }
static void lldp_tlv_put_u16(struct dp_packet *p, uint16_t x) { ovs_be16 nx = htons(x); dp_packet_put(p, &nx, sizeof nx); }
static void lldp_tlv_put_u8(struct dp_packet *p, uint8_t x) { dp_packet_put(p, &x, sizeof x); }