mbuf_t mbuf_concatenate(mbuf_t dst, mbuf_t src) { if (dst == NULL) return (NULL); m_cat(dst, src); /* return dst as is in the current implementation */ return (dst); }
/* * Concatenate two pkthdr mbuf chains. */ void m_catpkt(struct mbuf *m, struct mbuf *n) { M_ASSERTPKTHDR(m); M_ASSERTPKTHDR(n); m->m_pkthdr.len += n->m_pkthdr.len; m_demote(n, 1, 0); m_cat(m, n); }
static int smb_t2_placedata(struct mbuf *mtop, u_int16_t offset, u_int16_t count, struct mdchain *mdp) { struct mbuf *m, *m0; int len; m0 = m_split(mtop, offset, M_WAIT); len = m_length(m0, &m); m->m_len -= len - count; if (mdp->md_top == NULL) { md_initm(mdp, m0); } else m_cat(mdp->md_top, m0); return 0; }
/* * Extract data [offset,count] from mtop and add to mdp. */ static int smb_t2_placedata(mblk_t *mtop, u_int16_t offset, u_int16_t count, struct mdchain *mdp) { mblk_t *n; n = m_copym(mtop, offset, count, M_WAITOK); if (n == NULL) return (EBADRPC); if (mdp->md_top == NULL) { md_initm(mdp, n); } else m_cat(mdp->md_top, n); return (0); }
/* * [forward_packet] called when emulation of all hops in path is complete */ static void forward_packet(struct packet *pkt) { struct mbuf *m; if (pkt->m == NULL) { /* * return remote packet home when cached */ remote_hop(pkt, pkt->cachehost); return; } if (pkt->cachehost) { /* re-mbuf-headerizing packet */ MGETHDR(m, M_DONTWAIT, MT_DATA); if (!m) { /* * pkt and pkt->m freed on return */ printf("forward_packet: unable to allocate mhdr!\n"); return; } MN_DUMP_PKT(pkt); m->m_pkthdr.rcvif = NULL; /* unknown */ m->m_nextpkt = 0; m->m_pkthdr.len = pkt->info.len; m->m_len = 0; m_cat(m, pkt->m); m = m_pullup(m, sizeof(struct ip)); pkt->m = m; } if (xcp_initialized){ /* see code in filter_ipinput */ xcp_set_xcpinfo(pkt); } Dprintf(("forward_packet: calling ip_forward\n"), MN_P_PKTS); ip_forward(pkt->m, 0, NULL); /* * we lose this mbuf, IP output owns it now */ pkt->m = NULL; pktcount[(ticks / hz) % (sizeof(pktcount) / sizeof(*pktcount))]++; }
static int smb_t2_placedata(struct mbuf *mtop, u_int16_t offset, u_int16_t count, struct mdchain *mdp) { struct mbuf *m, *m0; int len; m0 = m_split(mtop, offset, M_WAIT); if (m0 == NULL) return EBADRPC; for(len = 0, m = m0; m->m_next; m = m->m_next) len += m->m_len; len += m->m_len; m->m_len -= len - count; if (mdp->md_top == NULL) { md_initm(mdp, m0); } else m_cat(mdp->md_top, m0); return 0; }
/* * Construct and reliably send a netdump packet. May fail from a resource * shortage or extreme number of unacknowledged retransmissions. Wait for * an acknowledgement before returning. Splits packets into chunks small * enough to be sent without fragmentation (looks up the interface MTU) * * Parameters: * type netdump packet type (HERALD, FINISHED, or VMCORE) * offset vmcore data offset (bytes) * data vmcore data * datalen vmcore data size (bytes) * * Returns: * int see errno.h, 0 for success */ static int netdump_send(uint32_t type, off_t offset, unsigned char *data, uint32_t datalen) { struct netdump_msg_hdr *nd_msg_hdr; struct mbuf *m, *m2; uint64_t want_acks; uint32_t i, pktlen, sent_so_far; int retries, polls, error; want_acks = 0; rcvd_acks = 0; retries = 0; MPASS(nd_ifp != NULL); retransmit: /* Chunks can be too big to fit in packets. */ for (i = sent_so_far = 0; sent_so_far < datalen || (i == 0 && datalen == 0); i++) { pktlen = datalen - sent_so_far; /* First bound: the packet structure. */ pktlen = min(pktlen, NETDUMP_DATASIZE); /* Second bound: the interface MTU (assume no IP options). */ pktlen = min(pktlen, nd_ifp->if_mtu - sizeof(struct udpiphdr) - sizeof(struct netdump_msg_hdr)); /* * Check if it is retransmitting and this has been ACKed * already. */ if ((rcvd_acks & (1 << i)) != 0) { sent_so_far += pktlen; continue; } /* * Get and fill a header mbuf, then chain data as an extended * mbuf. */ m = m_gethdr(M_NOWAIT, MT_DATA); if (m == NULL) { printf("netdump_send: Out of mbufs\n"); return (ENOBUFS); } m->m_len = sizeof(struct netdump_msg_hdr); m->m_pkthdr.len = sizeof(struct netdump_msg_hdr); MH_ALIGN(m, sizeof(struct netdump_msg_hdr)); nd_msg_hdr = mtod(m, struct netdump_msg_hdr *); nd_msg_hdr->mh_seqno = htonl(nd_seqno + i); nd_msg_hdr->mh_type = htonl(type); nd_msg_hdr->mh_offset = htobe64(offset + sent_so_far); nd_msg_hdr->mh_len = htonl(pktlen); nd_msg_hdr->mh__pad = 0; if (pktlen != 0) { m2 = m_get(M_NOWAIT, MT_DATA); if (m2 == NULL) { m_freem(m); printf("netdump_send: Out of mbufs\n"); return (ENOBUFS); } MEXTADD(m2, data + sent_so_far, pktlen, netdump_mbuf_free, NULL, NULL, 0, EXT_DISPOSABLE); m2->m_len = pktlen; m_cat(m, m2); m->m_pkthdr.len += pktlen; } error = netdump_udp_output(m); if (error != 0) return (error); /* Note that we're waiting for this packet in the bitfield. */ want_acks |= (1 << i); sent_so_far += pktlen; } if (i >= NETDUMP_MAX_IN_FLIGHT) printf("Warning: Sent more than %d packets (%d). " "Acknowledgements will fail unless the size of " "rcvd_acks/want_acks is increased.\n", NETDUMP_MAX_IN_FLIGHT, i); /* * Wait for acks. A *real* window would speed things up considerably. */ polls = 0; while (rcvd_acks != want_acks) { if (polls++ > nd_polls) { if (retries++ > nd_retries) return (ETIMEDOUT); printf(". "); goto retransmit; } netdump_network_poll(); DELAY(500); } nd_seqno += i; return (0); }
/* * Defragment a mbuf chain, returning the shortest possible * chain of mbufs and clusters. If allocation fails and * this cannot be completed, NULL will be returned, but * the passed in chain will be unchanged. Upon success, * the original chain will be freed, and the new chain * will be returned. * * If a non-packet header is passed in, the original * mbuf (chain?) will be returned unharmed. */ struct mbuf * m_defrag(struct mbuf *m0, int how) { struct mbuf *m_new = NULL, *m_final = NULL; int progress = 0, length; MBUF_CHECKSLEEP(how); if (!(m0->m_flags & M_PKTHDR)) return (m0); m_fixhdr(m0); /* Needed sanity check */ #ifdef MBUF_STRESS_TEST if (m_defragrandomfailures) { int temp = arc4random() & 0xff; if (temp == 0xba) goto nospace; } #endif if (m0->m_pkthdr.len > MHLEN) m_final = m_getcl(how, MT_DATA, M_PKTHDR); else m_final = m_gethdr(how, MT_DATA); if (m_final == NULL) goto nospace; if (m_dup_pkthdr(m_final, m0, how) == 0) goto nospace; m_new = m_final; while (progress < m0->m_pkthdr.len) { length = m0->m_pkthdr.len - progress; if (length > MCLBYTES) length = MCLBYTES; if (m_new == NULL) { if (length > MLEN) m_new = m_getcl(how, MT_DATA, 0); else m_new = m_get(how, MT_DATA); if (m_new == NULL) goto nospace; } m_copydata(m0, progress, length, mtod(m_new, caddr_t)); progress += length; m_new->m_len = length; if (m_new != m_final) m_cat(m_final, m_new); m_new = NULL; } #ifdef MBUF_STRESS_TEST if (m0->m_next == NULL) m_defraguseless++; #endif m_freem(m0); m0 = m_final; #ifdef MBUF_STRESS_TEST m_defragpackets++; m_defragbytes += m0->m_pkthdr.len; #endif return (m0); nospace: #ifdef MBUF_STRESS_TEST m_defragfailure++; #endif if (m_final) m_freem(m_final); return (NULL); }
bool_t xdr_rpc_gss_wrap_data(struct mbuf **argsp, gss_ctx_id_t ctx, gss_qop_t qop, rpc_gss_service_t svc, u_int seq) { struct mbuf *args, *mic; OM_uint32 maj_stat, min_stat; int conf_state; u_int len; static char zpad[4]; args = *argsp; /* * Prepend the sequence number before calling gss_get_mic or gss_wrap. */ put_uint32(&args, seq); len = m_length(args, NULL); if (svc == rpc_gss_svc_integrity) { /* Checksum rpc_gss_data_t. */ maj_stat = gss_get_mic_mbuf(&min_stat, ctx, qop, args, &mic); if (maj_stat != GSS_S_COMPLETE) { rpc_gss_log_debug("gss_get_mic failed"); m_freem(args); return (FALSE); } /* * Marshal databody_integ. Note that since args is * already RPC encoded, there will be no padding. */ put_uint32(&args, len); /* * Marshal checksum. This is likely to need padding. */ len = m_length(mic, NULL); put_uint32(&mic, len); if (len != RNDUP(len)) { m_append(mic, RNDUP(len) - len, zpad); } /* * Concatenate databody_integ with checksum. */ m_cat(args, mic); } else if (svc == rpc_gss_svc_privacy) { /* Encrypt rpc_gss_data_t. */ maj_stat = gss_wrap_mbuf(&min_stat, ctx, TRUE, qop, &args, &conf_state); if (maj_stat != GSS_S_COMPLETE) { rpc_gss_log_status("gss_wrap", NULL, maj_stat, min_stat); return (FALSE); } /* * Marshal databody_priv and deal with RPC padding. */ len = m_length(args, NULL); put_uint32(&args, len); if (len != RNDUP(len)) { m_append(args, RNDUP(len) - len, zpad); } } *argsp = args; return (TRUE); }
/* * Take incoming datagram fragment and try to * reassemble it into whole datagram. If a chain for * reassembly of this datagram already exists, then it * is given as fp; otherwise have to make a chain. */ struct ip *ip_reass(struct ipasfrag *ip, struct ipq *fp) { struct mbuf *m = dtom(ip); struct ipasfrag *q; int hlen = ip->ip_hl << 2; int i, next; DEBUG_CALL("ip_reass"); DEBUG_ARG("ip = %lx", (long)ip); DEBUG_ARG("fp = %lx", (long)fp); DEBUG_ARG("m = %lx", (long)m); /* * Presence of header sizes in mbufs * would confuse code below. * Fragment m_data is concatenated. */ m->m_data += hlen; m->m_len -= hlen; /* * If first fragment to arrive, create a reassembly queue. */ if (fp == 0) { struct mbuf *t; if ((t = m_get()) == NULL) goto dropfrag; fp = mtod(t, struct ipq *); insque_32(fp, &ipq); fp->ipq_ttl = IPFRAGTTL; fp->ipq_p = ip->ip_p; fp->ipq_id = ip->ip_id; fp->ipq_next = fp->ipq_prev = (ipasfragp_32)fp; fp->ipq_src = ((struct ip *)ip)->ip_src; fp->ipq_dst = ((struct ip *)ip)->ip_dst; q = (struct ipasfrag *)fp; goto insert; } /* * Find a segment which begins after this one does. */ for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp; q = (struct ipasfrag *)q->ipf_next) if (q->ip_off > ip->ip_off) break; /* * If there is a preceding segment, it may provide some of * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us. */ if (q->ipf_prev != (ipasfragp_32)fp) { i = ((struct ipasfrag *)(q->ipf_prev))->ip_off + ((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off; if (i > 0) { if (i >= ip->ip_len) goto dropfrag; m_adj(dtom(ip), i); ip->ip_off += i; ip->ip_len -= i; } } /* * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { i = (ip->ip_off + ip->ip_len) - q->ip_off; if (i < q->ip_len) { q->ip_len -= i; q->ip_off += i; m_adj(dtom(q), i); break; } q = (struct ipasfrag *) q->ipf_next; m_freem(dtom((struct ipasfrag *) q->ipf_prev)); ip_deq((struct ipasfrag *) q->ipf_prev); } insert: /* * Stick new segment in its place; * check for complete reassembly. */ ip_enq(ip, (struct ipasfrag *) q->ipf_prev); next = 0; for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; q = (struct ipasfrag *) q->ipf_next) { if (q->ip_off != next) return (0); next += q->ip_len; } if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1) return (0); /* * Reassembly is complete; concatenate fragments. */ q = (struct ipasfrag *) fp->ipq_next; m = dtom(q); q = (struct ipasfrag *) q->ipf_next; while (q != (struct ipasfrag *)fp) { struct mbuf *t; t = dtom(q); q = (struct ipasfrag *) q->ipf_next; m_cat(m, t); } /* * Create header for new ip packet by * modifying header of first packet; * dequeue and discard fragment reassembly header. * Make header visible. */ ip = (struct ipasfrag *) fp->ipq_next; /* * If the fragments concatenated to an mbuf that's * bigger than the total size of the fragment, then and * m_ext buffer was alloced. But fp->ipq_next points to * the old buffer (in the mbuf), so we must point ip * into the new buffer. */ if (m->m_flags & M_EXT) { int delta; delta = (char *)ip - m->m_dat; ip = (struct ipasfrag *)(m->m_ext + delta); } /* DEBUG_ARG("ip = %lx", (long)ip); * ip=(struct ipasfrag *)m->m_data; */ ip->ip_len = next; ip->ipf_mff &= ~1; ((struct ip *)ip)->ip_src = fp->ipq_src; ((struct ip *)ip)->ip_dst = fp->ipq_dst; remque_32(fp); (void) m_free(dtom(fp)); m = dtom(ip); m->m_len += (ip->ip_hl << 2); m->m_data -= (ip->ip_hl << 2); return ((struct ip *)ip); dropfrag: ipstat.ips_fragdropped++; m_freem(m); return (0); }