summaryrefslogtreecommitdiff
path: root/sys/net/encap.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net/encap.c')
-rw-r--r--sys/net/encap.c668
1 files changed, 390 insertions, 278 deletions
diff --git a/sys/net/encap.c b/sys/net/encap.c
index acd9a4e179c..898ff599dcf 100644
--- a/sys/net/encap.c
+++ b/sys/net/encap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: encap.c,v 1.4 1997/06/17 23:25:53 deraadt Exp $ */
+/* $OpenBSD: encap.c,v 1.5 1997/06/25 07:53:19 provos Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -62,65 +62,65 @@ struct sockaddr encap_src = { 2, PF_ENCAP, };
struct sockproto encap_proto = { PF_ENCAP, };
struct protosw encapsw[] = {
-{ SOCK_RAW, &encapdomain, 0, PR_ATOMIC|PR_ADDR,
- raw_input, encap_output, raw_ctlinput, 0,
- encap_usrreq,
- encap_init, 0, 0, 0,
-},
+ { SOCK_RAW, &encapdomain, 0, PR_ATOMIC|PR_ADDR,
+ raw_input, encap_output, raw_ctlinput, 0,
+ encap_usrreq,
+ encap_init, 0, 0, 0,
+ },
};
struct domain encapdomain =
- { AF_ENCAP, "encapsulation", 0, 0, 0,
- encapsw, &encapsw[sizeof(encapsw)/sizeof(encapsw[0])], 0,
- rn_inithead, 16, sizeof(struct sockaddr_encap)};
+{ AF_ENCAP, "encapsulation", 0, 0, 0,
+ encapsw, &encapsw[sizeof(encapsw)/sizeof(encapsw[0])], 0,
+ rn_inithead, 16, sizeof(struct sockaddr_encap)};
void
encap_init()
{
- struct xformsw *xsp;
-
- for (xsp = xformsw; xsp < xformswNXFORMSW; xsp++)
- {
- printf("encap_init: attaching <%s>\n", xsp->xf_name);
- (*(xsp->xf_attach))();
- }
+ struct xformsw *xsp;
+
+ for (xsp = xformsw; xsp < xformswNXFORMSW; xsp++)
+ {
+ printf("encap_init: attaching <%s>\n", xsp->xf_name);
+ (*(xsp->xf_attach))();
+ }
}
/*ARGSUSED*/
int
encap_usrreq(register struct socket *so, int req, struct mbuf *m, struct mbuf *nam, struct mbuf *control)
{
- register int error = 0;
- register struct rawcb *rp = sotorawcb(so);
- int s;
-
- if (req == PRU_ATTACH)
- {
- MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
- if ((so->so_pcb = (caddr_t)rp))
- bzero(so->so_pcb, sizeof(*rp));
-
- }
- s = splnet();
- error = raw_usrreq(so, req, m, nam, control);
- rp = sotorawcb(so);
- if ((req == PRU_ATTACH) && rp)
+ register int error = 0;
+ register struct rawcb *rp = sotorawcb(so);
+ int s;
+
+ if (req == PRU_ATTACH)
+ {
+ MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
+ if ((so->so_pcb = (caddr_t)rp))
+ bzero(so->so_pcb, sizeof(*rp));
+ }
+
+ s = splnet();
+ error = raw_usrreq(so, req, m, nam, control);
+ rp = sotorawcb(so);
+ if ((req == PRU_ATTACH) && rp)
+ {
+ /* int af = rp->rcb_proto.sp_protocol; */
+
+ if (error)
{
- /* int af = rp->rcb_proto.sp_protocol; */
-
- if (error)
- {
- free((caddr_t)rp, M_PCB);
- splx(s);
- return error;
- }
- rp->rcb_faddr = &encap_src;
- soisconnected(so);
- so->so_options |= SO_USELOOPBACK;
+ free((caddr_t)rp, M_PCB);
+ splx(s);
+ return error;
}
- splx(s);
- return error;
+ rp->rcb_faddr = &encap_src;
+ soisconnected(so);
+ so->so_options |= SO_USELOOPBACK;
+ }
+ splx(s);
+ return error;
}
int
@@ -128,264 +128,376 @@ int
encap_output(struct mbuf *m, ...)
#else
encap_output(m, va_alist)
- register struct mbuf *m;
- va_dcl
+register struct mbuf *m;
+va_dcl
#endif
{
#define SENDERR(e) do { error = e; goto flush;} while (0)
- struct socket *so;
- int len, emlen, error = 0, nspis, i;
- struct encap_msghdr *emp;
- struct ifnet *ifp;
- struct ifaddr *ifa;
- struct sockaddr_encap *sen, *sen2;
- struct sockaddr_in *sin;
- struct tdb *tdbp, *tprev;
- va_list ap;
-
- va_start(ap, m);
- so = va_arg(ap, struct socket *);
- va_end(ap);
-
- if ((m == 0) || ((m->m_len < sizeof(int32_t)) &&
- (m = m_pullup(m, sizeof(int32_t))) == 0))
- return ENOBUFS;
-
- if ((m->m_flags & M_PKTHDR) == 0)
- panic("encap_output");
-
- len = m->m_pkthdr.len;
- emp = mtod(m, struct encap_msghdr *);
- emlen = emp->em_msglen;
- if ((len < emlen))
- SENDERR(EINVAL);
-
- if (m->m_len < emlen)
- {
- m = m_pullup(m, emlen);
- if (m == NULL)
- SENDERR(ENOBUFS);
+ struct socket *so;
+ int len, emlen, error = 0, nspis, i;
+ struct encap_msghdr *emp;
+ struct ifnet *ifp;
+ struct ifaddr *ifa;
+ struct sockaddr_encap *sen, *sen2;
+ struct sockaddr_in *sin;
+ struct tdb *tdbp, *tprev;
+ va_list ap;
+ u_int32_t spi;
+
+ va_start(ap, m);
+ so = va_arg(ap, struct socket *);
+ va_end(ap);
+
+ if ((m == 0) || ((m->m_len < sizeof(int32_t)) &&
+ (m = m_pullup(m, sizeof(int32_t))) == 0))
+ return ENOBUFS;
+
+ if ((m->m_flags & M_PKTHDR) == 0)
+ panic("encap_output");
+
+ len = m->m_pkthdr.len;
+ emp = mtod(m, struct encap_msghdr *);
+ emlen = emp->em_msglen;
+ if ((len < emlen))
+ SENDERR(EINVAL);
+
+ if (m->m_len < emlen)
+ {
+ m = m_pullup(m, emlen);
+ if (m == NULL)
+ SENDERR(ENOBUFS);
- emp = mtod(m, struct encap_msghdr *);
- }
+ emp = mtod(m, struct encap_msghdr *);
+ }
- switch (emp->em_type)
- {
- case EMT_IFADDR:
- if (emp->em_ifn >= nencap)
- SENDERR(ENODEV);
- /*
- * Set the default source address for an encap interface
- */
-
- ifp = &(enc_softc[emp->em_ifn].enc_if);
+ switch (emp->em_type)
+ {
+ case EMT_IFADDR:
+ if (emp->em_ifn >= nencap)
+ SENDERR(ENODEV);
+
+ /*
+ * Set the default source address for an encap interface
+ */
+
+ ifp = &(enc_softc[emp->em_ifn].enc_if);
- if ((ifp->if_addrlist.tqh_first == NULL) ||
- (ifp->if_addrlist.tqh_first->ifa_addr == NULL) ||
- (ifp->if_addrlist.tqh_first->ifa_addr->sa_family != AF_ENCAP))
- {
- MALLOC(ifa, struct ifaddr *, sizeof (struct ifaddr) + 2*SENT_DEFIF_LEN, M_IFADDR, M_WAITOK);
- if (ifa == NULL)
- SENDERR(ENOBUFS);
- bzero((caddr_t)ifa, sizeof (struct ifaddr) + 2*SENT_DEFIF_LEN);
- sen = (struct sockaddr_encap *)(ifa + 1);
- sen2 = (struct sockaddr_encap *)((caddr_t)sen + SENT_DEFIF_LEN);
- ifa->ifa_addr = (struct sockaddr *)sen;
- ifa->ifa_dstaddr = (struct sockaddr *)sen2;
- ifa->ifa_ifp = ifp;
- TAILQ_INSERT_HEAD(&(ifp->if_addrlist), ifa, ifa_list);
- }
- else
- {
- sen = (struct sockaddr_encap *)((&(ifp->if_addrlist))->tqh_first->ifa_addr);
- sen2 = (struct sockaddr_encap *)((&(ifp->if_addrlist))->tqh_first->ifa_dstaddr);
- }
-
- sen->sen_family = AF_ENCAP;
- sen->sen_len = SENT_DEFIF_LEN;
- sen->sen_type = SENT_DEFIF;
- sin = (struct sockaddr_in *) &(sen->sen_dfl);
- sin->sin_len = sizeof(*sin);
- sin->sin_family = AF_INET;
- sin->sin_addr = emp->em_ifa;
-
- *sen2 = *sen;
+ if ((ifp->if_addrlist.tqh_first == NULL) ||
+ (ifp->if_addrlist.tqh_first->ifa_addr == NULL) ||
+ (ifp->if_addrlist.tqh_first->ifa_addr->sa_family != AF_ENCAP))
+ {
+ MALLOC(ifa, struct ifaddr *, sizeof (struct ifaddr) +
+ 2 * SENT_DEFIF_LEN, M_IFADDR, M_WAITOK);
+ if (ifa == NULL)
+ SENDERR(ENOBUFS);
- break;
+ bzero((caddr_t)ifa, sizeof (struct ifaddr) +
+ 2 * SENT_DEFIF_LEN);
+ sen = (struct sockaddr_encap *)(ifa + 1);
+ sen2 = (struct sockaddr_encap *)((caddr_t)sen +
+ SENT_DEFIF_LEN);
+ ifa->ifa_addr = (struct sockaddr *)sen;
+ ifa->ifa_dstaddr = (struct sockaddr *)sen2;
+ ifa->ifa_ifp = ifp;
+ TAILQ_INSERT_HEAD(&(ifp->if_addrlist), ifa, ifa_list);
+ }
+ else
+ {
+ sen = (struct sockaddr_encap *)((&(ifp->if_addrlist))->tqh_first->ifa_addr);
+ sen2 = (struct sockaddr_encap *)((&(ifp->if_addrlist))->tqh_first->ifa_dstaddr);
+ }
+
+ sen->sen_family = AF_ENCAP;
+ sen->sen_len = SENT_DEFIF_LEN;
+ sen->sen_type = SENT_DEFIF;
+ sin = (struct sockaddr_in *) &(sen->sen_dfl);
+ sin->sin_len = sizeof(*sin);
+ sin->sin_family = AF_INET;
+ sin->sin_addr = emp->em_ifa;
+
+ *sen2 = *sen;
+
+ break;
- case EMT_SETSPI:
- if (emp->em_if >= nencap)
- SENDERR(ENODEV);
- tdbp = gettdb(emp->em_spi, emp->em_dst);
+ case EMT_SETSPI:
+ if (emp->em_if >= nencap)
+ SENDERR(ENODEV);
+ tdbp = gettdb(emp->em_spi, emp->em_dst);
+ if (tdbp == NULL)
+ {
+ MALLOC(tdbp, struct tdb *, sizeof (*tdbp), M_TDB, M_WAITOK);
if (tdbp == NULL)
- {
- MALLOC(tdbp, struct tdb *, sizeof (*tdbp), M_TDB, M_WAITOK);
- if (tdbp == NULL)
- SENDERR(ENOBUFS);
-
- bzero((caddr_t)tdbp, sizeof(*tdbp));
-
- tdbp->tdb_spi = emp->em_spi;
- tdbp->tdb_dst = emp->em_dst;
- tdbp->tdb_rcvif = &(enc_softc[emp->em_if].enc_if);
- puttdb(tdbp);
- }
- else
- (*tdbp->tdb_xform->xf_zeroize)(tdbp);
-
- error = tdb_init(tdbp, m);
- ipspkernfs_dirty = 1;
- break;
+ SENDERR(ENOBUFS);
- case EMT_DELSPI:
- if (emp->em_if >= nencap)
- SENDERR(ENODEV);
- tdbp = gettdb(emp->em_spi, emp->em_dst);
- if (tdbp == NULL)
- {
- error = EINVAL;
- break;
- }
-
- if (emp->em_alg != tdbp->tdb_xform->xf_type)
- {
- error = EINVAL;
- break;
- }
-
- error = tdb_delete(tdbp, 0);
+ bzero((caddr_t)tdbp, sizeof(*tdbp));
+
+ tdbp->tdb_spi = emp->em_spi;
+ tdbp->tdb_dst = emp->em_dst;
+ tdbp->tdb_rcvif = &(enc_softc[emp->em_if].enc_if);
+
+ puttdb(tdbp);
+ }
+ else
+ (*tdbp->tdb_xform->xf_zeroize)(tdbp);
+
+ /* Various timers/counters */
+ if (emp->em_relative_hard != 0)
+ {
+ tdbp->tdb_exp_relative = emp->em_relative_hard;
+ tdbp->tdb_flags |= TDBF_RELATIVE;
+ }
+
+ if (emp->em_relative_soft != 0)
+ {
+ tdbp->tdb_soft_relative = emp->em_relative_soft;
+ tdbp->tdb_flags |= TDBF_SOFT_RELATIVE;
+ }
+
+ if (emp->em_first_use_hard != 0)
+ {
+ tdbp->tdb_exp_first_use = emp->em_first_use_hard;
+ tdbp->tdb_flags |= TDBF_FIRSTUSE;
+ }
+
+ if (emp->em_first_use_soft != 0)
+ {
+ tdbp->tdb_soft_first_use = emp->em_first_use_soft;
+ tdbp->tdb_flags |= TDBF_SOFT_FIRSTUSE;
+ }
+
+ if (emp->em_expire_hard != 0)
+ {
+ tdbp->tdb_exp_timeout = emp->em_expire_hard;
+ tdbp->tdb_flags |= TDBF_TIMER;
+ }
+
+ if (emp->em_expire_soft != 0)
+ {
+ tdbp->tdb_soft_timeout = emp->em_expire_soft;
+ tdbp->tdb_flags |= TDBF_SOFT_TIMER;
+ }
+
+ if (emp->em_bytes_hard != 0)
+ {
+ tdbp->tdb_exp_bytes = emp->em_bytes_hard;
+ tdbp->tdb_flags |= TDBF_BYTES;
+ }
+
+ if (emp->em_bytes_soft != 0)
+ {
+ tdbp->tdb_soft_bytes = emp->em_bytes_soft;
+ tdbp->tdb_flags |= TDBF_SOFT_BYTES;
+ }
+
+ if (emp->em_packets_hard != 0)
+ {
+ tdbp->tdb_exp_packets = emp->em_packets_hard;
+ tdbp->tdb_flags |= TDBF_PACKETS;
+ }
+
+ if (emp->em_packets_soft != 0)
+ {
+ tdbp->tdb_soft_packets = emp->em_packets_soft;
+ tdbp->tdb_flags |= TDBF_SOFT_PACKETS;
+ }
+
+ error = tdb_init(tdbp, m);
+ ipspkernfs_dirty = 1;
+ break;
+
+ case EMT_DELSPI:
+ if (emp->em_if >= nencap)
+ SENDERR(ENODEV);
+ tdbp = gettdb(emp->em_spi, emp->em_dst);
+ if (tdbp == NULL)
+ {
+ error = EINVAL;
break;
+ }
- case EMT_DELSPICHAIN:
- if (emp->em_if >= nencap)
- SENDERR(ENODEV);
- tdbp = gettdb(emp->em_spi, emp->em_dst);
- if (tdbp == NULL)
- {
- error = EINVAL;
- break;
- }
-
- if (emp->em_alg != tdbp->tdb_xform->xf_type)
- {
- error = EINVAL;
- break;
- }
-
- error = tdb_delete(tdbp, 1);
- break;
-
- case EMT_GRPSPIS:
- nspis = (emlen - 4) / 12;
- if (nspis * 12 + 4 != emlen)
- SENDERR(EINVAL);
-
- for (i = 0; i < nspis; i++)
- if ((tdbp = gettdb(emp->em_rel[i].emr_spi, emp->em_rel[i].emr_dst)) == NULL)
- SENDERR(ENOENT);
- else
- emp->em_rel[i].emr_tdb = tdbp;
- tprev = emp->em_rel[0].emr_tdb;
- tprev->tdb_inext = NULL;
- for (i = 1; i < nspis; i++)
- {
- tdbp = emp->em_rel[i].emr_tdb;
- tprev->tdb_onext = tdbp;
- tdbp->tdb_inext = tprev;
- tprev = tdbp;
- }
- tprev->tdb_onext = NULL;
- ipspkernfs_dirty = 1;
- error = 0;
+ if (emp->em_alg != tdbp->tdb_xform->xf_type)
+ {
+ error = EINVAL;
break;
+ }
+
+ error = tdb_delete(tdbp, 0);
+ break;
+
+ case EMT_DELSPICHAIN:
+ if (emp->em_if >= nencap)
+ SENDERR(ENODEV);
+ tdbp = gettdb(emp->em_spi, emp->em_dst);
+ if (tdbp == NULL)
+ {
+ error = EINVAL;
+ break;
+ }
- default:
+ if (emp->em_alg != tdbp->tdb_xform->xf_type)
+ {
+ error = EINVAL;
+ break;
+ }
+
+ error = tdb_delete(tdbp, 1);
+ break;
+
+ case EMT_GRPSPIS:
+ nspis = (emlen - 4) / 12;
+ if (nspis * 12 + 4 != emlen)
+ SENDERR(EINVAL);
+
+ for (i = 0; i < nspis; i++)
+ if ((tdbp = gettdb(emp->em_rel[i].emr_spi, emp->em_rel[i].emr_dst)) == NULL)
+ SENDERR(ENOENT);
+ else
+ emp->em_rel[i].emr_tdb = tdbp;
+
+ tprev = emp->em_rel[0].emr_tdb;
+ tprev->tdb_inext = NULL;
+ for (i = 1; i < nspis; i++)
+ {
+ tdbp = emp->em_rel[i].emr_tdb;
+ tprev->tdb_onext = tdbp;
+ tdbp->tdb_inext = tprev;
+ tprev = tdbp;
+ }
+ tprev->tdb_onext = NULL;
+ ipspkernfs_dirty = 1;
+ error = 0;
+ break;
+
+ case EMT_RESERVESPI:
+ spi = reserve_spi(emp->em_spi, emp->em_dst);
+ if (spi == 0)
+ if (emp->em_spi == 0)
+ SENDERR(ENOBUFS);
+ else
SENDERR(EINVAL);
- }
-
- return error;
- flush:
- if (m)
- m_freem(m);
- return error;
+ emp->em_spi = spi;
+
+ /* Send it back to us */
+ if (sbappendaddr(&so->so_rcv, &encap_src, m,
+ (struct mbuf *)0) == 0)
+ SENDERR(ENOBUFS);
+ else
+ sorwakeup(so); /* wakeup */
+
+ error = 0;
+
+ break;
+
+ case EMT_ENABLESPI:
+ tdbp = gettdb(emp->em_spi, emp->em_dst);
+ if (tdbp == NULL)
+ SENDERR(ENOENT);
+
+ /* Clear the INVALID flag */
+ tdbp->tdb_flags &= (~TDBF_INVALID);
+ error = 0;
+
+ break;
+
+ case EMT_DISABLESPI:
+ tdbp = gettdb(emp->em_spi, emp->em_dst);
+ if (tdbp == NULL)
+ SENDERR(ENOENT);
+
+ /* Set the INVALID flag */
+ tdbp->tdb_flags |= TDBF_INVALID;
+ error = 0;
+
+ break;
+
+ default:
+ SENDERR(EINVAL);
+ }
+
+ return error;
+
+flush:
+ if (m)
+ m_freem(m);
+ return error;
}
struct ifaddr *
encap_findgwifa(struct sockaddr *gw)
{
- struct sockaddr_encap *egw = (struct sockaddr_encap *)gw;
- u_char *op = (u_char *)gw;
- int i, j;
- struct ifaddr *retval = loif.if_addrlist.tqh_first;
- union
- {
- struct in_addr ia;
- u_char io[4];
- } iao;
+ struct sockaddr_encap *egw = (struct sockaddr_encap *)gw;
+ u_char *op = (u_char *)gw;
+ int i, j;
+ struct ifaddr *retval = loif.if_addrlist.tqh_first;
+ union
+ {
+ struct in_addr ia;
+ u_char io[4];
+ } iao;
- switch (egw->sen_type)
- {
- case SENT_IPSP:
- return enc_softc[egw->sen_ipsp_ifn].enc_if.if_addrlist.tqh_first;
- break;
-
- case SENT_IP4:
- /*
- * Pretty-much standard options walking code.
- * Repeated elsewhere as necessary
- */
-
- for (i = SENT_IP4_LEN; i < egw->sen_len;)
- switch (op[i])
- {
- case SENO_EOL:
- goto opt_done;
-
- case SENO_NOP:
- i++;
- continue;
+ switch (egw->sen_type)
+ {
+ case SENT_IPSP:
+ return enc_softc[egw->sen_ipsp_ifn].enc_if.if_addrlist.tqh_first;
+ break;
+
+ case SENT_IP4:
+ /*
+ * Pretty-much standard options walking code.
+ * Repeated elsewhere as necessary
+ */
+
+ for (i = SENT_IP4_LEN; i < egw->sen_len;)
+ switch (op[i])
+ {
+ case SENO_EOL:
+ goto opt_done;
+
+ case SENO_NOP:
+ i++;
+ continue;
+
+ case SENO_IFN:
+ if (op[i+1] != 3)
+ {
+ return NULL;
+ }
+ retval = enc_softc[op[i+2]].enc_if.if_addrlist.tqh_first;
+ goto opt_done;
+
+ case SENO_IFIP4A:
+ if (op[i+1] != 6) /* XXX -- IPv4 address */
+ {
+ return NULL;
+ }
+ iao.io[0] = op[i+2];
+ iao.io[1] = op[i+3];
+ iao.io[2] = op[i+4];
+ iao.io[3] = op[i+5];
+
+ for (j = 0; j < nencap; j++)
+ {
+ struct ifaddr *ia = (struct ifaddr *)enc_softc[j].enc_if.if_addrlist.tqh_first;
- case SENO_IFN:
- if (op[i+1] != 3)
- {
- return NULL;
- }
- retval = enc_softc[op[i+2]].enc_if.if_addrlist.tqh_first;
- goto opt_done;
+ struct sockaddr_in *si = (struct sockaddr_in *)ia->ifa_addr;
- case SENO_IFIP4A:
- if (op[i+1] != 6) /* XXX -- IPv4 address */
+ if ((si->sin_family == AF_INET) && (si->sin_addr.s_addr == iao.ia.s_addr))
{
- return NULL;
+ retval = ia;
+ goto opt_done;
}
- iao.io[0] = op[i+2];
- iao.io[1] = op[i+3];
- iao.io[2] = op[i+4];
- iao.io[3] = op[i+5];
-
- for (j = 0; j < nencap; j++)
- {
- struct ifaddr *ia = (struct ifaddr *)enc_softc[j].enc_if.if_addrlist.tqh_first;
-
- struct sockaddr_in *si = (struct sockaddr_in *)ia->ifa_addr;
-
- if ((si->sin_family == AF_INET) && (si->sin_addr.s_addr == iao.ia.s_addr))
- {
- retval = ia;
- goto opt_done;
- }
- }
- i += 6;
- break;
-
- default:
- if (op[i+1] == 0)
- return NULL;
- i += op[i+i];
- }
- opt_done:
- break;
- }
- return retval;
+ }
+ i += 6;
+ break;
+
+ default:
+ if (op[i+1] == 0)
+ return NULL;
+ i += op[i+i];
+ }
+ opt_done:
+ break;
+ }
+ return retval;
}