ip6_input.c
来自「eCos操作系统源码」· C语言 代码 · 共 2,515 行 · 第 1/5 页
C
2,515 行
#endif /* * jumbo payload length must be larger than 65535. */ if (jumboplen <= IPV6_MAXPACKET) { ip6stat.ip6s_badoptions++; icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, erroff + opt + 2 - opthead); return(-1); } *plenp = jumboplen; break; default: /* unknown option */ if (hbhlen < IP6OPT_MINLEN) { ip6stat.ip6s_toosmall++; goto bad; } optlen = ip6_unknown_opt(opt, m, erroff + opt - opthead); if (optlen == -1) return(-1); optlen += 2; break; } } return(0); bad: m_freem(m); return(-1);}/* * Unknown option processing. * The third argument `off' is the offset from the IPv6 header to the option, * which is necessary if the IPv6 header the and option header and IPv6 header * is not continuous in order to return an ICMPv6 error. */intip6_unknown_opt(optp, m, off) u_int8_t *optp; struct mbuf *m; int off;{ struct ip6_hdr *ip6; switch (IP6OPT_TYPE(*optp)) { case IP6OPT_TYPE_SKIP: /* ignore the option */ return((int)*(optp + 1)); case IP6OPT_TYPE_DISCARD: /* silently discard */ m_freem(m); return(-1); case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */ ip6stat.ip6s_badoptions++; icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off); return(-1); case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */ ip6stat.ip6s_badoptions++; ip6 = mtod(m, struct ip6_hdr *); if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || (m->m_flags & (M_BCAST|M_MCAST))) m_freem(m); else icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off); return(-1); } m_freem(m); /* XXX: NOTREACHED */ return(-1);}/* * Create the "control" list for this pcb. * The function will not modify mbuf chain at all. * * with KAME mbuf chain restriction: * The routine will be called from upper layer handlers like tcp6_input(). * Thus the routine assumes that the caller (tcp6_input) have already * called IP6_EXTHDR_CHECK() and all the extension headers are located in the * very first mbuf on the mbuf chain. */voidip6_savecontrol(in6p, ip6, m, ctl, prevctlp)#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(HAVE_NRL_INPCB) struct inpcb *in6p;#else struct in6pcb *in6p;#endif struct ip6_hdr *ip6; struct mbuf *m; struct ip6_recvpktopts *ctl, **prevctlp;{#define IS2292(x, y) ((in6p->in6p_flags & IN6P_RFC2292) ? (x) : (y)) struct mbuf **mp; struct cmsghdr *cm = NULL; struct ip6_recvpktopts *prevctl = NULL;#ifdef HAVE_NRL_INPCB# define in6p_flags inp_flags#endif#ifdef __bsdi__# define sbcreatecontrol so_cmsg#endif int privileged = 1; if (ctl == NULL) /* validity check */ return; bzero(ctl, sizeof(*ctl)); /* XXX is it really OK? */ mp = &ctl->head; /* * If caller wanted to keep history, allocate space to store the * history at the first time. */ if (prevctlp) { if (*prevctlp == NULL) { MALLOC(prevctl, struct ip6_recvpktopts *, sizeof(*prevctl), M_IP6OPT, M_NOWAIT); if (prevctl == NULL) { printf("ip6_savecontrol: can't allocate " " enough space for history\n"); return; } bzero(prevctl, sizeof(*prevctl)); *prevctlp = prevctl; } else prevctl = *prevctlp; }#ifdef SO_TIMESTAMP if ((in6p->in6p_socket->so_options & SO_TIMESTAMP) != 0) { struct timeval tv; microtime(&tv); *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), SCM_TIMESTAMP, SOL_SOCKET); if (*mp) { /* always set regradless of the previous value */ ctl->timestamp = *mp; mp = &(*mp)->m_next; } }#endif /* RFC 2292 sec. 5 */ if ((in6p->in6p_flags & IN6P_PKTINFO) != 0) { struct in6_pktinfo pi6, *prevpi = NULL; bcopy(&ip6->ip6_dst, &pi6.ipi6_addr, sizeof(struct in6_addr)); if (IN6_IS_SCOPE_LINKLOCAL(&pi6.ipi6_addr) || IN6_IS_ADDR_MC_INTFACELOCAL(&pi6.ipi6_addr)) pi6.ipi6_addr.s6_addr16[1] = 0; pi6.ipi6_ifindex = (m && m->m_pkthdr.rcvif) ? m->m_pkthdr.rcvif->if_index : 0; if (prevctl && prevctl->pktinfo) { cm = mtod(prevctl->pktinfo, struct cmsghdr *); prevpi = (struct in6_pktinfo *)CMSG_DATA(cm); } /* * Make a new option only if this is the first time or if the * option value is chaned from last time. */ if (prevpi == NULL || bcmp(prevpi, &pi6, sizeof(pi6))) { *mp = sbcreatecontrol((caddr_t) &pi6, sizeof(struct in6_pktinfo), IS2292(IPV6_2292PKTINFO, IPV6_PKTINFO), IPPROTO_IPV6); if (*mp) { ctl->pktinfo = *mp; mp = &(*mp)->m_next; } } } if ((in6p->in6p_flags & IN6P_HOPLIMIT) != 0) { int hlim = ip6->ip6_hlim & 0xff, oldhlim = -1; if (prevctl && prevctl->hlim) { cm = mtod(prevctl->hlim, struct cmsghdr *); bcopy(CMSG_DATA(cm), &oldhlim, sizeof(oldhlim)); oldhlim &= 0xff; } if (oldhlim < 0 || hlim != oldhlim) { *mp = sbcreatecontrol((caddr_t) &hlim, sizeof(int), IS2292(IPV6_2292HOPLIMIT, IPV6_HOPLIMIT), IPPROTO_IPV6); if (*mp) { ctl->hlim = *mp; mp = &(*mp)->m_next; } } } if ((in6p->in6p_flags & IN6P_TCLASS) != 0) { u_int32_t flowinfo; int oflowinfo = -1; int v; flowinfo = (u_int32_t)ntohl(ip6->ip6_flow & IPV6_FLOWINFO_MASK); flowinfo >>= 20; if (prevctl && prevctl->hlim) { cm = mtod(prevctl->hlim, struct cmsghdr *); bcopy(CMSG_DATA(cm), &v, sizeof(v)); oflowinfo = v & 0xff; } if (oflowinfo < 0 || flowinfo != oflowinfo) { v = flowinfo & 0xff; *mp = sbcreatecontrol((caddr_t) &v, sizeof(v), IPV6_TCLASS, IPPROTO_IPV6); if (*mp) { ctl->hlim = *mp; mp = &(*mp)->m_next; } } } /* * IPV6_HOPOPTS socket option. We require super-user privilege * for the option, but it might be too strict, since there might * be some hop-by-hop options which can be returned to normal user. * See RFC 2292 section 6. */ if ((in6p->in6p_flags & IN6P_HOPOPTS) != 0 && privileged) { /* * Check if a hop-by-hop options header is contatined in the * received packet, and if so, store the options as ancillary * data. Note that a hop-by-hop options header must be * just after the IPv6 header, which fact is assured through * the IPv6 input processing. */ struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { struct ip6_hbh *hbh, *prevhbh = NULL; int hbhlen = 0, prevhbhlen = 0;#ifdef PULLDOWN_TEST struct mbuf *ext;#endif#ifndef PULLDOWN_TEST hbh = (struct ip6_hbh *)(ip6 + 1); hbhlen = (hbh->ip6h_len + 1) << 3;#else ext = ip6_pullexthdr(m, sizeof(struct ip6_hdr), ip6->ip6_nxt); if (ext == NULL) { ip6stat.ip6s_tooshort++; return; } hbh = mtod(ext, struct ip6_hbh *); hbhlen = (hbh->ip6h_len + 1) << 3; if (hbhlen != ext->m_len) { m_freem(ext); ip6stat.ip6s_tooshort++; return; }#endif if (prevctl && prevctl->hbh) { cm = mtod(prevctl->hbh, struct cmsghdr *); prevhbh = (struct ip6_hbh *)CMSG_DATA(cm); prevhbhlen = (prevhbh->ip6h_len + 1) << 3; } /* * Check if there's difference between the current * and previous HbH headers. * XXX: should the next header field be ignored? */ if (prevhbh == NULL || hbhlen != prevhbhlen || bcmp(prevhbh, hbh, hbhlen)) { /* * XXX: We copy whole the header even if a * jumbo payload option is included, which * option is to be removed before returning * in the RFC 2292. * Note: this constraint is removed in * 2292bis. */ *mp = sbcreatecontrol((caddr_t)hbh, hbhlen, IS2292(IPV6_2292HOPOPTS, IPV6_HOPOPTS), IPPROTO_IPV6); if (*mp) { ctl->hbh = *mp; mp = &(*mp)->m_next; } }#ifdef PULLDOWN_TEST m_freem(ext);#endif } } if ((in6p->in6p_flags & (IN6P_RTHDR | IN6P_DSTOPTS)) != 0) { struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr); /* * Search for destination options headers or routing * header(s) through the header chain, and stores each * header as ancillary data. * Note that the order of the headers remains in * the chain of ancillary data. */ while (1) { /* is explicit loop prevention necessary? */ struct ip6_ext *ip6e = NULL; int elen;#ifdef PULLDOWN_TEST struct mbuf *ext = NULL;#endif /* * if it is not an extension header, don't try to * pull it from the chain. */ switch (nxt) { case IPPROTO_DSTOPTS: case IPPROTO_ROUTING: case IPPROTO_HOPOPTS: case IPPROTO_AH: /* is it possible? */ break; default: goto loopend; }#ifndef PULLDOWN_TEST if (off + sizeof(*ip6e) > m->m_len) goto loopend; ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off); if (nxt == IPPROTO_AH) elen = (ip6e->ip6e_len + 2) << 2; else elen = (ip6e->ip6e_len + 1) << 3; if (off + elen > m->m_len) goto loopend;#else ext = ip6_pullexthdr(m, off, nxt); if (ext == NULL) { ip6stat.ip6s_tooshort++; return; } ip6e = mtod(ext, struct ip6_ext *); if (nxt == IPPROTO_AH) elen = (ip6e->ip6e_len + 2) << 2; else elen = (ip6e->ip6e_len + 1) << 3; if (elen != ext->m_len) { m_freem(ext); ip6stat.ip6s_tooshort++; return; }#endif switch (nxt) { case IPPROTO_DSTOPTS: { struct ip6_dest *prevdest = NULL; int prevdestlen = 0; if (!(in6p->in6p_flags & IN6P_DSTOPTS)) break; /* * We also require super-user privilege for * the option. See comments on IN6_HOPOPTS. */ if (prevctl && prevctl->dest) { cm = mtod(prevctl->dest, struct cmsghdr *); prevdest = (struct ip6_dest *)CMSG_DATA(cm); prevdestlen = (prevdest->ip6d_len + 1) << 3; } /* * If this is the 1st dst opt header * we enconter and this header is * not different from the previous one, * simply ignore the header. */ if (ctl->dest == NULL && prevdest && prevdestlen == elen && bcmp(ip6e, prevdest, elen) == 0) break; *mp = sbcreatecontrol((caddr_t)ip6e, elen, IS2292(IPV6_2292DSTOPTS, IPV6_DSTOPTS), IPPROTO_IPV6); if (ctl->dest == NULL) ctl->dest = *mp; if (*mp) mp = &(*mp)->m_next; break; } case IPPROTO_ROUTING: { struct ip6_rthdr *prevrth = NULL; int prevrhlen = 0; if (!in6p->in6p_flags & IN6P_RTHDR) break; if (prevctl && prevctl->rthdr) { cm = mtod(prevctl->rthdr, struct cmsghdr *); prevrth = (struct ip6_rthdr *)CMSG_DATA(cm); prevrhlen = (prevrth->ip6r_len + 1) << 3; } /* * Check if the rthdr should be passed to * a user. See the comments for dstopt hdr. */ 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}voidip6_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)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?