I refactored pppx(4). The idea is to use pipex(4) as it was designed.
No one holds pipex_session outside pipex(4) so pipex_timer() calls are
safe. Unfortunately, this way gives some performance impact, because we
need to call pipex_lookup_by_session_id() in some places. This impact
will gone after pipex_session becames safely shared between multiple
holders and this is my next goal.
Index: sys/net/if_pppx.c
===================================================================
RCS file: /cvs/src/sys/net/if_pppx.c,v
retrieving revision 1.77
diff -u -p -r1.77 if_pppx.c
--- sys/net/if_pppx.c 26 Mar 2020 16:50:46 -0000 1.77
+++ sys/net/if_pppx.c 31 Mar 2020 13:28:54 -0000
@@ -155,8 +155,8 @@ struct pppx_if {
int pxi_unit;
struct ifnet pxi_if;
struct pppx_dev *pxi_dev;
- struct pipex_session pxi_session;
struct pipex_iface_context pxi_ifcontext;
+ int pxi_ppp_id;
};
static inline int
@@ -178,7 +178,8 @@ int pppx_del_session(struct pppx_dev *,
int pppx_set_session_descr(struct pppx_dev *,
struct pipex_session_descr_req *);
-void pppx_if_destroy(struct pppx_dev *, struct pppx_if *);
+int pppx_if_destroy(struct pppx_dev *, struct pppx_if *,
+ struct pipex_session_close_req *);
void pppx_if_start(struct ifnet *);
int pppx_if_output(struct ifnet *, struct mbuf *,
struct sockaddr *, struct rtentry *);
@@ -587,7 +588,7 @@ pppxclose(dev_t dev, int flags, int mode
/* XXX */
NET_LOCK();
while ((pxi = LIST_FIRST(&pxd->pxd_pxis)))
- pppx_if_destroy(pxd, pxi);
+ pppx_if_destroy(pxd, pxi, NULL);
NET_UNLOCK();
LIST_REMOVE(pxd, pxd_entry);
@@ -655,160 +656,14 @@ int
pppx_add_session(struct pppx_dev *pxd, struct pipex_session_req *req)
{
struct pppx_if *pxi;
- struct pipex_session *session;
- struct pipex_hash_head *chain;
struct ifnet *ifp;
int unit, error = 0;
struct in_ifaddr *ia;
struct sockaddr_in ifaddr;
-#ifdef PIPEX_PPPOE
- struct ifnet *over_ifp = NULL;
-#endif
-
- switch (req->pr_protocol) {
-#ifdef PIPEX_PPPOE
- case PIPEX_PROTO_PPPOE:
- over_ifp = ifunit(req->pr_proto.pppoe.over_ifname);
- if (over_ifp == NULL)
- return (EINVAL);
- if (req->pr_peer_address.ss_family != AF_UNSPEC)
- return (EINVAL);
- break;
-#endif
-#if defined(PIPEX_PPTP) || defined(PIPEX_L2TP)
- case PIPEX_PROTO_PPTP:
- case PIPEX_PROTO_L2TP:
- switch (req->pr_peer_address.ss_family) {
- case AF_INET:
- if (req->pr_peer_address.ss_len != sizeof(struct
sockaddr_in))
- return (EINVAL);
- break;
-#ifdef INET6
- case AF_INET6:
- if (req->pr_peer_address.ss_len != sizeof(struct
sockaddr_in6))
- return (EINVAL);
- break;
-#endif
- default:
- return (EPROTONOSUPPORT);
- }
- if (req->pr_peer_address.ss_family !=
- req->pr_local_address.ss_family ||
- req->pr_peer_address.ss_len !=
- req->pr_local_address.ss_len)
- return (EINVAL);
- break;
-#endif /* defined(PIPEX_PPTP) || defined(PIPEX_L2TP) */
- default:
- return (EPROTONOSUPPORT);
- }
pxi = pool_get(pppx_if_pl, PR_WAITOK | PR_ZERO);
- if (pxi == NULL)
- return (ENOMEM);
-
- session = &pxi->pxi_session;
ifp = &pxi->pxi_if;
- /* fake a pipex interface context */
- session->pipex_iface = &pxi->pxi_ifcontext;
- session->pipex_iface->ifnet_this = ifp;
- session->pipex_iface->pipexmode = PIPEX_ENABLED;
-
- /* setup session */
- session->state = PIPEX_STATE_OPENED;
- session->protocol = req->pr_protocol;
- session->session_id = req->pr_session_id;
- session->peer_session_id = req->pr_peer_session_id;
- session->peer_mru = req->pr_peer_mru;
- session->timeout_sec = req->pr_timeout_sec;
- session->ppp_flags = req->pr_ppp_flags;
- session->ppp_id = req->pr_ppp_id;
-
- session->ip_forward = 1;
-
- session->ip_address.sin_family = AF_INET;
- session->ip_address.sin_len = sizeof(struct sockaddr_in);
- session->ip_address.sin_addr = req->pr_ip_address;
-
- session->ip_netmask.sin_family = AF_INET;
- session->ip_netmask.sin_len = sizeof(struct sockaddr_in);
- session->ip_netmask.sin_addr = req->pr_ip_netmask;
-
- if (session->ip_netmask.sin_addr.s_addr == 0L)
- session->ip_netmask.sin_addr.s_addr = 0xffffffffL;
- session->ip_address.sin_addr.s_addr &=
- session->ip_netmask.sin_addr.s_addr;
-
- if (req->pr_peer_address.ss_len > 0)
- memcpy(&session->peer, &req->pr_peer_address,
- MIN(req->pr_peer_address.ss_len, sizeof(session->peer)));
- if (req->pr_local_address.ss_len > 0)
- memcpy(&session->local, &req->pr_local_address,
- MIN(req->pr_local_address.ss_len, sizeof(session->local)));
-#ifdef PIPEX_PPPOE
- if (req->pr_protocol == PIPEX_PROTO_PPPOE)
- session->proto.pppoe.over_ifidx = over_ifp->if_index;
-#endif
-#ifdef PIPEX_PPTP
- if (req->pr_protocol == PIPEX_PROTO_PPTP) {
- struct pipex_pptp_session *sess_pptp = &session->proto.pptp;
-
- sess_pptp->snd_gap = 0;
- sess_pptp->rcv_gap = 0;
- sess_pptp->snd_una = req->pr_proto.pptp.snd_una;
- sess_pptp->snd_nxt = req->pr_proto.pptp.snd_nxt;
- sess_pptp->rcv_nxt = req->pr_proto.pptp.rcv_nxt;
- sess_pptp->rcv_acked = req->pr_proto.pptp.rcv_acked;
-
- sess_pptp->winsz = req->pr_proto.pptp.winsz;
- sess_pptp->maxwinsz = req->pr_proto.pptp.maxwinsz;
- sess_pptp->peer_maxwinsz = req->pr_proto.pptp.peer_maxwinsz;
- /* last ack number */
- sess_pptp->ul_snd_una = sess_pptp->snd_una - 1;
- }
-#endif
-#ifdef PIPEX_L2TP
- if (req->pr_protocol == PIPEX_PROTO_L2TP) {
- struct pipex_l2tp_session *sess_l2tp = &session->proto.l2tp;
-
- /* session keys */
- sess_l2tp->tunnel_id = req->pr_proto.l2tp.tunnel_id;
- sess_l2tp->peer_tunnel_id = req->pr_proto.l2tp.peer_tunnel_id;
-
- /* protocol options */
- sess_l2tp->option_flags = req->pr_proto.l2tp.option_flags;
-
- /* initial state of dynamic context */
- sess_l2tp->ns_gap = sess_l2tp->nr_gap = 0;
- sess_l2tp->ns_nxt = req->pr_proto.l2tp.ns_nxt;
- sess_l2tp->nr_nxt = req->pr_proto.l2tp.nr_nxt;
- sess_l2tp->ns_una = req->pr_proto.l2tp.ns_una;
- sess_l2tp->nr_acked = req->pr_proto.l2tp.nr_acked;
- /* last ack number */
- sess_l2tp->ul_ns_una = sess_l2tp->ns_una - 1;
- }
-#endif
-#ifdef PIPEX_MPPE
- if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ACCEPTED) != 0)
- pipex_session_init_mppe_recv(session,
- req->pr_mppe_recv.stateless, req->pr_mppe_recv.keylenbits,
- req->pr_mppe_recv.master_key);
- if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ENABLED) != 0)
- pipex_session_init_mppe_send(session,
- req->pr_mppe_send.stateless, req->pr_mppe_send.keylenbits,
- req->pr_mppe_send.master_key);
-
- if (pipex_session_is_mppe_required(session)) {
- if (!pipex_session_is_mppe_enabled(session) ||
- !pipex_session_is_mppe_accepted(session)) {
- pool_put(pppx_if_pl, pxi);
- return (EINVAL);
- }
- }
-#endif
-
- /* try to set the interface up */
rw_enter_write(&pppx_ifs_lk);
unit = pppx_if_next_unit();
if (unit < 0) {
@@ -822,6 +677,7 @@ pppx_add_session(struct pppx_dev *pxd, s
pxi->pxi_key.pxik_session_id = req->pr_session_id;
pxi->pxi_key.pxik_protocol = req->pr_protocol;
pxi->pxi_dev = pxd;
+ pxi->pxi_ppp_id = req->pr_ppp_id;
/* this is safe without splnet since we're not modifying it */
if (RBT_FIND(pppx_ifs, &pppx_ifs, pxi) != NULL) {
@@ -848,24 +704,20 @@ pppx_add_session(struct pppx_dev *pxd, s
ifp->if_softc = pxi;
/* ifp->if_rdomain = req->pr_rdomain; */
- /* hook up pipex context */
- chain = PIPEX_ID_HASHTABLE(session->session_id);
- LIST_INSERT_HEAD(chain, session, id_chain);
- LIST_INSERT_HEAD(&pipex_session_list, session, session_list);
-#if defined(PIPEX_PPTP) || defined(PIPEX_L2TP)
- switch (req->pr_protocol) {
- case PIPEX_PROTO_PPTP:
- case PIPEX_PROTO_L2TP:
- chain = PIPEX_PEER_ADDR_HASHTABLE(
- pipex_sockaddr_hash_key(&session->peer.sa));
- LIST_INSERT_HEAD(chain, session, peer_addr_chain);
- break;
- }
-#endif
+ pipex_iface_init(&pxi->pxi_ifcontext, ifp);
+ pipex_iface_start(&pxi->pxi_ifcontext);
+
+ error = pipex_add_session(req, &pxi->pxi_ifcontext);
- /* if first session is added, start timer */
- if (LIST_NEXT(session, session_list) == NULL)
- pipex_timer_start();
+ if (error) {
+ NET_UNLOCK();
+ pipex_iface_fini(&pxi->pxi_ifcontext);
+ NET_LOCK();
+ pool_put(pppx_if_pl, pxi);
+ error = EADDRINUSE;
+ rw_exit_write(&pppx_ifs_lk);
+ goto out;
+ }
/* XXXSMP breaks atomicity */
NET_UNLOCK();
@@ -932,11 +784,7 @@ pppx_del_session(struct pppx_dev *pxd, s
pxi = pppx_if_find(pxd, req->pcr_session_id, req->pcr_protocol);
if (pxi == NULL)
return (EINVAL);
-
- req->pcr_stat = pxi->pxi_session.stat;
-
- pppx_if_destroy(pxd, pxi);
- return (0);
+ return pppx_if_destroy(pxd, pxi, req);
}
int
@@ -955,34 +803,28 @@ pppx_set_session_descr(struct pppx_dev *
return (0);
}
-void
-pppx_if_destroy(struct pppx_dev *pxd, struct pppx_if *pxi)
+int
+pppx_if_destroy(struct pppx_dev *pxd, struct pppx_if *pxi,
+ struct pipex_session_close_req *req)
{
- struct ifnet *ifp;
- struct pipex_session *session;
+ int error;
NET_ASSERT_LOCKED();
- session = &pxi->pxi_session;
- ifp = &pxi->pxi_if;
- LIST_REMOVE(session, id_chain);
- LIST_REMOVE(session, session_list);
-#if defined(PIPEX_PPTP) || defined(PIPEX_L2TP)
- switch (session->protocol) {
- case PIPEX_PROTO_PPTP:
- case PIPEX_PROTO_L2TP:
- LIST_REMOVE(session, peer_addr_chain);
- break;
- }
-#endif
+ /* XXXSMP breaks atomicity */
+ NET_UNLOCK();
+ if_detach(&pxi->pxi_if);
+ NET_LOCK();
- /* if final session is destroyed, stop timer */
- if (LIST_EMPTY(&pipex_session_list))
- pipex_timer_stop();
+ /*
+ * XXX: is safe: the only session will be killed by
+ * pipex_iface_fini() call
+ */
+ if (req)
+ error = pipex_close_session(req);
- /* XXXSMP breaks atomicity */
NET_UNLOCK();
- if_detach(ifp);
+ pipex_iface_fini(&pxi->pxi_ifcontext);
NET_LOCK();
rw_enter_write(&pppx_ifs_lk);
@@ -992,6 +834,8 @@ pppx_if_destroy(struct pppx_dev *pxd, st
rw_exit_write(&pppx_ifs_lk);
pool_put(pppx_if_pl, pxi);
+
+ return error;
}
void
@@ -1005,6 +849,8 @@ pppx_if_start(struct ifnet *ifp)
return;
for (;;) {
+ struct pipex_session *session;
+
IFQ_DEQUEUE(&ifp->if_snd, m);
if (m == NULL)
@@ -1016,7 +862,13 @@ pppx_if_start(struct ifnet *ifp)
ifp->if_obytes += m->m_pkthdr.len;
ifp->if_opackets++;
- pipex_ppp_output(m, &pxi->pxi_session, proto);
+ session = pipex_lookup_by_session_id(
+ pxi->pxi_key.pxik_protocol, pxi->pxi_key.pxik_session_id);
+
+ if (session)
+ pipex_ppp_output(m, session, proto);
+ else
+ m_freem(m);
}
}
@@ -1076,7 +928,8 @@ pppx_if_output(struct ifnet *ifp, struct
}
th = mtod(m, struct pppx_hdr *);
th->pppx_proto = 0; /* not used */
- th->pppx_id = pxi->pxi_session.ppp_id;
+ th->pppx_id = pxi->pxi_ppp_id;
+
rw_enter_read(&pppx_devs_lk);
error = mq_enqueue(&pxi->pxi_dev->pxd_svcq, m);
if (error == 0) {
@@ -1100,8 +953,15 @@ pppx_if_ioctl(struct ifnet *ifp, u_long
{
struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
struct ifreq *ifr = (struct ifreq *)addr;
+ struct pipex_session *session;
int error = 0;
+ session = pipex_lookup_by_session_id(pxi->pxi_key.pxik_protocol,
+ pxi->pxi_key.pxik_session_id);
+
+ if (session == NULL)
+ return ENXIO;
+
switch (cmd) {
case SIOCSIFADDR:
break;
@@ -1114,8 +974,7 @@ pppx_if_ioctl(struct ifnet *ifp, u_long
break;
case SIOCSIFMTU:
- if (ifr->ifr_mtu < 512 ||
- ifr->ifr_mtu > pxi->pxi_session.peer_mru)
+ if (ifr->ifr_mtu < 512 || ifr->ifr_mtu > session->peer_mru)
error = EINVAL;
else
ifp->if_mtu = ifr->ifr_mtu;