예제 #1
0
파일: kpi_mbuf.c 프로젝트: onlynone/xnu
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);
}
예제 #2
0
/*
 * 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);
}
예제 #3
0
파일: smb_rq.c 프로젝트: AhmadTux/freebsd
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;
}
예제 #4
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);
}
예제 #5
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))]++;
}
예제 #6
0
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;
}
예제 #7
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);
}
예제 #8
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);
}
예제 #9
0
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);
}
예제 #10
0
/*
 * 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);
}