59#include <sys/kernel.h>
62#include <sys/malloc.h>
65#include <sys/endian.h>
67#include <sys/sysctl.h>
69#include <netinet/in.h>
70#include <netinet/in_systm.h>
71#include <netinet/ip.h>
80#if BYTE_ORDER == LITTLE_ENDIAN
90#elif BYTE_ORDER == BIG_ENDIAN
101#error BYTE_ORDER is not defined properly
110#define PPTP_GRE_PROTO 0x880b
113#define PPTP_INIT_VALUE ((0x2001 << 16) | PPTP_GRE_PROTO)
114#define PPTP_INIT_MASK 0xef7fffff
117#define PPTP_MAX_PAYLOAD (0xffff - sizeof(struct greheader) - 8)
120#define PPTP_TIME_SCALE 1024
124#define PPTP_XMIT_WIN 16
125#define PPTP_MIN_TIMEOUT (PPTP_TIME_SCALE / 83)
126#define PPTP_MAX_TIMEOUT (3 * PPTP_TIME_SCALE)
128#define PPTP_REORDER_TIMEOUT 1
134#define PPTP_MIN_ACK_DELAY (PPTP_TIME_SCALE / 500)
135#define PPTP_MAX_ACK_DELAY (PPTP_TIME_SCALE / 2)
138#define PPTP_ACK_ALPHA(x) (((x) + 4) >> 3)
139#define PPTP_ACK_BETA(x) (((x) + 2) >> 2)
140#define PPTP_ACK_CHI(x) ((x) << 2)
141#define PPTP_ACK_DELTA(x) ((x) << 1)
143#define PPTP_SEQ_DIFF(x,y) ((int32_t)(x) - (int32_t)(y))
145#define SESSHASHSIZE 0x0020
146#define SESSHASH(x) (((x) ^ ((x) >> 8)) & (SESSHASHSIZE - 1))
148SYSCTL_NODE(_net_graph, OID_AUTO, pptpgre, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
175typedef struct ng_pptpgre_roq_head
roqh;
198 struct callout reorderTimer;
227 void *arg1,
int arg2);
229 void *arg1,
int arg2);
231 void *arg1,
int arg2);
309#define ERROUT(x) do { error = (x); goto done; } while (0)
325 priv = malloc(
sizeof(*
priv), M_NETGRAPH, M_WAITOK | M_ZERO);
330 mtx_init(&
priv->uppersess.mtx,
"ng_pptp", NULL, MTX_DEF);
333 priv->uppersess.node = node;
335 SLIST_INIT(&
priv->uppersess.roq);
336 priv->uppersess.roq_len = 0;
340 LIST_INIT(&
priv->sesshash[i]);
342 LIST_INSERT_HEAD(&
priv->sesshash[0], &
priv->uppersess, sessions);
359 priv->uppersess.hook = hook;
365 static const char hexdig[16] =
"0123456789abcdef";
376 for (cid = i = 0; i < 4; i++) {
377 for (j = 0; j < 16 && hex[i] != hexdig[j]; j++);
380 cid = (cid << 4) | j;
385 hpriv = malloc(
sizeof(*hpriv), M_NETGRAPH, M_NOWAIT | M_ZERO);
390 mtx_init(&hpriv->mtx,
"ng_pptp", NULL, MTX_DEF);
393 hpriv->conf.cid = cid;
397 SLIST_INIT(&hpriv->roq);
404 LIST_INSERT_HEAD(&
priv->sesshash[hash], hpriv, sessions);
439 hpriv = &
priv->uppersess;
440 LIST_REMOVE(hpriv, sessions);
442 LIST_INSERT_HEAD(&
priv->sesshash[hash], hpriv,
446 hpriv->conf = *newConf;
456 *((uint16_t *)msg->
data));
461 hpriv = &
priv->uppersess;
467 bcopy(&hpriv->conf, resp->
data,
sizeof(hpriv->conf));
511 if (!hpriv->conf.enabled) {
516 mtx_lock(&hpriv->mtx);
520 mtx_assert(&hpriv->mtx, MA_NOTOWNED);
538 priv->uppersess.hook = NULL;
545 LIST_REMOVE(hpriv, sessions);
546 mtx_destroy(&hpriv->mtx);
547 free(hpriv, M_NETGRAPH);
568 LIST_REMOVE(&
priv->uppersess, sessions);
569 mtx_destroy(&
priv->uppersess.mtx);
571 free(
priv, M_NETGRAPH);
589 u_char buf[
sizeof(
struct greheader) + 2 *
sizeof(u_int32_t)];
594 mtx_assert(&hpriv->mtx, MA_OWNED);
604 if (hpriv->conf.enableWindowing) {
607 hpriv->recvAck) >= hpriv->xmitWin) {
624 be16enc(&gre->
length, (m != NULL) ? m->m_pkthdr.len : 0);
625 be16enc(&gre->
cid, hpriv->conf.peerCid);
630 if (hpriv->conf.enableWindowing) {
631 hpriv->timeSent[hpriv->xmitSeq - hpriv->recvAck]
635 be32enc(&gre->
data[0], hpriv->xmitSeq);
639 if (hpriv->conf.enableAlwaysAck || hpriv->xmitAck != hpriv->recvSeq) {
641 be32enc(&gre->
data[gre->
hasSeq], hpriv->recvSeq);
642 hpriv->xmitAck = hpriv->recvSeq;
643 if (hpriv->conf.enableDelayedAck)
648 grelen =
sizeof(*gre) +
sizeof(u_int32_t) * (gre->
hasSeq + gre->
hasAck);
650 MGETHDR(m, M_NOWAIT, MT_DATA);
655 m->m_len = m->m_pkthdr.len = grelen;
656 m->m_pkthdr.rcvif = NULL;
658 M_PREPEND(m, grelen, M_NOWAIT);
659 if (m == NULL || (m->m_len < grelen
660 && (m = m_pullup(m, grelen)) == NULL)) {
665 bcopy(gre, mtod(m, u_char *), grelen);
669 priv->
stats.xmitOctets += m->m_pkthdr.len;
675 if (hpriv->conf.enableWindowing &&
676 gre->
hasSeq && hpriv->xmitSeq == hpriv->recvAck + 1)
679 mtx_unlock(&hpriv->mtx);
691 mtx_unlock(&hpriv->mtx);
701 mtx_assert(&hpriv->mtx, MA_OWNED);
702 if (!(callout_pending(&hpriv->sackTimer))) {
704 if (!hpriv->conf.enableDelayedAck) {
711 mtx_unlock(&hpriv->mtx);
714 mtx_unlock(&hpriv->mtx);
729 mtx_assert(&hpriv->mtx, MA_NOTOWNED);
730 while (!SLIST_EMPTY(q)) {
732 SLIST_REMOVE_HEAD(q, next);
736 free(np, M_NETGRAPH);
750 int iphlen, grelen, extralen;
756 roqh sendq = SLIST_HEAD_INITIALIZER(sendq);
766 priv->
stats.recvOctets += m->m_pkthdr.len;
769 if (m->m_pkthdr.len <
sizeof(*ip) +
sizeof(*gre)) {
775 if (m->m_len <
sizeof(*ip) +
sizeof(*gre)) {
776 if ((m = m_pullup(m,
sizeof(*ip) +
sizeof(*gre))) == NULL) {
783 ip = mtod(m,
const struct ip *);
784 iphlen = ip->ip_hl << 2;
785 if (m->m_len < iphlen +
sizeof(*gre)) {
786 if ((m = m_pullup(m, iphlen +
sizeof(*gre))) == NULL) {
792 ip = mtod(m,
const struct ip *);
794 gre = (
const struct greheader *)((
const u_char *)ip + iphlen);
795 grelen =
sizeof(*gre) +
sizeof(u_int32_t) * (gre->
hasSeq + gre->
hasAck);
796 if (m->m_pkthdr.len < iphlen + grelen) {
800 if (m->m_len < iphlen + grelen) {
801 if ((m = m_pullup(m, iphlen + grelen)) == NULL) {
807 ip = mtod(m,
const struct ip *);
808 gre = (
const struct greheader *)((
const u_char *)ip + iphlen);
812 extralen = m->m_pkthdr.len
813 - (iphlen + grelen + gre->
hasSeq * be16dec(&gre->
length));
824 if (hpriv == NULL || hpriv->hook == NULL || !hpriv->conf.enabled) {
828 mtx_lock(&hpriv->mtx);
832 const u_int32_t ack = be32dec(&gre->
data[gre->
hasSeq]);
833 const int index = ack - hpriv->recvAck - 1;
843 hpriv->recvAck = ack;
846 if (hpriv->conf.enableWindowing) {
848 diff = sample - hpriv->rtt;
861 bcopy(hpriv->timeSent + index + 1, hpriv->timeSent,
862 sizeof(*hpriv->timeSent)
869 hpriv->winAck = ack + hpriv->xmitWin;
874 if (hpriv->recvAck != hpriv->xmitSeq)
883 mtx_unlock(&hpriv->mtx);
887 seq = be32dec(&gre->
data[0]);
895 mtx_unlock(&hpriv->mtx);
900 m_adj(m, iphlen + grelen);
904#define INIT_SENDQ(t) do { \
907 SLIST_INSERT_HEAD(&sendq, &t, next); \
909 hpriv->recvSeq = seq; \
923 prev = SLIST_FIRST(&hpriv->roq);
924 SLIST_FOREACH(np, &hpriv->roq, next) {
928 mtx_unlock(&hpriv->mtx);
962 np = SLIST_FIRST(&hpriv->roq);
965 SLIST_REMOVE_HEAD(&hpriv->roq, next);
967 SLIST_INSERT_HEAD(&sendq, np, next);
969 hpriv->recvSeq = np->seq;
972 np = malloc(
sizeof(*np), M_NETGRAPH, M_NOWAIT | M_ZERO);
980 while (!SLIST_EMPTY(&hpriv->roq)) {
981 np = SLIST_FIRST(&hpriv->roq);
984 SLIST_REMOVE_HEAD(&hpriv->roq, next);
987 SLIST_INSERT_HEAD(&sendq, np, next);
989 SLIST_INSERT_AFTER(
last, np, next);
997 hpriv->recvSeq = seq;
1008 SLIST_INSERT_HEAD(&hpriv->roq, np, next);
1010 SLIST_INSERT_AFTER(prev, np, next);
1015 while (!SLIST_EMPTY(&hpriv->roq)) {
1016 np = SLIST_FIRST(&hpriv->roq);
1021 SLIST_REMOVE_HEAD(&hpriv->roq, next);
1023 hpriv->recvSeq = np->seq;
1026 SLIST_INSERT_HEAD(&sendq, np, next);
1028 SLIST_INSERT_AFTER(
last, np, next);
1032 if (SLIST_EMPTY(&hpriv->roq)) {
1033 if (callout_pending(&hpriv->reorderTimer))
1036 if (!callout_pending(&hpriv->reorderTimer))
1040 if (SLIST_EMPTY(&sendq)) {
1042 mtx_unlock(&hpriv->mtx);
1079 ng_callout(&hpriv->rackTimer, hpriv->node, hpriv->hook,
1104 hpriv->recvAck = hpriv->xmitSeq;
1105 hpriv->xmitWin = (hpriv->xmitWin + 1) / 2;
1106 hpriv->winAck = hpriv->recvAck + hpriv->xmitWin;
1116 int ackTimeout, ticks;
1119 ackTimeout = (hpriv->rtt >> 2);
1127 ng_callout(&hpriv->sackTimer, hpriv->node, hpriv->hook,
1142 mtx_lock(&hpriv->mtx);
1145 mtx_assert(&hpriv->mtx, MA_NOTOWNED);
1159 ng_callout(&hpriv->reorderTimer, hpriv->node, hpriv->hook,
1172 roqh sendq = SLIST_HEAD_INITIALIZER(sendq);
1176 mtx_lock(&hpriv->mtx);
1177 if (SLIST_EMPTY(&hpriv->roq)) {
1178 mtx_unlock(&hpriv->mtx);
1182 last = np = SLIST_FIRST(&hpriv->roq);
1184 SLIST_REMOVE_HEAD(&hpriv->roq, next);
1185 SLIST_INSERT_HEAD(&sendq, np, next);
1188 while (!SLIST_EMPTY(&hpriv->roq)) {
1189 np = SLIST_FIRST(&hpriv->roq);
1195 SLIST_REMOVE_HEAD(&hpriv->roq, next);
1196 SLIST_INSERT_AFTER(
last, np, next);
1200 hpriv->recvSeq =
last->seq;
1201 if (!SLIST_EMPTY(&hpriv->roq))
1207 mtx_assert(&hpriv->mtx, MA_NOTOWNED);
1223 LIST_FOREACH(hpriv, &privp->sesshash[hash], sessions) {
1224 if (hpriv->conf.cid == cid)
1242 if (hpriv->conf.peerPpd > 1)
1243 hpriv->rtt *= hpriv->conf.peerPpd;
1245 hpriv->xmitWin = (hpriv->conf.recvWin + 1) / 2;
1246 if (hpriv->xmitWin < 2)
1250 hpriv->winAck = hpriv->xmitWin;
1253 hpriv->recvSeq = ~0;
1254 hpriv->recvAck = ~0;
1255 hpriv->xmitSeq = ~0;
1256 hpriv->xmitAck = ~0;
1264 while (!SLIST_EMPTY(&hpriv->roq)) {
1265 np = SLIST_FIRST(&hpriv->roq);
1266 SLIST_REMOVE_HEAD(&hpriv->roq, next);
1268 free(np, M_NETGRAPH);
#define NG_HOOK_NODE(hook)
int ng_rcvmsg_t(node_p node, item_p item, hook_p lasthook)
int ng_disconnect_t(hook_p hook)
#define NG_NODE_SET_PRIVATE(node, val)
#define NG_RESPOND_MSG(error, here, item, resp)
#define NG_NODE_IS_VALID(node)
#define NG_NODE_UNREF(node)
#define NG_HOOK_SET_PRIVATE(hook, val)
int ng_rmnode_self(node_p here)
#define ng_callout_init(c)
#define NG_FWD_NEW_DATA(error, item, hook, m)
#define NG_SEND_DATA_ONLY(error, hook, m)
int ng_rcvdata_t(hook_p hook, item_p item)
int ng_shutdown_t(node_p node)
int ng_uncallout(struct callout *c, node_p node)
#define NG_FREE_ITEM(item)
#define NG_HOOK_SET_RCVDATA(hook, val)
int ng_constructor_t(node_p node)
#define NG_NODE_NUMHOOKS(node)
#define NGI_GET_MSG(i, m)
#define NG_NODE_PRIVATE(node)
int ng_callout(struct callout *c, node_p node, hook_p hook, int ticks, ng_item_fn *fn, void *arg1, int arg2)
int ng_newhook_t(node_p node, hook_p hook, const char *name)
#define NG_HOOK_PRIVATE(hook)
#define NG_MKRESPONSE(rsp, msg, len, how)
const struct ng_parse_type ng_parse_struct_type
const struct ng_parse_type ng_parse_hint16_type
static hpriv_p ng_pptpgre_find_session(priv_p privp, u_int16_t cid)
#define PPTP_SEQ_DIFF(x, y)
static int ng_pptpgre_xmit(hpriv_p hpriv, item_p item)
static void ng_pptpgre_ack(const hpriv_p hpriv)
static ng_shutdown_t ng_pptpgre_shutdown
static const struct ng_parse_type ng_pptp_stats_type
static void ng_pptpgre_send_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2)
struct ng_pptpgre_private * priv_p
static pptptime_t ng_pptpgre_time(void)
static ng_newhook_t ng_pptpgre_newhook
SYSCTL_UINT(_net_graph_pptpgre, OID_AUTO, reorder_max, CTLFLAG_RWTUN, &reorder_max, 0, "Reorder queue maximum length")
struct ng_pptpgre_sess * hpriv_p
#define PPTP_MAX_ACK_DELAY
static const struct ng_parse_struct_field ng_pptpgre_stats_type_fields[]
static void ng_pptpgre_start_reorder_timer(hpriv_p hpriv)
static ng_rcvmsg_t ng_pptpgre_rcvmsg
#define PPTP_MIN_ACK_DELAY
SLIST_HEAD(ng_pptpgre_roq_head, ng_pptpgre_roq)
static void ng_pptpgre_start_recv_ack_timer(hpriv_p hpriv)
static ng_constructor_t ng_pptpgre_constructor
#define PPTP_REORDER_TIMEOUT
static const struct ng_cmdlist ng_pptpgre_cmdlist[]
static void ng_pptpgre_recv_ack_timeout(node_p node, hook_p hook, void *arg1, int arg2)
static void ng_pptpgre_reorder_timeout(node_p node, hook_p hook, void *arg1, int arg2)
static ng_rcvdata_t ng_pptpgre_rcvdata
static ng_disconnect_t ng_pptpgre_disconnect
static const struct ng_parse_type ng_pptpgre_conf_type
NETGRAPH_INIT(pptpgre, &ng_pptpgre_typestruct)
struct ng_pptpgre_roq_head roqh
SYSCTL_NODE(_net_graph, OID_AUTO, pptpgre, CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "PPTPGRE")
#define PPTP_ACK_ALPHA(x)
static int ng_pptpgre_sendq(const hpriv_p hpriv, roqh *q, const struct ng_pptpgre_roq *st)
static struct ng_type ng_pptpgre_typestruct
static int reorder_timeout
static const struct ng_parse_struct_field ng_pptpgre_conf_type_fields[]
static void ng_pptpgre_reset(hpriv_p hpriv)
#define PPTP_ACK_DELTA(x)
static ng_rcvdata_t ng_pptpgre_rcvdata_lower
static void ng_pptpgre_start_send_ack_timer(hpriv_p hpriv)
#define NG_PPTPGRE_NODE_TYPE
#define NG_PPTPGRE_HOOK_SESSION_P
@ NGM_PPTPGRE_GETCLR_STATS
#define NG_PPTPGRE_STATS_TYPE_INFO
#define NG_PPTPGRE_HOOK_LOWER
#define NG_PPTPGRE_CONF_TYPE_INFO
#define NGM_PPTPGRE_COOKIE
#define NG_PPTPGRE_HOOK_UPPER
static LIST_HEAD(ngatm_msg)
struct ng_mesg::ng_msghdr header
struct ng_pptpgre_sess uppersess
pptptime_t timeSent[PPTP_XMIT_WIN]
struct ng_pptpgre_conf conf