-/*
- * Merge new IPv6 received options to previous ones.
- * If a new option is not given, just re-link the option chain.
- * If an old option exists but a corresponding new one doesn't, just
- * keep the ole option.
- * If a new option exists but a corresponding old one doesn't, just
- * copy the new option.
- * If both new and old options exist, free old one and overwrite the option
- * with the new option.
- * Otherwise, do nothing for the option.
- * XXX: in any case, options that don't follow the recommend order and
- * number of extension headers (RFC 2460 Section 4.1) are simply ignored.
- * XXX: We assume that each option is stored in a single mbuf.
- */
-#define CLEAN_RECVOPT(old, type) \
-do { \
- if ((old)->type && (old)->type->m_next) { \
- (old)->type->m_next = NULL; \
- } \
-} while (0)
-#define MERGE_RECVOPT(new, old, type) if ((new)->type) {\
- if ((old)->type)\
- m_free((old)->type);\
- (old)->type = m_copy((new)->type, 0, (new)->type->m_len);\
- if (((old)->type) && ((old)->type->m_next)) {\
- m_freem((old)->type);\
- old->type = NULL;\
- }\
- }
-#define LINK_RECVOPTS(opt, type, p) if ((opt)->type) {\
- *(p) = (opt)->type;\
- (p) = &(opt)->type->m_next;\
- }
-
-static void dump_inputopts __P((char *, struct ip6_recvpktopts *));
-static void
-dump_inputopts(str, p)
- char *str;
- struct ip6_recvpktopts *p;
-{
-#if 1
- return;
-#else
-#define PRINT1(p, name) \
-do { \
- if (p->name) { \
- printf(" %s: %p", #name, (p)->name); \
- if (p->name->m_next) \
- printf("[%p]", (p)->name->m_next); \
- } \
-} while (0)
-
- printf("%s p=%p head=%p", str, p, p->head);
- PRINT1(p, hlim);
- PRINT1(p, pktinfo);
- PRINT1(p, hbh);
- PRINT1(p, dest1);
- PRINT1(p, dest2);
- PRINT1(p, rthdr);
- printf("\n");
-#undef PRINT1
-#endif
-}
-
-void
-ip6_update_recvpcbopt(old, new)
- struct ip6_recvpktopts *new, *old;
-{
- struct mbuf **mp;
-
- if (old == NULL) {
- printf("ip6_update_recvpcbopt: invalid arguments\n");
- return;
- }
-
- dump_inputopts("old before", old);
- if (new)
- dump_inputopts("new before", new);
-
-#if 0
- /*
- * cleanup m->m_next linkage. note that we do it in reverse order
- * to prevent possible memory leakage.
- */
- old->head = NULL;
- CLEAN_RECVOPT(old, rthdr);
- CLEAN_RECVOPT(old, dest2);
- CLEAN_RECVOPT(old, dest1);
- CLEAN_RECVOPT(old, hbh);
- CLEAN_RECVOPT(old, pktinfo);
- CLEAN_RECVOPT(old, hlim);
-#endif
-
- if (new) {
- MERGE_RECVOPT(new, old, hlim);
- MERGE_RECVOPT(new, old, pktinfo);
- MERGE_RECVOPT(new, old, hbh);
- MERGE_RECVOPT(new, old, dest1);
- MERGE_RECVOPT(new, old, dest2);
- MERGE_RECVOPT(new, old, rthdr);
- }
-
- dump_inputopts("old middle", old);
- if (new)
- dump_inputopts("new middle", new);
-
- /* link options */
- mp = &old->head;
- LINK_RECVOPTS(old, hlim, mp);
- LINK_RECVOPTS(old, pktinfo, mp);
- LINK_RECVOPTS(old, hbh, mp);
- LINK_RECVOPTS(old, dest1, mp);
- LINK_RECVOPTS(old, dest2, mp);
- LINK_RECVOPTS(old, rthdr, mp);
- *mp = NULL;
-
- dump_inputopts("old after", old);
- if (new)
- dump_inputopts("new after", new);
-}
-
-#undef MERGE_RECVOPT
-#undef LINK_RECVOPTS
-
-void
-ip6_reset_rcvopt(opts, optname)
- struct ip6_recvpktopts *opts;
- int optname;
-{
- if (opts == NULL)
- return;
-
- switch(optname) {
- case IPV6_RECVPKTINFO:
- if (opts->pktinfo) m_free(opts->pktinfo);
- opts->pktinfo = NULL;
- break;
- case IPV6_RECVHOPLIMIT:
- if (opts->hlim) m_free(opts->hlim);
- opts->hlim = NULL;
- break;
- case IPV6_RECVHOPOPTS:
- if (opts->hbh) m_free(opts->hbh);
- opts->hbh = NULL;
- break;
- case IPV6_RECVRTHDRDSTOPTS:
- if (opts->dest1) m_free(opts->dest1);
- opts->dest1 = NULL;
- break;
- case IPV6_RECVDSTOPTS:
- if (opts->dest2) m_free(opts->dest2);
- opts->dest2 = NULL;
- break;
- case IPV6_RECVRTHDR:
- if (opts->rthdr) m_free(opts->rthdr);
- opts->rthdr = NULL;
- break;
- default:
- printf("ip6_reset_rcvopt: invalid option name (%d)\n",
- optname);
- return;
- }
-
- ip6_update_recvpcbopt(opts, NULL); /* re-link the option chain */
-}
-