ip6_input.c
来自「eCos操作系统源码」· C语言 代码 · 共 2,515 行 · 第 1/5 页
C
2,515 行
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 voiddump_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}voidip6_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_RECVOPTSvoidip6_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. */intip6_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. */intip6_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_nexthdr(m, off, proto, nxtp); if (newoff < 0) return off; else if (newoff < off) return -1; /* invalid */ else if (newoff == off) return newoff; off = newoff; proto = *nxtp; }}#if !(defined(__FreeBSD__) && __FreeBSD__ >= 4)voidpfctlinput2(cmd, sa, ctlparam) int cmd; struct sockaddr *sa; void *ctlparam;{ struct domain *dp; struct protosw *pr; if (!sa) return; for (dp = domains; dp; dp = dp->dom_next) { /* * the check must be made by xx_ctlinput() anyways, to * make sure we use data item pointed to by ctlparam in * correct way. the following check is made just for safety. */ if (dp->dom_family != sa->sa_family) continue; for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) if (pr->pr_ctlinput) (*pr->pr_ctlinput)(cmd, sa, ctlparam); }}#endifstruct mbuf *ip6_addaux(m) struct mbuf *m;{ struct mbuf *n;#ifdef DIAGNOSTIC if (sizeof(struct ip6aux) > MHLEN) panic("assumption failed on sizeof(ip6aux)");#endif n = m_aux_find(m, AF_INET6, -1); if (n) { if (n->m_len < sizeof(struct ip6aux)) { printf("conflicting use of ip6aux"); return NULL; } } else { n = m_aux_add(m, AF_INET6, -1); n->m_len = sizeof(struct ip6aux); bzero(mtod(n, caddr_t), n->m_len); } return n;}struct mbuf *ip6_findaux(m) struct mbuf *m;{ struct mbuf *n; n = m_aux_find(m, AF_INET6, -1); if (n && n->m_len < sizeof(struct ip6aux)) { printf("conflicting use of ip6aux"); n = NULL; } return n;}voidip6_delaux(m) struct mbuf *m;{ struct mbuf *n; n = m_aux_find(m, AF_INET6, -1); if (n) m_aux_delete(m, n);}/* * System control for IP6 */int inet6ctlerrmap[PRC_NCMDS] = { 0, 0, 0, 0, 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, EMSGSIZE, EHOSTUNREACH, 0, 0, 0, 0, 0, 0, ENOPROTOOPT};
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?