/* * Insert IP options into preformed packet. Adjust IP destination as * required for IP source routing, as indicated by a non-zero in_addr at the * start of the options. * * XXX This routine assumes that the packet has no options in place. */ struct mbuf * ip_insertoptions(struct mbuf *m, struct mbuf *opt, int *phlen) { struct ipoption *p = mtod(opt, struct ipoption *); struct mbuf *n; struct ip *ip = mtod(m, struct ip *); unsigned optlen; optlen = opt->m_len - sizeof(p->ipopt_dst); if (optlen + ntohs(ip->ip_len) > IP_MAXPACKET) { *phlen = 0; return (m); /* XXX should fail */ } if (p->ipopt_dst.s_addr) ip->ip_dst = p->ipopt_dst; if (!M_WRITABLE(m) || M_LEADINGSPACE(m) < optlen) { n = m_gethdr(M_NOWAIT, MT_DATA); if (n == NULL) { *phlen = 0; return (m); } m_move_pkthdr(n, m); n->m_pkthdr.rcvif = NULL; n->m_pkthdr.len += optlen; m->m_len -= sizeof(struct ip); m->m_data += sizeof(struct ip); n->m_next = m; m = n; m->m_len = optlen + sizeof(struct ip); m->m_data += max_linkhdr; bcopy(ip, mtod(m, void *), sizeof(struct ip)); } else {
/* * Defragment an mbuf chain, returning at most maxfrags separate * mbufs+clusters. If this is not possible NULL is returned and * the original mbuf chain is left in it's present (potentially * modified) state. We use two techniques: collapsing consecutive * mbufs and replacing consecutive mbufs by a cluster. * * NB: this should really be named m_defrag but that name is taken */ struct mbuf * m_collapse(struct mbuf *m0, int how, int maxfrags) { struct mbuf *m, *n, *n2, **prev; u_int curfrags; /* * Calculate the current number of frags. */ curfrags = 0; for (m = m0; m != NULL; m = m->m_next) curfrags++; /* * First, try to collapse mbufs. Note that we always collapse * towards the front so we don't need to deal with moving the * pkthdr. This may be suboptimal if the first mbuf has much * less data than the following. */ m = m0; again: for (;;) { n = m->m_next; if (n == NULL) break; if (M_WRITABLE(m) && n->m_len < M_TRAILINGSPACE(m)) { bcopy(mtod(n, void *), mtod(m, char *) + m->m_len, n->m_len); m->m_len += n->m_len; m->m_next = n->m_next; m_free(n); if (--curfrags <= maxfrags) return m0; } else
/* * Append the data in mbuf chain (m) into the socket buffer sb following mbuf * (n). If (n) is NULL, the buffer is presumed empty. * * When the data is compressed, mbufs in the chain may be handled in one of * three ways: * * (1) The mbuf may simply be dropped, if it contributes nothing (no data, no * record boundary, and no change in data type). * * (2) The mbuf may be coalesced -- i.e., data in the mbuf may be copied into * an mbuf already in the socket buffer. This can occur if an * appropriate mbuf exists, there is room, and no merging of data types * will occur. * * (3) The mbuf may be appended to the end of the existing mbuf chain. * * If any of the new mbufs is marked as M_EOR, mark the last mbuf appended as * end-of-record. */ void sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n) { int eor = 0; struct mbuf *o; SOCKBUF_LOCK_ASSERT(sb); while (m) { eor |= m->m_flags & M_EOR; if (m->m_len == 0 && (eor == 0 || (((o = m->m_next) || (o = n)) && o->m_type == m->m_type))) { if (sb->sb_lastrecord == m) sb->sb_lastrecord = m->m_next; m = m_free(m); continue; } if (n && (n->m_flags & M_EOR) == 0 && M_WRITABLE(n) && ((sb->sb_flags & SB_NOCOALESCE) == 0) && m->m_len <= M_TRAILINGSPACE(n) && n->m_type == m->m_type) { if (n->m_flags & M_HOLE) { n->m_len += m->m_len; sb->sb_cc += m->m_len; m = m_free(m); continue; } else if (m->m_len <= MCLBYTES / 4) { /* XXX: Don't copy too much */ bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len, (unsigned)m->m_len); n->m_len += m->m_len; sb->sb_cc += m->m_len; if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA) /* XXX: Probably don't need.*/ sb->sb_ctl += m->m_len; m = m_free(m); continue; } } if (n) n->m_next = m; else sb->sb_mb = m; sb->sb_mbtail = m; sballoc(sb, m); n = m; m->m_flags &= ~M_EOR; m = m->m_next; n->m_next = 0; } if (eor) { KASSERT(n != NULL, ("sbcompress: eor && n == NULL")); n->m_flags |= eor; } SBLASTMBUFCHK(sb); }
m_megapullup(PNATState pData, struct mbuf *m, int len) #endif { struct mbuf *mcl; if (len > m->m_pkthdr.len) goto bad; /* Do not reallocate packet if it is sequentional, * writable and has some extra space for expansion. * XXX: Constant 100bytes is completely empirical. */ #define RESERVE 100 if (m->m_next == NULL && M_WRITABLE(m) && M_TRAILINGSPACE(m) >= RESERVE) return (m); if (len <= MCLBYTES - RESERVE) { #ifndef VBOX mcl = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); #else mcl = m_getcl(pData, M_DONTWAIT, MT_DATA, M_PKTHDR); #endif } else if (len < MJUM16BYTES) { int size; if (len <= MJUMPAGESIZE - RESERVE) { size = MJUMPAGESIZE; } else if (len <= MJUM9BYTES - RESERVE) { size = MJUM9BYTES; } else { size = MJUM16BYTES; }; #ifndef VBOX mcl = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, size); #else mcl = m_getjcl(pData, M_DONTWAIT, MT_DATA, M_PKTHDR, size); #endif } else { goto bad; } if (mcl == NULL) goto bad; m_move_pkthdr(mcl, m); m_copydata(m, 0, len, mtod(mcl, caddr_t)); mcl->m_len = mcl->m_pkthdr.len = len; #ifndef VBOX m_freem(m); #else m_freem(pData, m); #endif return (mcl); bad: #ifndef VBOX m_freem(m); #else m_freem(pData, m); #endif return (NULL); }
static int nicvf_if_transmit(struct ifnet *ifp, struct mbuf *mbuf) { struct nicvf *nic = if_getsoftc(ifp); struct queue_set *qs = nic->qs; struct snd_queue *sq; struct mbuf *mtmp; int qidx; int err = 0; if (__predict_false(qs == NULL)) { panic("%s: missing queue set for %s", __func__, device_get_nameunit(nic->dev)); } /* Select queue */ if (M_HASHTYPE_GET(mbuf) != M_HASHTYPE_NONE) qidx = mbuf->m_pkthdr.flowid % qs->sq_cnt; else qidx = curcpu % qs->sq_cnt; sq = &qs->sq[qidx]; if (mbuf->m_next != NULL && (mbuf->m_pkthdr.csum_flags & (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_SCTP)) != 0) { if (M_WRITABLE(mbuf) == 0) { mtmp = m_dup(mbuf, M_NOWAIT); m_freem(mbuf); if (mtmp == NULL) return (ENOBUFS); mbuf = mtmp; } } err = drbr_enqueue(ifp, sq->br, mbuf); if (((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) || !nic->link_up || (err != 0)) { /* * Try to enqueue packet to the ring buffer. * If the driver is not active, link down or enqueue operation * failed, return with the appropriate error code. */ return (err); } if (NICVF_TX_TRYLOCK(sq) != 0) { err = nicvf_xmit_locked(sq); NICVF_TX_UNLOCK(sq); return (err); } else taskqueue_enqueue(sq->snd_taskq, &sq->snd_task); return (0); }
/* * Concatenate mbuf chain n to m. * Both chains must be of the same type (e.g. MT_DATA). * Any m_pkthdr is not updated. */ void m_cat(struct mbuf *m, struct mbuf *n) { while (m->m_next) m = m->m_next; while (n) { if (!M_WRITABLE(m) || M_TRAILINGSPACE(m) < n->m_len) { /* just join the two chains */ m->m_next = n; return; } /* splat the data from one into the other */ bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, (u_int)n->m_len); m->m_len += n->m_len; n = m_free(n); } }
/* * m_megapullup() - this function is a big hack. * Thankfully, it's only used in ng_nat and ipfw+nat. * * It allocates an mbuf with cluster and copies the specified part of the chain * into cluster, so that it is all contiguous and can be accessed via a plain * (char *) pointer. This is required, because libalias doesn't know how to * handle mbuf chains. * * On success, m_megapullup returns an mbuf (possibly with cluster) containing * the input packet, on failure NULL. The input packet is always consumed. */ struct mbuf * m_megapullup(struct mbuf *m, int len) { struct mbuf *mcl; if (len > m->m_pkthdr.len) goto bad; if (m->m_next == NULL && M_WRITABLE(m)) return (m); mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR); if (mcl == NULL) goto bad; m_align(mcl, len); m_move_pkthdr(mcl, m); m_copydata(m, 0, len, mtod(mcl, caddr_t)); mcl->m_len = mcl->m_pkthdr.len = len; m_freem(m); return (mcl); bad: m_freem(m); return (NULL); }
/* * Compress mbuf chain m into the socket buffer sb following mbuf tailm. * If tailm is null, the buffer is presumed empty. Also, as a side-effect, * increment the sockbuf counts for each mbuf in the chain. */ void sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *tailm) { int eor = 0; struct mbuf *free_chain = NULL; mbuftrackid(m, 23); sbcheck(sb); while (m) { struct mbuf *o; eor |= m->m_flags & M_EOR; /* * Disregard empty mbufs as long as we don't encounter * an end-of-record or there is a trailing mbuf of * the same type to propagate the EOR flag to. * * Defer the m_free() call because it can block and break * the atomicy of the sockbuf. */ if (m->m_len == 0 && (eor == 0 || (((o = m->m_next) || (o = tailm)) && o->m_type == m->m_type))) { o = m->m_next; m->m_next = free_chain; free_chain = m; m = o; continue; } /* See if we can coalesce with preceding mbuf. */ if (tailm && !(tailm->m_flags & M_EOR) && M_WRITABLE(tailm) && m->m_len <= MCLBYTES / 4 && /* XXX: Don't copy too much */ m->m_len <= M_TRAILINGSPACE(tailm) && tailm->m_type == m->m_type) { u_long mbcnt_sz; bcopy(mtod(m, caddr_t), mtod(tailm, caddr_t) + tailm->m_len, (unsigned)m->m_len); tailm->m_len += m->m_len; sb->sb_cc += m->m_len; /* update sb counter */ /* * Fix the wrongly updated mbcnt_prealloc */ mbcnt_sz = MSIZE; if (m->m_flags & M_EXT) mbcnt_sz += m->m_ext.ext_size; atomic_subtract_long(&sb->sb_mbcnt_prealloc, mbcnt_sz); o = m->m_next; m->m_next = free_chain; free_chain = m; m = o; continue; } /* Insert whole mbuf. */ if (tailm == NULL) { KASSERT(sb->sb_mb == NULL, ("sbcompress: sb_mb not NULL")); sb->sb_mb = m; /* only mbuf in sockbuf */ sb->sb_lastrecord = m; /* new last record */ } else { tailm->m_next = m; /* tack m on following tailm */ } sb->sb_lastmbuf = m; /* update last mbuf hint */ tailm = m; /* just inserted mbuf becomes the new tail */ m = m->m_next; /* advance to next mbuf */ tailm->m_next = NULL; /* split inserted mbuf off from chain */ /* update sb counters for just added mbuf */ sballoc(sb, tailm); /* clear EOR on intermediate mbufs */ tailm->m_flags &= ~M_EOR; } /* * Propogate EOR to the last mbuf */ if (eor) { if (tailm) tailm->m_flags |= eor; else kprintf("semi-panic: sbcompress"); } /* * Clean up any defered frees. */ while (free_chain) free_chain = m_free(free_chain); sbcheck(sb); }