/* Prefixes 'size' bytes to the head end of 'b', reallocating and copying its * data if necessary. Returns a pointer to the first byte of the data's * location in the dp_packet. The new data is left uninitialized. */ void * dp_packet_push_uninit(struct dp_packet *b, size_t size) { dp_packet_prealloc_headroom(b, size); dp_packet_set_data(b, (char*)dp_packet_data(b) - size); dp_packet_set_size(b, dp_packet_size(b) + size); return dp_packet_data(b); }
/* Appends 'size' bytes of data to the tail end of 'b', reallocating and * copying its data if necessary. Returns a pointer to the first byte of the * new data, which is left uninitialized. */ void * dp_packet_put_uninit(struct dp_packet *b, size_t size) { void *p; dp_packet_prealloc_tailroom(b, size); p = dp_packet_tail(b); dp_packet_set_size(b, dp_packet_size(b) + size); return p; }
static void dp_packet_use__(struct dp_packet *b, void *base, size_t allocated, enum dp_packet_source source) { dp_packet_set_base(b, base); dp_packet_set_data(b, base); dp_packet_set_size(b, 0); dp_packet_init__(b, allocated, source); }
/* 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; }
/* Initializes 'b' as an dp_packet whose data starts at 'data' and continues for * 'size' bytes. This is appropriate for an dp_packet that will be used to * inspect existing data, without moving it around or reallocating it, and * generally without modifying it at all. * * An dp_packet operation that requires reallocating data will assert-fail if this * function was used to initialize it. */ void dp_packet_use_const(struct dp_packet *b, const void *data, size_t size) { dp_packet_use__(b, CONST_CAST(void *, data), size, DPBUF_STACK); dp_packet_set_size(b, size); }