Changeset View
Changeset View
Standalone View
Standalone View
head/sys/net/if_me.c
Show All 31 Lines | |||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/libkern.h> | #include <sys/libkern.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <sys/priv.h> | #include <sys/priv.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/protosw.h> | |||||
#include <sys/rmlock.h> | #include <sys/rmlock.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/sockio.h> | #include <sys/sockio.h> | ||||
#include <sys/sx.h> | #include <sys/sx.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/syslog.h> | #include <sys/syslog.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | |||||
static VNET_DEFINE(struct if_clone *, me_cloner); | static VNET_DEFINE(struct if_clone *, me_cloner); | ||||
#define V_me_cloner VNET(me_cloner) | #define V_me_cloner VNET(me_cloner) | ||||
static void me_qflush(struct ifnet *); | static void me_qflush(struct ifnet *); | ||||
static int me_transmit(struct ifnet *, struct mbuf *); | static int me_transmit(struct ifnet *, struct mbuf *); | ||||
static int me_ioctl(struct ifnet *, u_long, caddr_t); | static int me_ioctl(struct ifnet *, u_long, caddr_t); | ||||
static int me_output(struct ifnet *, struct mbuf *, | static int me_output(struct ifnet *, struct mbuf *, | ||||
const struct sockaddr *, struct route *); | const struct sockaddr *, struct route *); | ||||
static int me_input(struct mbuf **, int *, int); | static int me_input(struct mbuf *, int, int, void *); | ||||
static int me_set_tunnel(struct ifnet *, struct sockaddr_in *, | static int me_set_tunnel(struct ifnet *, struct sockaddr_in *, | ||||
struct sockaddr_in *); | struct sockaddr_in *); | ||||
static void me_delete_tunnel(struct ifnet *); | static void me_delete_tunnel(struct ifnet *); | ||||
static int me_encapcheck(const struct mbuf *, int, int, void *); | |||||
#define ME_MINLEN (sizeof(struct ip) + sizeof(struct mobhdr) -\ | |||||
sizeof(in_addr_t)) | |||||
static const struct encap_config ipv4_encap_cfg = { | |||||
.proto = IPPROTO_MOBILE, | |||||
.min_length = ME_MINLEN, | |||||
.exact_match = (sizeof(in_addr_t) << 4) + 8, | |||||
.check = me_encapcheck, | |||||
.input = me_input | |||||
}; | |||||
SYSCTL_DECL(_net_link); | SYSCTL_DECL(_net_link); | ||||
static SYSCTL_NODE(_net_link, IFT_TUNNEL, me, CTLFLAG_RW, 0, | static SYSCTL_NODE(_net_link, IFT_TUNNEL, me, CTLFLAG_RW, 0, | ||||
"Minimal Encapsulation for IP (RFC 2004)"); | "Minimal Encapsulation for IP (RFC 2004)"); | ||||
#ifndef MAX_ME_NEST | #ifndef MAX_ME_NEST | ||||
#define MAX_ME_NEST 1 | #define MAX_ME_NEST 1 | ||||
#endif | #endif | ||||
static VNET_DEFINE(int, max_me_nesting) = MAX_ME_NEST; | static VNET_DEFINE(int, max_me_nesting) = MAX_ME_NEST; | ||||
#define V_max_me_nesting VNET(max_me_nesting) | #define V_max_me_nesting VNET(max_me_nesting) | ||||
SYSCTL_INT(_net_link_me, OID_AUTO, max_nesting, CTLFLAG_RW | CTLFLAG_VNET, | SYSCTL_INT(_net_link_me, OID_AUTO, max_nesting, CTLFLAG_RW | CTLFLAG_VNET, | ||||
&VNET_NAME(max_me_nesting), 0, "Max nested tunnels"); | &VNET_NAME(max_me_nesting), 0, "Max nested tunnels"); | ||||
extern struct domain inetdomain; | |||||
static const struct protosw in_mobile_protosw = { | |||||
.pr_type = SOCK_RAW, | |||||
.pr_domain = &inetdomain, | |||||
.pr_protocol = IPPROTO_MOBILE, | |||||
.pr_flags = PR_ATOMIC|PR_ADDR, | |||||
.pr_input = me_input, | |||||
.pr_output = rip_output, | |||||
.pr_ctlinput = rip_ctlinput, | |||||
.pr_ctloutput = rip_ctloutput, | |||||
.pr_usrreqs = &rip_usrreqs | |||||
}; | |||||
static void | static void | ||||
vnet_me_init(const void *unused __unused) | vnet_me_init(const void *unused __unused) | ||||
{ | { | ||||
LIST_INIT(&V_me_softc_list); | LIST_INIT(&V_me_softc_list); | ||||
ME_LIST_LOCK_INIT(); | ME_LIST_LOCK_INIT(); | ||||
V_me_cloner = if_clone_simple(mename, me_clone_create, | V_me_cloner = if_clone_simple(mename, me_clone_create, | ||||
me_clone_destroy, 0); | me_clone_destroy, 0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 165 Lines • ▼ Show 20 Lines | me_encapcheck(const struct mbuf *m, int off, int proto, void *arg) | ||||
int ret; | int ret; | ||||
sc = (struct me_softc *)arg; | sc = (struct me_softc *)arg; | ||||
if ((ME2IFP(sc)->if_flags & IFF_UP) == 0) | if ((ME2IFP(sc)->if_flags & IFF_UP) == 0) | ||||
return (0); | return (0); | ||||
M_ASSERTPKTHDR(m); | M_ASSERTPKTHDR(m); | ||||
if (m->m_pkthdr.len < sizeof(struct ip) + sizeof(struct mobhdr) - | |||||
sizeof(struct in_addr)) | |||||
return (0); | |||||
ret = 0; | ret = 0; | ||||
ME_RLOCK(sc); | ME_RLOCK(sc); | ||||
if (ME_READY(sc)) { | if (ME_READY(sc)) { | ||||
ip = mtod(m, struct ip *); | ip = mtod(m, struct ip *); | ||||
if (sc->me_src.s_addr == ip->ip_dst.s_addr && | if (sc->me_src.s_addr == ip->ip_dst.s_addr && | ||||
sc->me_dst.s_addr == ip->ip_src.s_addr) | sc->me_dst.s_addr == ip->ip_src.s_addr) | ||||
ret = 32 * 2; | ret = 32 * 2 + 8; | ||||
} | } | ||||
ME_RUNLOCK(sc); | ME_RUNLOCK(sc); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | static int | ||||
me_set_tunnel(struct ifnet *ifp, struct sockaddr_in *src, | me_set_tunnel(struct ifnet *ifp, struct sockaddr_in *src, | ||||
struct sockaddr_in *dst) | struct sockaddr_in *dst) | ||||
Show All 15 Lines | me_set_tunnel(struct ifnet *ifp, struct sockaddr_in *src, | ||||
ME_LIST_UNLOCK(); | ME_LIST_UNLOCK(); | ||||
ME_WLOCK(sc); | ME_WLOCK(sc); | ||||
sc->me_dst = dst->sin_addr; | sc->me_dst = dst->sin_addr; | ||||
sc->me_src = src->sin_addr; | sc->me_src = src->sin_addr; | ||||
ME_WUNLOCK(sc); | ME_WUNLOCK(sc); | ||||
if (sc->me_ecookie == NULL) | if (sc->me_ecookie == NULL) | ||||
sc->me_ecookie = encap_attach_func(AF_INET, IPPROTO_MOBILE, | sc->me_ecookie = ip_encap_attach(&ipv4_encap_cfg, | ||||
me_encapcheck, &in_mobile_protosw, sc); | sc, M_WAITOK); | ||||
if (sc->me_ecookie != NULL) { | if (sc->me_ecookie != NULL) { | ||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | ifp->if_drv_flags |= IFF_DRV_RUNNING; | ||||
if_link_state_change(ifp, LINK_STATE_UP); | if_link_state_change(ifp, LINK_STATE_UP); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
me_delete_tunnel(struct ifnet *ifp) | me_delete_tunnel(struct ifnet *ifp) | ||||
{ | { | ||||
struct me_softc *sc = ifp->if_softc; | struct me_softc *sc = ifp->if_softc; | ||||
sx_assert(&me_ioctl_sx, SA_XLOCKED); | sx_assert(&me_ioctl_sx, SA_XLOCKED); | ||||
if (sc->me_ecookie != NULL) | if (sc->me_ecookie != NULL) | ||||
encap_detach(sc->me_ecookie); | ip_encap_detach(sc->me_ecookie); | ||||
sc->me_ecookie = NULL; | sc->me_ecookie = NULL; | ||||
ME_WLOCK(sc); | ME_WLOCK(sc); | ||||
sc->me_src.s_addr = 0; | sc->me_src.s_addr = 0; | ||||
sc->me_dst.s_addr = 0; | sc->me_dst.s_addr = 0; | ||||
ME_WUNLOCK(sc); | ME_WUNLOCK(sc); | ||||
ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | ||||
if_link_state_change(ifp, LINK_STATE_DOWN); | if_link_state_change(ifp, LINK_STATE_DOWN); | ||||
} | } | ||||
static uint16_t | static uint16_t | ||||
me_in_cksum(uint16_t *p, int nwords) | me_in_cksum(uint16_t *p, int nwords) | ||||
{ | { | ||||
uint32_t sum = 0; | uint32_t sum = 0; | ||||
while (nwords-- > 0) | while (nwords-- > 0) | ||||
sum += *p++; | sum += *p++; | ||||
sum = (sum >> 16) + (sum & 0xffff); | sum = (sum >> 16) + (sum & 0xffff); | ||||
sum += (sum >> 16); | sum += (sum >> 16); | ||||
return (~sum); | return (~sum); | ||||
} | } | ||||
int | static int | ||||
me_input(struct mbuf **mp, int *offp, int proto) | me_input(struct mbuf *m, int off, int proto, void *arg) | ||||
{ | { | ||||
struct me_softc *sc; | struct me_softc *sc = arg; | ||||
struct mobhdr *mh; | struct mobhdr *mh; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct mbuf *m; | |||||
struct ip *ip; | struct ip *ip; | ||||
int hlen; | int hlen; | ||||
m = *mp; | |||||
sc = encap_getarg(m); | |||||
KASSERT(sc != NULL, ("encap_getarg returned NULL")); | |||||
ifp = ME2IFP(sc); | ifp = ME2IFP(sc); | ||||
/* checks for short packets */ | /* checks for short packets */ | ||||
hlen = sizeof(struct mobhdr); | hlen = sizeof(struct mobhdr); | ||||
if (m->m_pkthdr.len < sizeof(struct ip) + hlen) | if (m->m_pkthdr.len < sizeof(struct ip) + hlen) | ||||
hlen -= sizeof(struct in_addr); | hlen -= sizeof(struct in_addr); | ||||
if (m->m_len < sizeof(struct ip) + hlen) | if (m->m_len < sizeof(struct ip) + hlen) | ||||
m = m_pullup(m, sizeof(struct ip) + hlen); | m = m_pullup(m, sizeof(struct ip) + hlen); | ||||
▲ Show 20 Lines • Show All 227 Lines • Show Last 20 Lines |