summaryrefslogtreecommitdiffstats
path: root/sys/netipsec/ipsec_input.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netipsec/ipsec_input.c')
-rw-r--r--sys/netipsec/ipsec_input.c118
1 files changed, 64 insertions, 54 deletions
diff --git a/sys/netipsec/ipsec_input.c b/sys/netipsec/ipsec_input.c
index 66de530..8fb74ff 100644
--- a/sys/netipsec/ipsec_input.c
+++ b/sys/netipsec/ipsec_input.c
@@ -117,9 +117,10 @@ static void ipsec4_common_ctlinput(int, struct sockaddr *, void *, int);
* and call the appropriate transform. The transform callback
* takes care of further processing (like ingress filtering).
*/
-static int
+int
ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
{
+ char buf[INET6_ADDRSTRLEN];
union sockaddr_union dst_address;
struct secasvar *sav;
u_int32_t spi;
@@ -194,6 +195,13 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
sizeof(struct in6_addr),
(caddr_t) &dst_address.sin6.sin6_addr);
+ /* We keep addresses in SADB without embedded scope id */
+ if (IN6_IS_SCOPE_LINKLOCAL(&dst_address.sin6.sin6_addr)) {
+ /* XXX: sa6_recoverscope() */
+ dst_address.sin6.sin6_scope_id =
+ ntohs(dst_address.sin6.sin6_addr.s6_addr16[1]);
+ dst_address.sin6.sin6_addr.s6_addr16[1] = 0;
+ }
break;
#endif /* INET6 */
default:
@@ -207,8 +215,8 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
sav = KEY_ALLOCSA(&dst_address, sproto, spi);
if (sav == NULL) {
DPRINTF(("%s: no key association found for SA %s/%08lx/%u\n",
- __func__, ipsec_address(&dst_address),
- (u_long) ntohl(spi), sproto));
+ __func__, ipsec_address(&dst_address, buf, sizeof(buf)),
+ (u_long) ntohl(spi), sproto));
IPSEC_ISTAT(sproto, notdb);
m_freem(m);
return ENOENT;
@@ -216,8 +224,8 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
if (sav->tdb_xform == NULL) {
DPRINTF(("%s: attempted to use uninitialized SA %s/%08lx/%u\n",
- __func__, ipsec_address(&dst_address),
- (u_long) ntohl(spi), sproto));
+ __func__, ipsec_address(&dst_address, buf, sizeof(buf)),
+ (u_long) ntohl(spi), sproto));
IPSEC_ISTAT(sproto, noxform);
KEY_FREESAV(&sav);
m_freem(m);
@@ -234,28 +242,11 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
}
#ifdef INET
-/*
- * Common input handler for IPv4 AH, ESP, and IPCOMP.
- */
-int
-ipsec4_common_input(struct mbuf *m, ...)
-{
- va_list ap;
- int off, nxt;
-
- va_start(ap, m);
- off = va_arg(ap, int);
- nxt = va_arg(ap, int);
- va_end(ap);
-
- return ipsec_common_input(m, off, offsetof(struct ip, ip_p),
- AF_INET, nxt);
-}
-
void
ah4_input(struct mbuf *m, int off)
{
- ipsec4_common_input(m, off, IPPROTO_AH);
+ ipsec_common_input(m, off, offsetof(struct ip, ip_p),
+ AF_INET, IPPROTO_AH);
}
void
ah4_ctlinput(int cmd, struct sockaddr *sa, void *v)
@@ -268,7 +259,8 @@ ah4_ctlinput(int cmd, struct sockaddr *sa, void *v)
void
esp4_input(struct mbuf *m, int off)
{
- ipsec4_common_input(m, off, IPPROTO_ESP);
+ ipsec_common_input(m, off, offsetof(struct ip, ip_p),
+ AF_INET, IPPROTO_ESP);
}
void
esp4_ctlinput(int cmd, struct sockaddr *sa, void *v)
@@ -281,7 +273,8 @@ esp4_ctlinput(int cmd, struct sockaddr *sa, void *v)
void
ipcomp4_input(struct mbuf *m, int off)
{
- ipsec4_common_input(m, off, IPPROTO_IPCOMP);
+ ipsec_common_input(m, off, offsetof(struct ip, ip_p),
+ AF_INET, IPPROTO_IPCOMP);
}
/*
@@ -291,9 +284,10 @@ ipcomp4_input(struct mbuf *m, int off)
* the processed packet.
*/
int
-ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav,
- int skip, int protoff, struct m_tag *mt)
+ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
+ int protoff)
{
+ char buf[INET6_ADDRSTRLEN];
int prot, af, sproto, isr_prot;
struct ip *ip;
struct m_tag *mtag;
@@ -332,8 +326,8 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav,
*/
if (m->m_len < skip && (m = m_pullup(m, skip)) == NULL) {
DPRINTF(("%s: processing failed for SA %s/%08lx\n",
- __func__, ipsec_address(&sav->sah->saidx.dst),
- (u_long) ntohl(sav->spi)));
+ __func__, ipsec_address(&sav->sah->saidx.dst,
+ buf, sizeof(buf)), (u_long) ntohl(sav->spi)));
IPSEC_ISTAT(sproto, hdrops);
error = ENOBUFS;
goto bad;
@@ -356,6 +350,7 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav,
ipsec_bpf(m, sav, AF_INET, ENC_IN|ENC_BEFORE);
if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_BEFORE)) != 0)
return (error);
+ ip = mtod(m, struct ip *);
#endif /* DEV_ENC */
/* IP-in-IP encapsulation */
@@ -449,13 +444,9 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav,
/*
* Record what we've done to the packet (under what SA it was
- * processed). If we've been passed an mtag, it means the packet
- * was already processed by an ethernet/crypto combo card and
- * thus has a tag attached with all the right information, but
- * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to
- * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type.
+ * processed).
*/
- if (mt == NULL && sproto != IPPROTO_IPCOMP) {
+ if (sproto != IPPROTO_IPCOMP) {
mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
sizeof(struct tdb_ident), M_NOWAIT);
if (mtag == NULL) {
@@ -474,9 +465,6 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav,
tdbi->alg_enc = sav->alg_enc;
m_tag_prepend(m, mtag);
- } else if (mt != NULL) {
- mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE;
- /* XXX do we need to mark m_flags??? */
}
key_sa_recordxfer(sav, m); /* record data transfer */
@@ -593,15 +581,16 @@ ipsec6_common_input(struct mbuf **mp, int *offp, int proto)
* filtering and other sanity checks on the processed packet.
*/
int
-ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int protoff,
- struct m_tag *mt)
+ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
+ int protoff)
{
+ char buf[INET6_ADDRSTRLEN];
int prot, af, sproto;
struct ip6_hdr *ip6;
struct m_tag *mtag;
struct tdb_ident *tdbi;
struct secasindex *saidx;
- int nxt;
+ int nxt, isr_prot;
u_int8_t nxt8;
int error, nest;
#ifdef notyet
@@ -632,8 +621,8 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto
(m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
DPRINTF(("%s: processing failed for SA %s/%08lx\n",
- __func__, ipsec_address(&sav->sah->saidx.dst),
- (u_long) ntohl(sav->spi)));
+ __func__, ipsec_address(&sav->sah->saidx.dst, buf,
+ sizeof(buf)), (u_long) ntohl(sav->spi)));
IPSEC_ISTAT(sproto, hdrops);
error = EACCES;
@@ -738,13 +727,9 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto
/*
* Record what we've done to the packet (under what SA it was
- * processed). If we've been passed an mtag, it means the packet
- * was already processed by an ethernet/crypto combo card and
- * thus has a tag attached with all the right information, but
- * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to
- * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type.
+ * processed).
*/
- if (mt == NULL && sproto != IPPROTO_IPCOMP) {
+ if (sproto != IPPROTO_IPCOMP) {
mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
sizeof(struct tdb_ident), M_NOWAIT);
if (mtag == NULL) {
@@ -763,10 +748,6 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto
tdbi->alg_enc = sav->alg_enc;
m_tag_prepend(m, mtag);
- } else {
- if (mt != NULL)
- mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE;
- /* XXX do we need to mark m_flags??? */
}
key_sa_recordxfer(sav, m);
@@ -785,6 +766,35 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int proto
if ((error = ipsec_filter(&m, PFIL_IN, ENC_IN|ENC_AFTER)) != 0)
return (error);
#endif /* DEV_ENC */
+ if (skip == 0) {
+ /*
+ * We stripped outer IPv6 header.
+ * Now we should requeue decrypted packet via netisr.
+ */
+ switch (prot) {
+#ifdef INET
+ case IPPROTO_IPIP:
+ isr_prot = NETISR_IP;
+ break;
+#endif
+ case IPPROTO_IPV6:
+ isr_prot = NETISR_IPV6;
+ break;
+ default:
+ DPRINTF(("%s: cannot handle inner ip proto %d\n",
+ __func__, prot));
+ IPSEC_ISTAT(sproto, nopf);
+ error = EPFNOSUPPORT;
+ goto bad;
+ }
+ error = netisr_queue_src(isr_prot, (uintptr_t)sav->spi, m);
+ if (error) {
+ IPSEC_ISTAT(sproto, qfull);
+ DPRINTF(("%s: queue full; proto %u packet dropped\n",
+ __func__, sproto));
+ }
+ return (error);
+ }
/*
* See the end of ip6_input for this logic.
* IPPROTO_IPV[46] case will be processed just like other ones
OpenPOWER on IntegriCloud