ip_encap.c
来自「eCos操作系统源码」· C语言 代码 · 共 1,059 行 · 第 1/2 页
C
1,059 行
if (!rnh->rnh_addaddr((caddr_t)ep->addrpack, (caddr_t)ep->maskpack, rnh, ep->nodes)) { error = EEXIST; goto fail; } }#endif return error;#ifdef USE_RADIX fail: LIST_REMOVE(ep, chain); return error;#endif}static intencap_remove(ep) struct encaptab *ep;{#ifdef USE_RADIX struct radix_node_head *rnh = encap_rnh(ep->af);#endif int error = 0; LIST_REMOVE(ep, chain);#ifdef USE_RADIX if (!ep->func && rnh) { if (!rnh->rnh_deladdr((caddr_t)ep->addrpack, (caddr_t)ep->maskpack, rnh)) error = ESRCH; }#endif return error;}static intencap_afcheck(af, sp, dp) int af; const struct sockaddr *sp; const struct sockaddr *dp;{ if (sp && dp) { if (sp->sa_len != dp->sa_len) return EINVAL; if (af != sp->sa_family || af != dp->sa_family) return EINVAL; } else if (!sp && !dp) ; else return EINVAL; switch (af) { case AF_INET: if (sp && sp->sa_len != sizeof(struct sockaddr_in)) return EINVAL; if (dp && dp->sa_len != sizeof(struct sockaddr_in)) return EINVAL; break;#ifdef INET6 case AF_INET6: if (sp && sp->sa_len != sizeof(struct sockaddr_in6)) return EINVAL; if (dp && dp->sa_len != sizeof(struct sockaddr_in6)) return EINVAL; break;#endif default: return EAFNOSUPPORT; } return 0;}/* * sp (src ptr) is always my side, and dp (dst ptr) is always remote side. * length of mask (sm and dm) is assumed to be same as sp/dp. * Return value will be necessary as input (cookie) for encap_detach(). */const struct encaptab *encap_attach(af, proto, sp, sm, dp, dm, psw, arg) int af; int proto; const struct sockaddr *sp, *sm; const struct sockaddr *dp, *dm; const struct protosw *psw; void *arg;{ struct encaptab *ep; int error; int s; size_t l; struct pack4 *pack4;#ifdef INET6 struct pack6 *pack6;#endif#if defined(__NetBSD__) || defined(__OpenBSD__) s = splsoftnet();#else s = splnet();#endif /* sanity check on args */ error = encap_afcheck(af, sp, dp); if (error) goto fail; /* check if anyone have already attached with exactly same config */ for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) { if (ep->af != af) continue; if (ep->proto != proto) continue; if (ep->func) continue;#ifdef DIAGNOSTIC if (!ep->src || !ep->dst || !ep->srcmask || !ep->dstmask) panic("null pointers in encaptab");#endif if (ep->src->sa_len != sp->sa_len || bcmp(ep->src, sp, sp->sa_len) != 0 || bcmp(ep->srcmask, sm, sp->sa_len) != 0) continue; if (ep->dst->sa_len != dp->sa_len || bcmp(ep->dst, dp, dp->sa_len) != 0 || bcmp(ep->dstmask, dm, dp->sa_len) != 0) continue; error = EEXIST; goto fail; } switch (af) { case AF_INET: l = sizeof(*pack4); break;#ifdef INET6 case AF_INET6: l = sizeof(*pack6); break;#endif default: goto fail; }#ifdef DIAGNOSTIC /* if l exceeds the value sa_len can possibly express, it's wrong. */ if (l > (1 << (8 * sizeof(ep->addrpack->sa_len)))) { error = EINVAL; goto fail; }#endif ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /* M_NETADDR ok? */ if (ep == NULL) { error = ENOBUFS; goto fail; } bzero(ep, sizeof(*ep)); ep->addrpack = malloc(l, M_NETADDR, M_NOWAIT); if (ep->addrpack == NULL) { error = ENOBUFS; goto gc; } ep->maskpack = malloc(l, M_NETADDR, M_NOWAIT); if (ep->maskpack == NULL) { error = ENOBUFS; goto gc; } ep->af = af; ep->proto = proto; ep->addrpack->sa_len = l & 0xff; ep->maskpack->sa_len = l & 0xff; switch (af) { case AF_INET: pack4 = (struct pack4 *)ep->addrpack; ep->src = (struct sockaddr *)&pack4->mine; ep->dst = (struct sockaddr *)&pack4->yours; pack4 = (struct pack4 *)ep->maskpack; ep->srcmask = (struct sockaddr *)&pack4->mine; ep->dstmask = (struct sockaddr *)&pack4->yours; break;#ifdef INET6 case AF_INET6: pack6 = (struct pack6 *)ep->addrpack; ep->src = (struct sockaddr *)&pack6->mine; ep->dst = (struct sockaddr *)&pack6->yours; pack6 = (struct pack6 *)ep->maskpack; ep->srcmask = (struct sockaddr *)&pack6->mine; ep->dstmask = (struct sockaddr *)&pack6->yours; break;#endif } bcopy(sp, ep->src, sp->sa_len); bcopy(sm, ep->srcmask, sp->sa_len); bcopy(dp, ep->dst, dp->sa_len); bcopy(dm, ep->dstmask, dp->sa_len); ep->psw = psw; ep->arg = arg; error = encap_add(ep); if (error) goto gc; error = 0; splx(s); return ep;gc: if (ep->addrpack) free(ep->addrpack, M_NETADDR); if (ep->maskpack) free(ep->maskpack, M_NETADDR); if (ep) free(ep, M_NETADDR);fail: splx(s); return NULL;}const struct encaptab *encap_attach_func(af, proto, func, psw, arg) int af; int proto; int (*func) __P((const struct mbuf *, int, int, void *)); const struct protosw *psw; void *arg;{ struct encaptab *ep; int error; int s;#if defined(__NetBSD__) || defined(__OpenBSD__) s = splsoftnet();#else s = splnet();#endif /* sanity check on args */ if (!func) { error = EINVAL; goto fail; } error = encap_afcheck(af, NULL, NULL); if (error) goto fail; ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/ if (ep == NULL) { error = ENOBUFS; goto fail; } bzero(ep, sizeof(*ep)); ep->af = af; ep->proto = proto; ep->func = func; ep->psw = psw; ep->arg = arg; error = encap_add(ep); if (error) goto fail; error = 0; splx(s); return ep;fail: splx(s); return NULL;}/* XXX encap4_ctlinput() is necessary if we set DF=1 on outer IPv4 header */#ifdef INET6#if defined(HAVE_NRL_INPCB) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)#undef in6_rtchange#define in6_rtchange in_rtchange#define in6pcb inpcb#endifvoidencap6_ctlinput(cmd, sa, d0) int cmd; struct sockaddr *sa; void *d0;{ void *d = d0; struct ip6_hdr *ip6; struct mbuf *m; int off; struct ip6ctlparam *ip6cp = NULL; const struct sockaddr_in6 *sa6_src = NULL; void *cmdarg; int nxt; struct encaptab *ep; const struct ip6protosw *psw; if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) return; if ((unsigned)cmd >= PRC_NCMDS) return; if (cmd == PRC_HOSTDEAD) d = NULL;#if defined(__NetBSD__) || defined(__OpenBSD__) else if (cmd == PRC_MSGSIZE) ; /* special code is present, see below */#endif else if (inet6ctlerrmap[cmd] == 0) return; /* if the parameter is from icmp6, decode it. */ if (d != NULL) { ip6cp = (struct ip6ctlparam *)d; m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; cmdarg = ip6cp->ip6c_cmdarg; sa6_src = ip6cp->ip6c_src; nxt = ip6cp->ip6c_nxt; } else { m = NULL; ip6 = NULL; cmdarg = NULL; sa6_src = &sa6_any; nxt = -1; }#if defined(__NetBSD__) || defined(__OpenBSD__) if (ip6 && cmd == PRC_MSGSIZE) { int valid = 0; struct encaptab *match; /* * Check to see if we have a valid encap configuration. */ match = encap6_lookup(m, off, nxt, OUTBOUND); if (match) valid++; /* * Depending on the value of "valid" and routing table * size (mtudisc_{hi,lo}wat), we will: * - recalcurate the new MTU and create the * corresponding routing entry, or * - ignore the MTU change notification. */ icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); }#endif /* inform all listeners */ for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) { if (ep->af != AF_INET6) continue; if (ep->proto >= 0 && ep->proto != nxt) continue; /* should optimize by looking at address pairs */ /* XXX need to pass ep->arg or ep itself to listeners */ psw = (const struct ip6protosw *)ep->psw; if (psw && psw->pr_ctlinput) (*psw->pr_ctlinput)(cmd, sa, d); } rip6_ctlinput(cmd, sa, d0);}#endifintencap_detach(cookie) const struct encaptab *cookie;{ const struct encaptab *ep = cookie; struct encaptab *p; int error; for (p = LIST_FIRST(&encaptab); p; p = LIST_NEXT(p, chain)) { if (p == ep) { error = encap_remove(p); if (error) return error; if (!ep->func) { free(p->addrpack, M_NETADDR); free(p->maskpack, M_NETADDR); } free(p, M_NETADDR); /*XXX*/ return 0; } } return ENOENT;}#ifdef USE_RADIXstatic struct radix_node_head *encap_rnh(af) int af;{ switch (af) { case AF_INET: return encap_head[0];#ifdef INET6 case AF_INET6: return encap_head[1];#endif default: return NULL; }}static intmask_matchlen(sa) const struct sockaddr *sa;{ const char *p, *ep; int l; p = (const char *)sa; ep = p + sa->sa_len; p += 2; /* sa_len + sa_family */ l = 0; while (p < ep) { l += (*p ? 8 : 0); /* estimate */ p++; } return l;}#endif#ifndef USE_RADIXstatic intmask_match(ep, sp, dp) const struct encaptab *ep; const struct sockaddr *sp; const struct sockaddr *dp;{ struct sockaddr_storage s; struct sockaddr_storage d; int i; const u_int8_t *p, *q; u_int8_t *r; int matchlen;#ifdef DIAGNOSTIC if (ep->func) panic("wrong encaptab passed to mask_match");#endif if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d)) return 0; if (sp->sa_family != ep->af || dp->sa_family != ep->af) return 0; if (sp->sa_len != ep->src->sa_len || dp->sa_len != ep->dst->sa_len) return 0; matchlen = 0; p = (const u_int8_t *)sp; q = (const u_int8_t *)ep->srcmask; r = (u_int8_t *)&s; for (i = 0 ; i < sp->sa_len; i++) { r[i] = p[i] & q[i]; /* XXX estimate */ matchlen += (q[i] ? 8 : 0); } p = (const u_int8_t *)dp; q = (const u_int8_t *)ep->dstmask; r = (u_int8_t *)&d; for (i = 0 ; i < dp->sa_len; i++) { r[i] = p[i] & q[i]; /* XXX rough estimate */ matchlen += (q[i] ? 8 : 0); } /* need to overwrite len/family portion as we don't compare them */ s.ss_len = sp->sa_len; s.ss_family = sp->sa_family; d.ss_len = dp->sa_len; d.ss_family = dp->sa_family; if (bcmp(&s, ep->src, ep->src->sa_len) == 0 && bcmp(&d, ep->dst, ep->dst->sa_len) == 0) { return matchlen; } else return 0;}#endifstatic voidencap_fillarg(m, ep) struct mbuf *m; const struct encaptab *ep;{ struct mbuf *n; n = m_aux_add(m, AF_INET, IPPROTO_IPV4); if (n) { *mtod(n, void **) = ep->arg; n->m_len = sizeof(void *); }}void *encap_getarg(m) struct mbuf *m;{ void *p; struct mbuf *n; p = NULL; n = m_aux_find(m, AF_INET, IPPROTO_IPV4); if (n) { if (n->m_len == sizeof(void *)) p = *mtod(n, void **); m_aux_delete(m, n); } return p;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?