📄 ip6_input.c
字号:
*/
if (ctl->rthdr == NULL && prevrth &&
prevrhlen == elen &&
bcmp(ip6e, prevrth, elen) == 0)
break;
*mp = sbcreatecontrol((caddr_t)ip6e, elen,
IS2292(IPV6_2292RTHDR,
IPV6_RTHDR),
IPPROTO_IPV6);
if (ctl->rthdr == NULL)
ctl->rthdr = *mp;
if (*mp)
mp = &(*mp)->m_next;
break;
}
case IPPROTO_HOPOPTS:
case IPPROTO_AH: /* is it possible? */
break;
default:
/*
* other cases have been filtered in the above.
* none will visit this case. here we supply
* the code just in case (nxt overwritten or
* other cases).
*/
#ifdef PULLDOWN_TEST
m_freem(ext);
#endif
goto loopend;
}
/* proceed with the next header. */
off += elen;
nxt = ip6e->ip6e_nxt;
ip6e = NULL;
#ifdef PULLDOWN_TEST
m_freem(ext);
ext = NULL;
#endif
}
loopend:
;
}
#ifdef __bsdi__
# undef sbcreatecontrol
#endif
#ifdef __OpenBSD__
# undef in6p_flags
#endif
#undef IS2292
}
void
ip6_notify_pmtu(in6p, dst, mtu)
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(HAVE_NRL_INPCB)
struct inpcb *in6p;
#else
struct in6pcb *in6p;
#endif
struct sockaddr_in6 *dst;
u_int32_t *mtu;
{
struct socket *so;
struct mbuf *m_mtu;
struct ip6_mtuinfo mtuctl;
#ifdef __bsdi__
# define sbcreatecontrol so_cmsg
#endif
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(HAVE_NRL_INPCB)
so = in6p->inp_socket;
#else
so = in6p->in6p_socket;
#endif
if (mtu == NULL)
return;
#ifdef DIAGNOSTIC
if (so == NULL) /* I believe this is impossible */
panic("ip6_notify_pmtu: socket is NULL");
#endif
bzero(&mtuctl, sizeof(mtuctl)); /* zero-clear for safety */
mtuctl.ip6m_mtu = *mtu;
mtuctl.ip6m_addr = *dst;
#ifndef SCOPEDROUTING
in6_recoverscope(&mtuctl.ip6m_addr, &mtuctl.ip6m_addr.sin6_addr, NULL);
#endif
if ((m_mtu = sbcreatecontrol((caddr_t)&mtuctl, sizeof(mtuctl),
IPV6_PATHMTU, IPPROTO_IPV6)) == NULL)
return;
if (sbappendaddr(&so->so_rcv, (struct sockaddr *)dst, NULL, m_mtu)
== 0) {
m_freem(m_mtu);
/* XXX: should count statistics */
} else
sorwakeup(so);
return;
#ifdef __bsdi__
# undef sbcreatecontrol
#endif
}
#ifdef PULLDOWN_TEST
/*
* pull single extension header from mbuf chain. returns single mbuf that
* contains the result, or NULL on error.
*/
static struct mbuf *
ip6_pullexthdr(m, off, nxt)
struct mbuf *m;
size_t off;
int nxt;
{
struct ip6_ext ip6e;
size_t elen;
struct mbuf *n;
#ifdef DIAGNOSTIC
switch (nxt) {
case IPPROTO_DSTOPTS:
case IPPROTO_ROUTING:
case IPPROTO_HOPOPTS:
case IPPROTO_AH: /* is it possible? */
break;
default:
printf("ip6_pullexthdr: invalid nxt=%d\n", nxt);
}
#endif
m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
if (nxt == IPPROTO_AH)
elen = (ip6e.ip6e_len + 2) << 2;
else
elen = (ip6e.ip6e_len + 1) << 3;
MGET(n, M_DONTWAIT, MT_DATA);
if (n && elen >= MLEN) {
MCLGET(n, M_DONTWAIT);
if ((n->m_flags & M_EXT) == 0) {
m_free(n);
n = NULL;
}
}
if (!n)
return NULL;
n->m_len = 0;
if (elen >= M_TRAILINGSPACE(n)) {
m_free(n);
return NULL;
}
m_copydata(m, off, elen, mtod(n, caddr_t));
n->m_len = elen;
return n;
}
#endif
/*
* 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, dest);
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, dest);
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, dest);
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, dest, 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_RECVDSTOPTS:
if (opts->dest) m_free(opts->dest);
opts->dest = 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 */
}
/*
* Get pointer to the previous header followed by the header
* currently processed.
* XXX: This function supposes that
* M includes all headers,
* the next header field and the header length field of each header
* are valid, and
* the sum of each header length equals to OFF.
* Because of these assumptions, this function must be called very
* carefully. Moreover, it will not be used in the near future when
* we develop `neater' mechanism to process extension headers.
*/
char *
ip6_get_prevhdr(m, off)
struct mbuf *m;
int off;
{
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
if (off == sizeof(struct ip6_hdr))
return(&ip6->ip6_nxt);
else {
int len, nxt;
struct ip6_ext *ip6e = NULL;
nxt = ip6->ip6_nxt;
len = sizeof(struct ip6_hdr);
while (len < off) {
ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len);
switch (nxt) {
case IPPROTO_FRAGMENT:
len += sizeof(struct ip6_frag);
break;
case IPPROTO_AH:
len += (ip6e->ip6e_len + 2) << 2;
break;
default:
len += (ip6e->ip6e_len + 1) << 3;
break;
}
nxt = ip6e->ip6e_nxt;
}
if (ip6e)
return(&ip6e->ip6e_nxt);
else
return NULL;
}
}
/*
* get next header offset. m will be retained.
*/
int
ip6_nexthdr(m, off, proto, nxtp)
struct mbuf *m;
int off;
int proto;
int *nxtp;
{
struct ip6_hdr ip6;
struct ip6_ext ip6e;
struct ip6_frag fh;
/* just in case */
if (m == NULL)
panic("ip6_nexthdr: m == NULL");
if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.len < off)
return -1;
switch (proto) {
case IPPROTO_IPV6:
/* do not chase beyond intermediate IPv6 headers */
if (off != 0)
return -1;
if (m->m_pkthdr.len < off + sizeof(ip6))
return -1;
m_copydata(m, off, sizeof(ip6), (caddr_t)&ip6);
if (nxtp)
*nxtp = ip6.ip6_nxt;
off += sizeof(ip6);
return off;
case IPPROTO_FRAGMENT:
/*
* terminate parsing if it is not the first fragment,
* it does not make sense to parse through it.
*/
if (m->m_pkthdr.len < off + sizeof(fh))
return -1;
m_copydata(m, off, sizeof(fh), (caddr_t)&fh);
if ((ntohs(fh.ip6f_offlg) & IP6F_OFF_MASK) != 0)
return -1;
if (nxtp)
*nxtp = fh.ip6f_nxt;
off += sizeof(struct ip6_frag);
return off;
case IPPROTO_AH:
if (m->m_pkthdr.len < off + sizeof(ip6e))
return -1;
m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
if (nxtp)
*nxtp = ip6e.ip6e_nxt;
off += (ip6e.ip6e_len + 2) << 2;
if (m->m_pkthdr.len < off)
return -1;
return off;
case IPPROTO_HOPOPTS:
case IPPROTO_ROUTING:
case IPPROTO_DSTOPTS:
if (m->m_pkthdr.len < off + sizeof(ip6e))
return -1;
m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
if (nxtp)
*nxtp = ip6e.ip6e_nxt;
off += (ip6e.ip6e_len + 1) << 3;
if (m->m_pkthdr.len < off)
return -1;
return off;
case IPPROTO_NONE:
case IPPROTO_ESP:
case IPPROTO_IPCOMP:
/* give up */
return -1;
default:
return -1;
}
return -1;
}
/*
* get offset for the last header in the chain. m will be kept untainted.
*/
int
ip6_lasthdr(m, off, proto, nxtp)
struct mbuf *m;
int off;
int proto;
int *nxtp;
{
int newoff;
int nxt;
if (!nxtp) {
nxt = -1;
nxtp = &nxt;
}
while (1) {
newoff = ip6_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -