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:
dyoung 2008-05-09 20:14:07 +00:00
parent a790b941e6
commit 5198e29b4c
2 changed files with 219 additions and 186 deletions

View File

@ -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;

View File

@ -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 {