mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-13 10:02:38 +00:00
if_ovpn: pass control packets through the socket
Rather than passing control packets through the ioctl interface allow them to pass through the normal UDP socket flow. This simplifies both kernel and userspace, and matches the approach taken (or the one that will be taken) on the Linux side of things. Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D37317
This commit is contained in:
parent
e1184adecf
commit
5246f8fade
@ -170,8 +170,7 @@ struct ovpn_softc {
|
||||
int peercount;
|
||||
struct ovpn_kpeer *peers[OVPN_MAX_PEERS]; /* XXX Hard limit for now? */
|
||||
|
||||
/* Pending packets */
|
||||
struct buf_ring *rxring;
|
||||
/* Pending notification */
|
||||
struct buf_ring *notifring;
|
||||
|
||||
counter_u64_t counters[OVPN_COUNTER_SIZE];
|
||||
@ -1275,8 +1274,7 @@ ovpn_poll_pkt(struct ovpn_softc *sc, nvlist_t **onvl)
|
||||
if (nvl == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
nvlist_add_number(nvl, "pending",
|
||||
buf_ring_count(sc->rxring) + buf_ring_count(sc->notifring));
|
||||
nvlist_add_number(nvl, "pending", buf_ring_count(sc->notifring));
|
||||
|
||||
*onvl = nvl;
|
||||
|
||||
@ -1287,57 +1285,24 @@ static int
|
||||
opvn_get_pkt(struct ovpn_softc *sc, nvlist_t **onvl)
|
||||
{
|
||||
struct ovpn_notification *n;
|
||||
struct ovpn_wire_header *ohdr;
|
||||
struct mbuf *m;
|
||||
uint8_t *buf;
|
||||
nvlist_t *nvl;
|
||||
uint32_t peerid;
|
||||
u_int mlength;
|
||||
|
||||
/* Check if we have notifications pending. */
|
||||
n = buf_ring_dequeue_mc(sc->notifring);
|
||||
if (n != NULL) {
|
||||
nvl = nvlist_create(0);
|
||||
if (nvl == NULL) {
|
||||
free(n, M_OVPN);
|
||||
return (ENOMEM);
|
||||
}
|
||||
nvlist_add_number(nvl, "peerid", n->peerid);
|
||||
nvlist_add_number(nvl, "notification", n->type);
|
||||
free(n, M_OVPN);
|
||||
|
||||
*onvl = nvl;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Queued packet. */
|
||||
m = buf_ring_dequeue_mc(sc->rxring);
|
||||
if (m == NULL)
|
||||
if (n == NULL)
|
||||
return (ENOENT);
|
||||
|
||||
mlength = m_length(m, NULL);
|
||||
buf = malloc(mlength, M_NVLIST, M_WAITOK);
|
||||
m_copydata(m, 0, mlength, buf);
|
||||
ohdr = (struct ovpn_wire_header *)buf;
|
||||
peerid = ntohl(ohdr->opcode) & 0x00ffffff;
|
||||
|
||||
nvl = nvlist_create(0);
|
||||
if (nvl == NULL) {
|
||||
OVPN_COUNTER_ADD(sc, lost_ctrl_pkts_in, 1);
|
||||
m_freem(m);
|
||||
free(buf, M_NVLIST);
|
||||
free(n, M_OVPN);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
nvlist_move_binary(nvl, "packet", buf, mlength);
|
||||
buf = NULL;
|
||||
nvlist_add_number(nvl, "peerid", peerid);
|
||||
nvlist_add_number(nvl, "peerid", n->peerid);
|
||||
nvlist_add_number(nvl, "notification", n->type);
|
||||
free(n, M_OVPN);
|
||||
|
||||
*onvl = nvl;
|
||||
|
||||
m_freem(m);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -2086,22 +2051,6 @@ ovpn_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
||||
return (ovpn_transmit_to_peer(ifp, m, peer, _ovpn_lock_trackerp));
|
||||
}
|
||||
|
||||
static void
|
||||
ovpn_rcv_ctrl(struct ovpn_softc *sc, struct mbuf *m, int off)
|
||||
{
|
||||
/* Lop off the IP and UDP headers */
|
||||
m_adj_decap(m, off);
|
||||
|
||||
/* Keep in the local ring until userspace fetches it. */
|
||||
if (buf_ring_enqueue(sc->rxring, m) != 0) {
|
||||
OVPN_COUNTER_ADD(sc, lost_ctrl_pkts_in, 1);
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
|
||||
OVPN_COUNTER_ADD(sc, received_ctrl_pkts, 1);
|
||||
}
|
||||
|
||||
static bool
|
||||
ovpn_check_replay(struct ovpn_kkey_dir *key, uint32_t seq)
|
||||
{
|
||||
@ -2174,6 +2123,7 @@ ovpn_udp_input(struct mbuf *m, int off, struct inpcb *inp,
|
||||
const struct sockaddr *sa, void *ctx)
|
||||
{
|
||||
struct ovpn_softc *sc = ctx;
|
||||
struct ovpn_wire_header tmphdr;
|
||||
struct ovpn_wire_header *ohdr;
|
||||
struct udphdr *uhdr;
|
||||
struct ovpn_kkey *key;
|
||||
@ -2199,16 +2149,27 @@ ovpn_udp_input(struct mbuf *m, int off, struct inpcb *inp,
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (m_length(m, NULL) < (off + sizeof(*uhdr) + ohdrlen)) {
|
||||
/* Short packet. */
|
||||
OVPN_RUNLOCK(sc);
|
||||
return (false);
|
||||
}
|
||||
|
||||
m_copydata(m, off + sizeof(*uhdr), ohdrlen, (caddr_t)&tmphdr);
|
||||
|
||||
op = ntohl(tmphdr.opcode) >> 24 >> OVPN_OP_SHIFT;
|
||||
if (op != OVPN_OP_DATA_V2) {
|
||||
/* Control packet? */
|
||||
OVPN_RUNLOCK(sc);
|
||||
return (false);
|
||||
}
|
||||
|
||||
m = m_pullup(m, off + sizeof(*uhdr) + ohdrlen);
|
||||
if (m == NULL) {
|
||||
OVPN_RUNLOCK(sc);
|
||||
OVPN_COUNTER_ADD(sc, nomem_data_pkts_in, 1);
|
||||
return (true);
|
||||
}
|
||||
uhdr = mtodo(m, off);
|
||||
ohdr = mtodo(m, off + sizeof(*uhdr));
|
||||
|
||||
op = ntohl(ohdr->opcode) >> 24 >> OVPN_OP_SHIFT;
|
||||
|
||||
/*
|
||||
* Simplify things by getting rid of the preceding headers, we don't
|
||||
@ -2219,15 +2180,6 @@ ovpn_udp_input(struct mbuf *m, int off, struct inpcb *inp,
|
||||
uhdr = mtodo(m, 0);
|
||||
ohdr = mtodo(m, sizeof(*uhdr));
|
||||
|
||||
if (op != OVPN_OP_DATA_V2) {
|
||||
OVPN_RUNLOCK(sc);
|
||||
ovpn_rcv_ctrl(sc, m, sizeof(struct udphdr));
|
||||
INP_WLOCK(inp);
|
||||
udp_notify(inp, EAGAIN);
|
||||
INP_WUNLOCK(inp);
|
||||
return (true);
|
||||
}
|
||||
|
||||
key = ovpn_find_key(sc, peer, ohdr);
|
||||
if (key == NULL || key->decrypt == NULL) {
|
||||
OVPN_RUNLOCK(sc);
|
||||
@ -2313,16 +2265,10 @@ ovpn_qflush(struct ifnet *ifp __unused)
|
||||
static void
|
||||
ovpn_flush_rxring(struct ovpn_softc *sc)
|
||||
{
|
||||
struct mbuf *m;
|
||||
struct ovpn_notification *n;
|
||||
|
||||
OVPN_WASSERT(sc);
|
||||
|
||||
while (! buf_ring_empty(sc->rxring)) {
|
||||
m = buf_ring_dequeue_sc(sc->rxring);
|
||||
m_freem(m);
|
||||
}
|
||||
|
||||
while (! buf_ring_empty(sc->notifring)) {
|
||||
n = buf_ring_dequeue_sc(sc->notifring);
|
||||
free(n, M_OVPN);
|
||||
@ -2409,7 +2355,6 @@ ovpn_clone_create(struct if_clone *ifc, char *name, size_t len,
|
||||
rm_init_flags(&sc->lock, "if_ovpn_lock", RM_RECURSE);
|
||||
sc->refcount = 0;
|
||||
|
||||
sc->rxring = buf_ring_alloc(32, M_OVPN, M_WAITOK, NULL);
|
||||
sc->notifring = buf_ring_alloc(32, M_OVPN, M_WAITOK, NULL);
|
||||
|
||||
COUNTER_ARRAY_ALLOC(sc->counters, OVPN_COUNTER_SIZE, M_WAITOK);
|
||||
@ -2486,7 +2431,6 @@ ovpn_clone_destroy(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags)
|
||||
} while (i < OVPN_MAX_PEERS);
|
||||
|
||||
ovpn_flush_rxring(sc);
|
||||
buf_ring_free(sc->rxring, M_OVPN);
|
||||
buf_ring_free(sc->notifring, M_OVPN);
|
||||
|
||||
OVPN_WUNLOCK(sc);
|
||||
|
Loading…
Reference in New Issue
Block a user