+/*
+ * Create and return an m_tag, either by re-using space in a previous tag
+ * or by allocating a new mbuf/cluster
+ */
+struct m_tag *
+m_tag_create(u_int32_t id, u_int16_t type, int len, int wait, struct mbuf *buf)
+{
+ struct m_tag *t = NULL;
+ struct m_tag *p;
+
+ if (len < 0)
+ return (NULL);
+
+ if (len + sizeof (struct m_tag) + sizeof (struct m_taghdr) > MLEN)
+ return (m_tag_alloc(id, type, len, wait));
+
+ /*
+ * We've exhausted all external cases. Now, go through the m_tag
+ * chain and see if we can fit it in any of them.
+ * If not (t == NULL), call m_tag_alloc to store it in a new mbuf.
+ */
+ p = SLIST_FIRST(&buf->m_pkthdr.tags);
+ while(p != NULL) {
+ /* 2KCL m_tag */
+ if (M_TAG_ALIGN(p->m_tag_len) +
+ sizeof (struct m_taghdr) > MLEN) {
+ p = SLIST_NEXT(p, m_tag_link);
+ continue;
+ }
+
+ VERIFY(p->m_tag_cookie == M_TAG_VALID_PATTERN);
+
+ struct mbuf *m = m_dtom(p);
+ struct m_taghdr *hdr = (struct m_taghdr *)m->m_data;
+
+ VERIFY(m->m_flags & M_TAGHDR && !(m->m_flags & M_EXT));
+
+ /* The mbuf can store this m_tag */
+ if (M_TAG_ALIGN(len) <= MLEN - m->m_len) {
+ t = (struct m_tag *)(m->m_data + m->m_len);
+ hdr->refcnt++;
+ m->m_len += M_TAG_ALIGN(len);
+ VERIFY(m->m_len <= MLEN);
+ break;
+ }
+
+ p = SLIST_NEXT(p, m_tag_link);
+ }
+
+ if (t == NULL)
+ return (m_tag_alloc(id, type, len, wait));
+
+ t->m_tag_cookie = M_TAG_VALID_PATTERN;
+ t->m_tag_type = type;
+ t->m_tag_len = len;
+ t->m_tag_id = id;
+ if (len > 0)
+ bzero(t + 1, len);
+ return (t);
+}
+