* Partition an mbuf chain in two pieces, returning the tail -- * all but the first len0 bytes. In case of failure, it returns NULL and * attempts to restore the chain to its original state. * * Note that the resulting mbufs might be read-only, because the new * mbuf can end up sharing an mbuf cluster with the original mbuf if * the "breaking point" happens to lie within a cluster mbuf. Use
| 974 | * M_WRITABLE() macro to check for this case. |
| 975 | */ |
| 976 | struct mbuf * |
| 977 | m_split(struct mbuf *m0, int len0, int wait) |
| 978 | { |
| 979 | struct mbuf *m, *n; |
| 980 | u_int len = len0, remain; |
| 981 | |
| 982 | MBUF_CHECKSLEEP(wait); |
| 983 | for (m = m0; m && len > m->m_len; m = m->m_next) |
| 984 | len -= m->m_len; |
| 985 | if (m == NULL) |
| 986 | return (NULL); |
| 987 | remain = m->m_len - len; |
| 988 | if (m0->m_flags & M_PKTHDR && remain == 0) { |
| 989 | n = m_gethdr(wait, m0->m_type); |
| 990 | if (n == NULL) |
| 991 | return (NULL); |
| 992 | n->m_next = m->m_next; |
| 993 | m->m_next = NULL; |
| 994 | if (m0->m_pkthdr.csum_flags & CSUM_SND_TAG) { |
| 995 | n->m_pkthdr.snd_tag = |
| 996 | m_snd_tag_ref(m0->m_pkthdr.snd_tag); |
| 997 | n->m_pkthdr.csum_flags |= CSUM_SND_TAG; |
| 998 | } else |
| 999 | n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; |
| 1000 | n->m_pkthdr.len = m0->m_pkthdr.len - len0; |
| 1001 | m0->m_pkthdr.len = len0; |
| 1002 | return (n); |
| 1003 | } else if (m0->m_flags & M_PKTHDR) { |
| 1004 | n = m_gethdr(wait, m0->m_type); |
| 1005 | if (n == NULL) |
| 1006 | return (NULL); |
| 1007 | if (m0->m_pkthdr.csum_flags & CSUM_SND_TAG) { |
| 1008 | n->m_pkthdr.snd_tag = |
| 1009 | m_snd_tag_ref(m0->m_pkthdr.snd_tag); |
| 1010 | n->m_pkthdr.csum_flags |= CSUM_SND_TAG; |
| 1011 | } else |
| 1012 | n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; |
| 1013 | n->m_pkthdr.len = m0->m_pkthdr.len - len0; |
| 1014 | m0->m_pkthdr.len = len0; |
| 1015 | if (m->m_flags & (M_EXT|M_EXTPG)) |
| 1016 | goto extpacket; |
| 1017 | if (remain > MHLEN) { |
| 1018 | /* m can't be the lead packet */ |
| 1019 | M_ALIGN(n, 0); |
| 1020 | n->m_next = m_split(m, len, wait); |
| 1021 | if (n->m_next == NULL) { |
| 1022 | (void) m_free(n); |
| 1023 | return (NULL); |
| 1024 | } else { |
| 1025 | n->m_len = 0; |
| 1026 | return (n); |
| 1027 | } |
| 1028 | } else |
| 1029 | M_ALIGN(n, remain); |
| 1030 | } else if (remain == 0) { |
| 1031 | n = m->m_next; |
| 1032 | m->m_next = NULL; |
| 1033 | return (n); |
no test coverage detected