Make gre(4) work in the New File Descriptor / Socket Locking Order.
Move the function+line printing into GRE_DPRINTF(). Retire gre_closef(). Retire gre_join(). Constify gre_reconf(), and don't pass it an LWP any longer. Make this work in the new file descriptor regime. Add a kernel thread per gre(4) instance whose purpose is to install the socket into proc0's file descriptor table. Add gre_fp_send() and gre_fp_recv() for passing file_t pointers to proc0. Fix locking: don't solock() in the socket upcall, where it is already held. Do solock() before calling soconnect(). Simplify reconfiguration. Update a comment that mentions finding a less specific route, since we don't do that any more.
This commit is contained in:
parent
a790b941e6
commit
5198e29b4c
382
sys/net/if_gre.c
382
sys/net/if_gre.c
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: if_gre.c,v 1.131 2008/04/28 20:24:09 martin Exp $ */
|
||||
/* $NetBSD: if_gre.c,v 1.132 2008/05/09 20:14:07 dyoung Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
|
||||
|
@ -40,7 +40,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: if_gre.c,v 1.131 2008/04/28 20:24:09 martin Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: if_gre.c,v 1.132 2008/05/09 20:14:07 dyoung Exp $");
|
||||
|
||||
#include "opt_gre.h"
|
||||
#include "opt_inet.h"
|
||||
|
@ -115,11 +115,13 @@ __KERNEL_RCSID(0, "$NetBSD: if_gre.c,v 1.131 2008/04/28 20:24:09 martin Exp $");
|
|||
|
||||
#ifdef GRE_DEBUG
|
||||
int gre_debug = 0;
|
||||
#define GRE_DPRINTF(__sc, __fmt, ...) \
|
||||
do { \
|
||||
if (__predict_false(gre_debug || \
|
||||
((__sc)->sc_if.if_flags & IFF_DEBUG) != 0)) \
|
||||
printf(__fmt, __VA_ARGS__); \
|
||||
#define GRE_DPRINTF(__sc, ...) \
|
||||
do { \
|
||||
if (__predict_false(gre_debug || \
|
||||
((__sc)->sc_if.if_flags & IFF_DEBUG) != 0)) { \
|
||||
printf("%s.%d: ", __func__, __LINE__); \
|
||||
printf(__VA_ARGS__); \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
#else
|
||||
#define GRE_DPRINTF(__sc, __fmt, ...) do { } while (/*CONSTCOND*/0)
|
||||
|
@ -140,7 +142,6 @@ static bool gre_is_nullconf(const struct gre_soparm *);
|
|||
static int gre_output(struct ifnet *, struct mbuf *,
|
||||
const struct sockaddr *, struct rtentry *);
|
||||
static int gre_ioctl(struct ifnet *, u_long, void *);
|
||||
static void gre_closef(file_t **);
|
||||
static int gre_getsockname(struct socket *, struct mbuf *, struct lwp *);
|
||||
static int gre_getpeername(struct socket *, struct mbuf *, struct lwp *);
|
||||
static int gre_getnames(struct socket *, struct lwp *,
|
||||
|
@ -148,8 +149,11 @@ static int gre_getnames(struct socket *, struct lwp *,
|
|||
static void gre_clearconf(struct gre_soparm *, bool);
|
||||
static int gre_soreceive(struct socket *, struct mbuf **);
|
||||
static int gre_sosend(struct socket *, struct mbuf *, struct lwp *);
|
||||
static struct socket *gre_reconf(struct gre_softc *, struct socket *, lwp_t *,
|
||||
const struct gre_soparm *);
|
||||
static struct socket *gre_reconf(struct gre_softc *, const struct gre_soparm *);
|
||||
|
||||
static bool gre_fp_send(struct gre_softc *, enum gre_msg, file_t *);
|
||||
static bool gre_fp_recv(struct gre_softc *);
|
||||
static void gre_fp_recvloop(void *);
|
||||
|
||||
static int
|
||||
nearest_pow2(size_t len0)
|
||||
|
@ -237,20 +241,18 @@ static void
|
|||
greintr(void *arg)
|
||||
{
|
||||
struct gre_softc *sc = (struct gre_softc *)arg;
|
||||
struct socket *so = sc->sc_so;
|
||||
struct socket *so = sc->sc_soparm.sp_so;
|
||||
int rc;
|
||||
struct mbuf *m;
|
||||
|
||||
KASSERT(sc->sc_so != NULL);
|
||||
KASSERT(so != NULL);
|
||||
|
||||
sc->sc_send_ev.ev_count++;
|
||||
GRE_DPRINTF(sc, "%s: enter\n", __func__);
|
||||
GRE_DPRINTF(sc, "enter\n");
|
||||
while ((m = gre_bufq_dequeue(&sc->sc_snd)) != NULL) {
|
||||
/* XXX handle ENOBUFS? */
|
||||
if ((rc = gre_sosend(so, m, curlwp)) != 0) {
|
||||
GRE_DPRINTF(sc, "%s: gre_sosend failed %d\n", __func__,
|
||||
rc);
|
||||
}
|
||||
if ((rc = gre_sosend(so, m, curlwp)) != 0)
|
||||
GRE_DPRINTF(sc, "gre_sosend failed %d\n", rc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,12 +265,12 @@ gre_wait(struct gre_softc *sc)
|
|||
sc->sc_waiters--;
|
||||
}
|
||||
|
||||
/* Caller must hold sc->sc_mtx. */
|
||||
static void
|
||||
gre_join(struct gre_softc *sc)
|
||||
gre_fp_wait(struct gre_softc *sc)
|
||||
{
|
||||
while (sc->sc_waiters > 0)
|
||||
cv_wait(&sc->sc_condvar, &sc->sc_mtx);
|
||||
sc->sc_fp_waiters++;
|
||||
cv_wait(&sc->sc_fp_condvar, &sc->sc_mtx);
|
||||
sc->sc_fp_waiters--;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -307,12 +309,14 @@ gre_evcnt_attach(struct gre_softc *sc)
|
|||
static int
|
||||
gre_clone_create(struct if_clone *ifc, int unit)
|
||||
{
|
||||
struct gre_soparm sp;
|
||||
int rc;
|
||||
struct gre_softc *sc;
|
||||
struct gre_soparm *sp;
|
||||
|
||||
sc = malloc(sizeof(struct gre_softc), M_DEVBUF, M_WAITOK|M_ZERO);
|
||||
mutex_init(&sc->sc_mtx, MUTEX_DRIVER, IPL_SOFTNET);
|
||||
cv_init(&sc->sc_condvar, "gre wait");
|
||||
cv_init(&sc->sc_fp_condvar, "gre fp");
|
||||
|
||||
snprintf(sc->sc_if.if_xname, sizeof(sc->sc_if.if_xname), "%s%d",
|
||||
ifc->ifc_name, unit);
|
||||
|
@ -325,13 +329,21 @@ gre_clone_create(struct if_clone *ifc, int unit)
|
|||
sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
|
||||
sc->sc_if.if_output = gre_output;
|
||||
sc->sc_if.if_ioctl = gre_ioctl;
|
||||
sockaddr_copy(sstosa(&sp.sp_dst), sizeof(sp.sp_dst), sintocsa(&in_any));
|
||||
sockaddr_copy(sstosa(&sp.sp_src), sizeof(sp.sp_src), sintocsa(&in_any));
|
||||
sp.sp_proto = IPPROTO_GRE;
|
||||
sp.sp_type = SOCK_RAW;
|
||||
sp.sp_bysock = 0;
|
||||
sp.sp_fd = -1;
|
||||
sc->sc_soparm = sp;
|
||||
sp = &sc->sc_soparm;
|
||||
sockaddr_copy(sstosa(&sp->sp_dst), sizeof(sp->sp_dst),
|
||||
sintocsa(&in_any));
|
||||
sockaddr_copy(sstosa(&sp->sp_src), sizeof(sp->sp_src),
|
||||
sintocsa(&in_any));
|
||||
sp->sp_proto = IPPROTO_GRE;
|
||||
sp->sp_type = SOCK_RAW;
|
||||
|
||||
sc->sc_fd = -1;
|
||||
|
||||
rc = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, gre_fp_recvloop, sc,
|
||||
NULL, sc->sc_if.if_xname);
|
||||
|
||||
if (rc != 0)
|
||||
return -1;
|
||||
|
||||
gre_evcnt_attach(sc);
|
||||
|
||||
|
@ -342,7 +354,6 @@ gre_clone_create(struct if_clone *ifc, int unit)
|
|||
#if NBPFILTER > 0
|
||||
bpfattach(&sc->sc_if, DLT_NULL, sizeof(uint32_t));
|
||||
#endif
|
||||
sc->sc_lwp = &lwp0;
|
||||
sc->sc_state = GRE_S_IDLE;
|
||||
return 0;
|
||||
}
|
||||
|
@ -353,7 +364,7 @@ gre_clone_destroy(struct ifnet *ifp)
|
|||
int s;
|
||||
struct gre_softc *sc = ifp->if_softc;
|
||||
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
|
||||
#if NBPFILTER > 0
|
||||
bpfdetach(ifp);
|
||||
|
@ -366,20 +377,29 @@ gre_clone_destroy(struct ifnet *ifp)
|
|||
* cannot locate the interface any longer.
|
||||
*/
|
||||
mutex_enter(&sc->sc_mtx);
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
while (sc->sc_state != GRE_S_IDLE)
|
||||
gre_wait(sc);
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
sc->sc_state = GRE_S_DIE;
|
||||
cv_broadcast(&sc->sc_condvar);
|
||||
gre_join(sc);
|
||||
while (sc->sc_waiters > 0)
|
||||
cv_wait(&sc->sc_condvar, &sc->sc_mtx);
|
||||
/* At this point, no other LWP will access the gre_softc, so
|
||||
* we can release the mutex.
|
||||
*/
|
||||
mutex_exit(&sc->sc_mtx);
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
/* Note that we must not hold the mutex while we call gre_reconf(). */
|
||||
sc->sc_so = gre_reconf(sc, sc->sc_so, sc->sc_lwp, NULL);
|
||||
gre_reconf(sc, NULL);
|
||||
|
||||
mutex_enter(&sc->sc_mtx);
|
||||
sc->sc_msg = GRE_M_STOP;
|
||||
cv_signal(&sc->sc_fp_condvar);
|
||||
while (sc->sc_fp_waiters > 0)
|
||||
cv_wait(&sc->sc_fp_condvar, &sc->sc_mtx);
|
||||
mutex_exit(&sc->sc_mtx);
|
||||
|
||||
splx(s);
|
||||
|
||||
cv_destroy(&sc->sc_condvar);
|
||||
|
@ -398,7 +418,7 @@ gre_receive(struct socket *so, void *arg, int waitflag)
|
|||
const struct gre_h *gh;
|
||||
struct mbuf *m;
|
||||
|
||||
GRE_DPRINTF(sc, "%s: enter\n", __func__);
|
||||
GRE_DPRINTF(sc, "enter\n");
|
||||
|
||||
sc->sc_recv_ev.ev_count++;
|
||||
|
||||
|
@ -407,7 +427,7 @@ gre_receive(struct socket *so, void *arg, int waitflag)
|
|||
* ICMP Port Unreachable)?
|
||||
*/
|
||||
if (rc == EWOULDBLOCK) {
|
||||
GRE_DPRINTF(sc, "%s: EWOULDBLOCK\n", __func__);
|
||||
GRE_DPRINTF(sc, "EWOULDBLOCK\n");
|
||||
sc->sc_block_ev.ev_count++;
|
||||
return;
|
||||
} else if (rc != 0 || m == NULL) {
|
||||
|
@ -417,7 +437,7 @@ gre_receive(struct socket *so, void *arg, int waitflag)
|
|||
return;
|
||||
}
|
||||
if (m->m_len < sizeof(*gh) && (m = m_pullup(m, sizeof(*gh))) == NULL) {
|
||||
GRE_DPRINTF(sc, "%s: m_pullup failed\n", __func__);
|
||||
GRE_DPRINTF(sc, "m_pullup failed\n");
|
||||
sc->sc_pullup_ev.ev_count++;
|
||||
return;
|
||||
}
|
||||
|
@ -425,7 +445,7 @@ gre_receive(struct socket *so, void *arg, int waitflag)
|
|||
|
||||
if (gre_input(sc, m, 0, gh) == 0) {
|
||||
sc->sc_unsupp_ev.ev_count++;
|
||||
GRE_DPRINTF(sc, "%s: dropping unsupported\n", __func__);
|
||||
GRE_DPRINTF(sc, "dropping unsupported\n");
|
||||
m_freem(m);
|
||||
}
|
||||
}
|
||||
|
@ -449,21 +469,21 @@ gre_upcall_remove(struct socket *so)
|
|||
}
|
||||
|
||||
static int
|
||||
gre_socreate(struct gre_softc *sc, struct gre_soparm *sp, int *fdout)
|
||||
gre_socreate(struct gre_softc *sc, const struct gre_soparm *sp, int *fdout)
|
||||
{
|
||||
const struct protosw *pr;
|
||||
int fd, rc;
|
||||
struct mbuf *m;
|
||||
struct sockaddr *sa;
|
||||
sa_family_t af;
|
||||
struct socket *so;
|
||||
sa_family_t af;
|
||||
|
||||
GRE_DPRINTF(sc, "%s: enter\n", __func__);
|
||||
GRE_DPRINTF(sc, "enter\n");
|
||||
|
||||
af = sp->sp_src.ss_family;
|
||||
rc = fsocreate(af, &so, sp->sp_type, sp->sp_proto, curlwp, &fd);
|
||||
rc = fsocreate(af, NULL, sp->sp_type, sp->sp_proto, curlwp, &fd);
|
||||
if (rc != 0) {
|
||||
GRE_DPRINTF(sc, "%s: fsocreate failed\n", __func__);
|
||||
GRE_DPRINTF(sc, "fsocreate failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -475,32 +495,24 @@ gre_socreate(struct gre_softc *sc, struct gre_soparm *sp, int *fdout)
|
|||
goto out;
|
||||
}
|
||||
sa = mtod(m, struct sockaddr *);
|
||||
sockaddr_copy(sa, MIN(MLEN, sizeof(sp->sp_src)), sstosa(&sp->sp_src));
|
||||
sockaddr_copy(sa, MIN(MLEN, sizeof(sp->sp_src)), sstocsa(&sp->sp_src));
|
||||
m->m_len = sp->sp_src.ss_len;
|
||||
|
||||
#if 0
|
||||
/* XXX */
|
||||
GRE_DPRINTF(sc, "%s: bind 0x%08" PRIx32 " port %d\n", __func__,
|
||||
sin->sin_addr.s_addr, ntohs(sin->sin_port));
|
||||
#endif
|
||||
if ((rc = sobind(so, m, curlwp)) != 0) {
|
||||
GRE_DPRINTF(sc, "%s: sobind failed\n", __func__);
|
||||
GRE_DPRINTF(sc, "sobind failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((rc = gre_getsockname(so, m, curlwp)) != 0) {
|
||||
GRE_DPRINTF(sc, "%s: gre_getsockname\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
sockaddr_copy(sstosa(&sp->sp_src), sizeof(sp->sp_src), sa);
|
||||
|
||||
sockaddr_copy(sa, MIN(MLEN, sizeof(sp->sp_dst)), sstosa(&sp->sp_dst));
|
||||
sockaddr_copy(sa, MIN(MLEN, sizeof(sp->sp_dst)), sstocsa(&sp->sp_dst));
|
||||
m->m_len = sp->sp_dst.ss_len;
|
||||
|
||||
solock(so);
|
||||
if ((rc = soconnect(so, m, curlwp)) != 0) {
|
||||
GRE_DPRINTF(sc, "%s: soconnect failed\n", __func__);
|
||||
GRE_DPRINTF(sc, "soconnect failed\n");
|
||||
sounlock(so);
|
||||
goto out;
|
||||
}
|
||||
sounlock(so);
|
||||
|
||||
/* XXX convert to a (new) SOL_SOCKET call */
|
||||
*mtod(m, int *) = ip_gre_ttl;
|
||||
|
@ -510,12 +522,12 @@ gre_socreate(struct gre_softc *sc, struct gre_soparm *sp, int *fdout)
|
|||
rc = sosetopt(so, IPPROTO_IP, IP_TTL, m);
|
||||
m = NULL;
|
||||
if (rc != 0) {
|
||||
GRE_DPRINTF(sc, "%s: sosetopt ttl failed\n", __func__);
|
||||
GRE_DPRINTF(sc, "sosetopt ttl failed\n");
|
||||
rc = 0;
|
||||
}
|
||||
rc = sosetopt(so, SOL_SOCKET, SO_NOHEADER, m_intopt(so, 1));
|
||||
if (rc != 0) {
|
||||
GRE_DPRINTF(sc, "%s: sosetopt SO_NOHEADER failed\n", __func__);
|
||||
GRE_DPRINTF(sc, "sosetopt SO_NOHEADER failed\n");
|
||||
rc = 0;
|
||||
}
|
||||
out:
|
||||
|
@ -609,12 +621,10 @@ gre_soreceive(struct socket *so, struct mbuf **mp0)
|
|||
|
||||
KASSERT(pr->pr_flags & PR_ATOMIC);
|
||||
|
||||
solock(so);
|
||||
if (so->so_state & SS_ISCONFIRMING)
|
||||
(*pr->pr_usrreq)(so, PRU_RCVD, NULL, NULL, NULL, curlwp);
|
||||
restart:
|
||||
if ((error = sblock(&so->so_rcv, M_NOWAIT)) != 0) {
|
||||
sounlock(so);
|
||||
return error;
|
||||
}
|
||||
m = so->so_rcv.sb_mb;
|
||||
|
@ -785,63 +795,50 @@ gre_soreceive(struct socket *so, struct mbuf **mp0)
|
|||
|
||||
release:
|
||||
sbunlock(&so->so_rcv);
|
||||
sounlock(so);
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct socket *
|
||||
gre_reconf(struct gre_softc *sc, struct socket *so, lwp_t *l,
|
||||
const struct gre_soparm *newsoparm)
|
||||
gre_reconf(struct gre_softc *sc, const struct gre_soparm *newsoparm)
|
||||
{
|
||||
int rc;
|
||||
file_t *fp;
|
||||
struct ifnet *ifp = &sc->sc_if;
|
||||
|
||||
GRE_DPRINTF(sc, "%s: enter\n", __func__);
|
||||
GRE_DPRINTF(sc, "enter\n");
|
||||
|
||||
shutdown:
|
||||
if (sc->sc_soparm.sp_fd != -1) {
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
gre_upcall_remove(so);
|
||||
if (sc->sc_soparm.sp_so != NULL) {
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
gre_upcall_remove(sc->sc_soparm.sp_so);
|
||||
softint_disestablish(sc->sc_si);
|
||||
sc->sc_si = NULL;
|
||||
fd_getfile(sc->sc_soparm.sp_fd);
|
||||
fd_close(sc->sc_soparm.sp_fd);
|
||||
badsock:
|
||||
gre_fp_send(sc, GRE_M_DELFP, NULL);
|
||||
gre_clearconf(&sc->sc_soparm, false);
|
||||
so = NULL;
|
||||
}
|
||||
|
||||
if (newsoparm != NULL) {
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
sc->sc_soparm = *newsoparm;
|
||||
newsoparm = NULL;
|
||||
}
|
||||
|
||||
if (sc->sc_soparm.sp_fd != -1) {
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
rc = getsock(sc->sc_soparm.sp_fd, &fp);
|
||||
if (rc != 0)
|
||||
goto badsock;
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
so = (struct socket *)fp->f_data;
|
||||
if (sc->sc_soparm.sp_so != NULL) {
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
sc->sc_si = softint_establish(SOFTINT_NET, greintr, sc);
|
||||
gre_upcall_add(so, sc);
|
||||
fd_putfile(sc->sc_soparm.sp_fd);
|
||||
gre_upcall_add(sc->sc_soparm.sp_so, sc);
|
||||
if ((ifp->if_flags & IFF_UP) == 0) {
|
||||
GRE_DPRINTF(sc, "%s: down\n", __func__);
|
||||
GRE_DPRINTF(sc, "down\n");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
if (so != NULL)
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
if (sc->sc_soparm.sp_so != NULL)
|
||||
sc->sc_if.if_flags |= IFF_RUNNING;
|
||||
else {
|
||||
gre_bufq_purge(&sc->sc_snd);
|
||||
sc->sc_if.if_flags &= ~IFF_RUNNING;
|
||||
}
|
||||
return so;
|
||||
return sc->sc_soparm.sp_so;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -895,7 +892,7 @@ gre_input(struct gre_softc *sc, struct mbuf *m, int hlen,
|
|||
break;
|
||||
#endif
|
||||
default: /* others not yet supported */
|
||||
GRE_DPRINTF(sc, "%s: unhandled ethertype 0x%04x\n", __func__,
|
||||
GRE_DPRINTF(sc, "unhandled ethertype 0x%04x\n",
|
||||
ntohs(gh->ptype));
|
||||
sc->sc_if.if_noproto++;
|
||||
return 0;
|
||||
|
@ -957,7 +954,7 @@ gre_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
|
|||
|
||||
m->m_flags &= ~(M_BCAST|M_MCAST);
|
||||
|
||||
GRE_DPRINTF(sc, "%s: dst->sa_family=%d\n", __func__, dst->sa_family);
|
||||
GRE_DPRINTF(sc, "dst->sa_family=%d\n", dst->sa_family);
|
||||
switch (dst->sa_family) {
|
||||
case AF_INET:
|
||||
ip = mtod(m, struct ip *);
|
||||
|
@ -1055,99 +1052,127 @@ out:
|
|||
}
|
||||
|
||||
static void
|
||||
gre_closef(file_t **fpp)
|
||||
gre_fp_recvloop(void *arg)
|
||||
{
|
||||
file_t *fp = *fpp;
|
||||
struct gre_softc *sc = arg;
|
||||
|
||||
closef(fp);
|
||||
*fpp = NULL;
|
||||
mutex_enter(&sc->sc_mtx);
|
||||
while (gre_fp_recv(sc))
|
||||
;
|
||||
mutex_exit(&sc->sc_mtx);
|
||||
kthread_exit(0);
|
||||
}
|
||||
|
||||
static bool
|
||||
gre_fp_recv(struct gre_softc *sc)
|
||||
{
|
||||
int fd, ofd, rc;
|
||||
file_t *fp;
|
||||
|
||||
fp = sc->sc_fp;
|
||||
ofd = sc->sc_fd;
|
||||
fd = -1;
|
||||
|
||||
switch (sc->sc_msg) {
|
||||
case GRE_M_STOP:
|
||||
cv_signal(&sc->sc_fp_condvar);
|
||||
return false;
|
||||
case GRE_M_SETFP:
|
||||
mutex_exit(&sc->sc_mtx);
|
||||
rc = fd_dup(fp, 0, &fd, 0);
|
||||
mutex_enter(&sc->sc_mtx);
|
||||
if (rc != 0) {
|
||||
sc->sc_msg = GRE_M_ERR;
|
||||
break;
|
||||
}
|
||||
/*FALLTHROUGH*/
|
||||
case GRE_M_DELFP:
|
||||
mutex_exit(&sc->sc_mtx);
|
||||
if (ofd != -1 && fd_getfile(ofd) != NULL)
|
||||
fd_close(ofd);
|
||||
mutex_enter(&sc->sc_mtx);
|
||||
sc->sc_fd = fd;
|
||||
sc->sc_msg = GRE_M_OK;
|
||||
break;
|
||||
default:
|
||||
gre_fp_wait(sc);
|
||||
return true;
|
||||
}
|
||||
cv_signal(&sc->sc_fp_condvar);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
gre_fp_send(struct gre_softc *sc, enum gre_msg msg, file_t *fp)
|
||||
{
|
||||
bool rc;
|
||||
|
||||
mutex_enter(&sc->sc_mtx);
|
||||
while (sc->sc_msg != GRE_M_NONE)
|
||||
gre_fp_wait(sc);
|
||||
sc->sc_fp = fp;
|
||||
sc->sc_msg = msg;
|
||||
cv_signal(&sc->sc_fp_condvar);
|
||||
while (sc->sc_msg != GRE_M_STOP && sc->sc_msg != GRE_M_OK &&
|
||||
sc->sc_msg != GRE_M_ERR)
|
||||
gre_fp_wait(sc);
|
||||
rc = (sc->sc_msg != GRE_M_ERR);
|
||||
sc->sc_msg = GRE_M_NONE;
|
||||
cv_signal(&sc->sc_fp_condvar);
|
||||
mutex_exit(&sc->sc_mtx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
gre_ssock(struct ifnet *ifp, struct gre_soparm *sp, int fd)
|
||||
{
|
||||
int error, kfd;
|
||||
int error = 0;
|
||||
const struct protosw *pr;
|
||||
file_t *fp;
|
||||
struct gre_softc *sc = ifp->if_softc;
|
||||
struct proc *kp;
|
||||
struct socket *so;
|
||||
struct sockaddr_storage dst, src;
|
||||
|
||||
/* getsock() will FILE_USE() and unlock the descriptor for us */
|
||||
if ((fp = fd_getfile(fd)) == NULL) {
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
return EINVAL;
|
||||
}
|
||||
if (fp->f_type != DTYPE_SOCKET) {
|
||||
fd_putfile(fd);
|
||||
return ENOTSOCK;
|
||||
}
|
||||
if ((error = getsock(fd, &fp)) != 0)
|
||||
return error;
|
||||
|
||||
/* Increase reference count. Now that our reference to
|
||||
* the file descriptor is counted, this thread can release
|
||||
* our "use" of the descriptor, but it will not be destroyed
|
||||
* by some other thread's action. This thread needs to
|
||||
* release its use, too, because one and only one thread
|
||||
* can have use of the descriptor at once. The kernel
|
||||
* thread will pick up the use if it needs it.
|
||||
*/
|
||||
mutex_enter(&fp->f_lock);
|
||||
fp->f_count++;
|
||||
mutex_exit(&fp->f_lock);
|
||||
fd_putfile(fd);
|
||||
GRE_DPRINTF(sc, "%s: l.%d f_count %d\n", __func__, __LINE__,
|
||||
fp->f_count);
|
||||
|
||||
kp = sc->sc_lwp->l_proc;
|
||||
while ((error = fd_alloc(kp, 0, &kfd)) != 0 && error == ENOSPC)
|
||||
fd_tryexpand(kp);
|
||||
if (error != 0)
|
||||
goto closef;
|
||||
fd_affix(kp, fp, kfd);
|
||||
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
|
||||
so = (struct socket *)fp->f_data;
|
||||
pr = so->so_proto;
|
||||
|
||||
GRE_DPRINTF(sc, "type %d, proto %d\n", pr->pr_type, pr->pr_protocol);
|
||||
|
||||
if ((pr->pr_flags & PR_ATOMIC) == 0 ||
|
||||
(sp->sp_type != 0 && pr->pr_type != sp->sp_type) ||
|
||||
(sp->sp_proto != 0 && pr->pr_protocol != 0 &&
|
||||
pr->pr_protocol != sp->sp_proto)) {
|
||||
GRE_DPRINTF(sc, "%s: l.%d, type %d, proto %d\n", __func__,
|
||||
__LINE__, pr->pr_type, pr->pr_protocol);
|
||||
error = EINVAL;
|
||||
goto release;
|
||||
goto err;
|
||||
}
|
||||
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
|
||||
/* check address */
|
||||
if ((error = gre_getnames(so, curlwp, &src, &dst)) != 0)
|
||||
goto release;
|
||||
goto err;
|
||||
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
|
||||
if (error != 0)
|
||||
goto release;
|
||||
if (!gre_fp_send(sc, GRE_M_SETFP, fp)) {
|
||||
error = EBUSY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
|
||||
sp->sp_src = src;
|
||||
sp->sp_dst = dst;
|
||||
/* fp does not any longer belong to this thread. */
|
||||
sp->sp_fd = kfd;
|
||||
|
||||
/* XXX print src & dst */
|
||||
sp->sp_so = so;
|
||||
|
||||
return 0;
|
||||
release:
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
fd_abort(kp, fp, kfd);
|
||||
return error;
|
||||
closef:
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
gre_closef(&fp);
|
||||
err:
|
||||
fd_putfile(fd);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -1182,9 +1207,9 @@ gre_clearconf(struct gre_soparm *sp, bool force)
|
|||
sockaddr_any(sstosa(&sp->sp_src)));
|
||||
sockaddr_copy(sstosa(&sp->sp_dst), sizeof(sp->sp_dst),
|
||||
sockaddr_any(sstosa(&sp->sp_dst)));
|
||||
sp->sp_bysock = 0;
|
||||
sp->sp_bysock = false;
|
||||
}
|
||||
sp->sp_fd = -1;
|
||||
sp->sp_so = NULL; /* XXX */
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1198,7 +1223,7 @@ gre_ioctl_lock(struct gre_softc *sc)
|
|||
if (sc->sc_state != GRE_S_IDLE) {
|
||||
cv_signal(&sc->sc_condvar);
|
||||
mutex_exit(&sc->sc_mtx);
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
|
@ -1232,7 +1257,7 @@ gre_ioctl(struct ifnet *ifp, const u_long cmd, void *data)
|
|||
|
||||
ifr = data;
|
||||
|
||||
GRE_DPRINTF(sc, "%s: l.%d, cmd %lu\n", __func__, __LINE__, cmd);
|
||||
GRE_DPRINTF(sc, "cmd %lu\n", cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCSIFFLAGS:
|
||||
|
@ -1255,20 +1280,20 @@ gre_ioctl(struct ifnet *ifp, const u_long cmd, void *data)
|
|||
}
|
||||
|
||||
if ((error = gre_ioctl_lock(sc)) != 0) {
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
return error;
|
||||
}
|
||||
s = splnet();
|
||||
|
||||
sp0 = sc->sc_soparm;
|
||||
sp0.sp_fd = -1;
|
||||
sp0.sp_so = NULL;
|
||||
sp = &sp0;
|
||||
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCSIFADDR:
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
if ((ifp->if_flags & IFF_UP) != 0)
|
||||
break;
|
||||
gre_clearconf(sp, false);
|
||||
|
@ -1293,11 +1318,11 @@ gre_ioctl(struct ifnet *ifp, const u_long cmd, void *data)
|
|||
sp->sp_type = SOCK_RAW;
|
||||
break;
|
||||
default:
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
gre_clearconf(sp, false);
|
||||
if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) ==
|
||||
(IFF_UP|IFF_RUNNING) &&
|
||||
|
@ -1386,10 +1411,7 @@ gre_ioctl(struct ifnet *ifp, const u_long cmd, void *data)
|
|||
case GRESADDRS:
|
||||
case GRESADDRD:
|
||||
gre_clearconf(sp, false);
|
||||
/*
|
||||
* set tunnel endpoints, compute a less specific route
|
||||
* to the remote end and mark if as up
|
||||
*/
|
||||
/* set tunnel endpoints and mark interface as up */
|
||||
switch (cmd) {
|
||||
case GRESADDRS:
|
||||
sockaddr_copy(sstosa(&sp->sp_src),
|
||||
|
@ -1408,26 +1430,26 @@ gre_ioctl(struct ifnet *ifp, const u_long cmd, void *data)
|
|||
}
|
||||
/* let gre_socreate() check the rest */
|
||||
mksocket:
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
/* If we're administratively down, or the configuration
|
||||
* is empty, there's no use creating a socket.
|
||||
*/
|
||||
if ((ifp->if_flags & IFF_UP) == 0 || gre_is_nullconf(sp))
|
||||
goto sendconf;
|
||||
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
fd = 0;
|
||||
error = gre_socreate(sc, sp, &fd);
|
||||
if (error != 0)
|
||||
break;
|
||||
|
||||
setsock:
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
|
||||
error = gre_ssock(ifp, sp, fd);
|
||||
|
||||
if (cmd != GRESSOCK) {
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
/* XXX v. dodgy */
|
||||
if (fd_getfile(fd) != NULL)
|
||||
fd_close(fd);
|
||||
|
@ -1435,9 +1457,9 @@ gre_ioctl(struct ifnet *ifp, const u_long cmd, void *data)
|
|||
|
||||
if (error == 0) {
|
||||
sendconf:
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
ifp->if_flags &= ~IFF_RUNNING;
|
||||
sc->sc_so = gre_reconf(sc, sc->sc_so, sc->sc_lwp, sp);
|
||||
gre_reconf(sc, sp);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -1448,20 +1470,20 @@ gre_ioctl(struct ifnet *ifp, const u_long cmd, void *data)
|
|||
ifreq_setaddr(cmd, ifr, sstosa(&sp->sp_dst));
|
||||
break;
|
||||
case GREDSOCK:
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
if (sp->sp_bysock)
|
||||
ifp->if_flags &= ~IFF_UP;
|
||||
gre_clearconf(sp, false);
|
||||
goto mksocket;
|
||||
case GRESSOCK:
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
gre_clearconf(sp, true);
|
||||
fd = (int)ifr->ifr_value;
|
||||
sp->sp_bysock = 1;
|
||||
sp->sp_bysock = true;
|
||||
ifp->if_flags |= IFF_UP;
|
||||
goto setsock;
|
||||
case SIOCSLIFPHYADDR:
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
if (lifr->addr.ss_family != lifr->dstaddr.ss_family) {
|
||||
error = EAFNOSUPPORT;
|
||||
break;
|
||||
|
@ -1470,15 +1492,15 @@ gre_ioctl(struct ifnet *ifp, const u_long cmd, void *data)
|
|||
sstosa(&lifr->addr));
|
||||
sockaddr_copy(sstosa(&sp->sp_dst), sizeof(sp->sp_dst),
|
||||
sstosa(&lifr->dstaddr));
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
goto checkaddr;
|
||||
case SIOCDIFPHYADDR:
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
gre_clearconf(sp, true);
|
||||
ifp->if_flags &= ~IFF_UP;
|
||||
goto mksocket;
|
||||
case SIOCGLIFPHYADDR:
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
if (gre_is_nullconf(sp)) {
|
||||
error = EADDRNOTAVAIL;
|
||||
break;
|
||||
|
@ -1487,14 +1509,14 @@ gre_ioctl(struct ifnet *ifp, const u_long cmd, void *data)
|
|||
sstosa(&sp->sp_src));
|
||||
sockaddr_copy(sstosa(&lifr->dstaddr), sizeof(lifr->dstaddr),
|
||||
sstosa(&sp->sp_dst));
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
out:
|
||||
GRE_DPRINTF(sc, "%s: l.%d\n", __func__, __LINE__);
|
||||
GRE_DPRINTF(sc, "\n");
|
||||
splx(s);
|
||||
gre_ioctl_unlock(sc);
|
||||
return error;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: if_gre.h,v 1.36 2008/05/04 13:13:36 martin Exp $ */
|
||||
/* $NetBSD: if_gre.h,v 1.37 2008/05/09 20:14:07 dyoung Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
|
@ -41,12 +41,12 @@
|
|||
|
||||
#ifdef _KERNEL
|
||||
struct gre_soparm {
|
||||
struct socket *sp_so;
|
||||
struct sockaddr_storage sp_src; /* source of gre packets */
|
||||
struct sockaddr_storage sp_dst; /* destination of gre packets */
|
||||
int sp_type; /* encapsulating socket type */
|
||||
int sp_proto; /* encapsulating protocol */
|
||||
int sp_fd;
|
||||
int sp_bysock; /* encapsulation configured by passing
|
||||
bool sp_bysock; /* encapsulation configured by passing
|
||||
* socket, not by SIOCSLIFPHYADDR
|
||||
*/
|
||||
};
|
||||
|
@ -70,18 +70,26 @@ struct gre_bufq {
|
|||
|
||||
MALLOC_DECLARE(M_GRE_BUFQ);
|
||||
|
||||
enum gre_msg {
|
||||
GRE_M_NONE = 0
|
||||
, GRE_M_SETFP
|
||||
, GRE_M_DELFP
|
||||
, GRE_M_STOP
|
||||
, GRE_M_OK
|
||||
, GRE_M_ERR
|
||||
};
|
||||
|
||||
struct gre_softc {
|
||||
struct ifnet sc_if;
|
||||
kmutex_t sc_mtx;
|
||||
kcondvar_t sc_condvar;
|
||||
kcondvar_t sc_fp_condvar;
|
||||
struct gre_bufq sc_snd;
|
||||
struct gre_soparm sc_soparm;
|
||||
struct lwp *sc_lwp;
|
||||
volatile enum gre_state sc_state;
|
||||
volatile int sc_waiters;
|
||||
volatile int sc_upcalls;
|
||||
volatile int sc_fp_waiters;
|
||||
void *sc_si;
|
||||
struct socket *sc_so;
|
||||
|
||||
struct evcnt sc_recv_ev;
|
||||
struct evcnt sc_send_ev;
|
||||
|
@ -91,6 +99,9 @@ struct gre_softc {
|
|||
struct evcnt sc_pullup_ev;
|
||||
struct evcnt sc_unsupp_ev;
|
||||
struct evcnt sc_oflow_ev;
|
||||
file_t * volatile sc_fp;
|
||||
volatile enum gre_msg sc_msg;
|
||||
int sc_fd;
|
||||
};
|
||||
|
||||
struct gre_h {
|
||||
|
|
Loading…
Reference in New Issue