More complete fix for multi-link sequence number handling bugs.
Add a new control message for querying the sequence number state.
This commit is contained in:
parent
e6e7337683
commit
6f16db8137
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=66775
@ -34,7 +34,7 @@
|
||||
* THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* Author: Archie Cobbs <archie@whistle.com>
|
||||
* Author: Archie Cobbs <archie@freebsd.org>
|
||||
*
|
||||
* $FreeBSD$
|
||||
* $Whistle: ng_ppp.c,v 1.24 1999/11/01 09:24:52 julian Exp $
|
||||
@ -91,29 +91,30 @@
|
||||
#define MP_LONG_FIRST_FLAG 0x80000000 /* first fragment in frame */
|
||||
#define MP_LONG_LAST_FLAG 0x40000000 /* last fragment in frame */
|
||||
|
||||
#define MP_NOSEQ INT_MAX /* impossible sequence number */
|
||||
|
||||
#define MP_SEQ_MASK(priv) ((priv)->conf.recvShortSeq ? \
|
||||
MP_SHORT_SEQ_MASK : MP_LONG_SEQ_MASK)
|
||||
#define MP_NOSEQ 0x7fffffff /* impossible sequence number */
|
||||
|
||||
/* Sign extension of MP sequence numbers */
|
||||
#define MP_SHORT_EXTEND(s) (((s) & MP_SHORT_SEQ_HIBIT) ? \
|
||||
((s) | ~MP_SHORT_SEQ_MASK) : (s))
|
||||
#define MP_LONG_EXTEND(s) (((s) & MP_LONG_SEQ_HIBIT) ? \
|
||||
((s) | ~MP_LONG_SEQ_MASK) : (s))
|
||||
#define MP_SHORT_EXTEND(s) (((s) & MP_SHORT_SEQ_HIBIT) ? \
|
||||
((s) | ~MP_SHORT_SEQ_MASK) \
|
||||
: ((s) & MP_SHORT_SEQ_MASK))
|
||||
#define MP_LONG_EXTEND(s) (((s) & MP_LONG_SEQ_HIBIT) ? \
|
||||
((s) | ~MP_LONG_SEQ_MASK) \
|
||||
: ((s) & MP_LONG_SEQ_MASK))
|
||||
|
||||
/* Comparision of MP sequence numbers */
|
||||
#define MP_SHORT_SEQ_DIFF(x,y) \
|
||||
(MP_SHORT_EXTEND(((x) & MP_SHORT_SEQ_MASK) - ((y) & MP_SHORT_SEQ_MASK)))
|
||||
#define MP_LONG_SEQ_DIFF(x,y) \
|
||||
(MP_LONG_EXTEND(((x) & MP_LONG_SEQ_MASK) - ((y) & MP_LONG_SEQ_MASK)))
|
||||
/* Comparision of MP sequence numbers. Note: all sequence numbers
|
||||
except priv->xseq are stored with the sign bit extended. */
|
||||
#define MP_SHORT_SEQ_DIFF(x,y) MP_SHORT_EXTEND((x) - (y))
|
||||
#define MP_LONG_SEQ_DIFF(x,y) MP_LONG_EXTEND((x) - (y))
|
||||
|
||||
#define MP_SEQ_DIFF(priv,x,y) ((priv)->conf.recvShortSeq ? \
|
||||
MP_SHORT_SEQ_DIFF((x), (y)) : \
|
||||
#define MP_RECV_SEQ_DIFF(priv,x,y) \
|
||||
((priv)->conf.recvShortSeq ? \
|
||||
MP_SHORT_SEQ_DIFF((x), (y)) : \
|
||||
MP_LONG_SEQ_DIFF((x), (y)))
|
||||
|
||||
#define MP_NEXT_SEQ(priv,seq) (((seq) + 1) & MP_SEQ_MASK(priv))
|
||||
#define MP_PREV_SEQ(priv,seq) (((seq) - 1) & MP_SEQ_MASK(priv))
|
||||
/* Increment receive sequence number */
|
||||
#define MP_NEXT_RECV_SEQ(priv,seq) \
|
||||
(((seq) + 1) & ((priv)->conf.recvShortSeq ? \
|
||||
MP_SHORT_SEQ_MASK : MP_LONG_SEQ_MASK))
|
||||
|
||||
/* Don't fragment transmitted packets smaller than this */
|
||||
#define MP_MIN_FRAG_LEN 6
|
||||
@ -176,7 +177,7 @@ static const char *const ng_ppp_hook_names[] = {
|
||||
struct ng_ppp_link {
|
||||
struct ng_ppp_link_conf conf; /* link configuration */
|
||||
hook_p hook; /* connection to link data */
|
||||
int seq; /* highest rec'd seq# - MSEQ */
|
||||
int32_t seq; /* highest rec'd seq# - MSEQ */
|
||||
struct timeval lastWrite; /* time of last write */
|
||||
int bytesInQueue; /* bytes in the output queue */
|
||||
struct ng_ppp_link_stat stats; /* Link stats */
|
||||
@ -187,8 +188,8 @@ struct ng_ppp_private {
|
||||
struct ng_ppp_bund_conf conf; /* bundle config */
|
||||
struct ng_ppp_link_stat bundleStats; /* bundle stats */
|
||||
struct ng_ppp_link links[NG_PPP_MAX_LINKS];/* per-link info */
|
||||
int xseq; /* next out MP seq # */
|
||||
int mseq; /* min links[i].seq */
|
||||
int32_t xseq; /* next out MP seq # */
|
||||
int32_t mseq; /* min links[i].seq */
|
||||
u_char vjCompHooked; /* VJ comp hooked up? */
|
||||
u_char allLinksEqual; /* all xmit the same? */
|
||||
u_char timerActive; /* frag timer active? */
|
||||
@ -236,6 +237,22 @@ static void ng_ppp_update(node_p node, int newConf);
|
||||
static void ng_ppp_start_frag_timer(node_p node);
|
||||
static void ng_ppp_stop_frag_timer(node_p node);
|
||||
|
||||
/* Parse type for struct ng_ppp_mp_state_type */
|
||||
static const struct ng_parse_fixedarray_info ng_ppp_rseq_array_info = {
|
||||
&ng_parse_hint32_type,
|
||||
NG_PPP_MAX_LINKS
|
||||
};
|
||||
static const struct ng_parse_type ng_ppp_rseq_array_type = {
|
||||
&ng_parse_fixedarray_type,
|
||||
&ng_ppp_rseq_array_info,
|
||||
};
|
||||
static const struct ng_parse_struct_info ng_ppp_mp_state_type_info
|
||||
= NG_PPP_MP_STATE_TYPE_INFO(&ng_ppp_rseq_array_type);
|
||||
static const struct ng_parse_type ng_ppp_mp_state_type = {
|
||||
&ng_parse_struct_type,
|
||||
&ng_ppp_mp_state_type_info,
|
||||
};
|
||||
|
||||
/* Parse type for struct ng_ppp_link_conf */
|
||||
static const struct ng_parse_struct_info
|
||||
ng_ppp_link_type_info = NG_PPP_LINK_TYPE_INFO;
|
||||
@ -253,7 +270,7 @@ static const struct ng_parse_type ng_ppp_bund_type = {
|
||||
};
|
||||
|
||||
/* Parse type for struct ng_ppp_node_conf */
|
||||
struct ng_parse_fixedarray_info ng_ppp_array_info = {
|
||||
static const struct ng_parse_fixedarray_info ng_ppp_array_info = {
|
||||
&ng_ppp_link_type,
|
||||
NG_PPP_MAX_LINKS
|
||||
};
|
||||
@ -292,6 +309,13 @@ static const struct ng_cmdlist ng_ppp_cmds[] = {
|
||||
NULL,
|
||||
&ng_ppp_conf_type
|
||||
},
|
||||
{
|
||||
NGM_PPP_COOKIE,
|
||||
NGM_PPP_GET_MP_STATE,
|
||||
"getmpstate",
|
||||
NULL,
|
||||
&ng_ppp_mp_state_type
|
||||
},
|
||||
{
|
||||
NGM_PPP_COOKIE,
|
||||
NGM_PPP_GET_LINK_STATS,
|
||||
@ -482,6 +506,24 @@ ng_ppp_rcvmsg(node_p node, struct ng_mesg *msg,
|
||||
conf->links[i] = priv->links[i].conf;
|
||||
break;
|
||||
}
|
||||
case NGM_PPP_GET_MP_STATE:
|
||||
{
|
||||
struct ng_ppp_mp_state *info;
|
||||
int i;
|
||||
|
||||
NG_MKRESPONSE(resp, msg, sizeof(*info), M_NOWAIT);
|
||||
if (resp == NULL)
|
||||
ERROUT(ENOMEM);
|
||||
info = (struct ng_ppp_mp_state *)resp->data;
|
||||
bzero(info, sizeof(*info));
|
||||
for (i = 0; i < NG_PPP_MAX_LINKS; i++) {
|
||||
if (priv->links[i].seq != MP_NOSEQ)
|
||||
info->rseq[i] = priv->links[i].seq;
|
||||
}
|
||||
info->mseq = priv->mseq;
|
||||
info->xseq = priv->xseq;
|
||||
break;
|
||||
}
|
||||
case NGM_PPP_GET_LINK_STATS:
|
||||
case NGM_PPP_CLR_LINK_STATS:
|
||||
case NGM_PPP_GETCLR_LINK_STATS:
|
||||
@ -1035,7 +1077,7 @@ ng_ppp_mp_input(node_p node, int linkNum, struct mbuf *m, meta_p meta)
|
||||
return (ENOBUFS);
|
||||
}
|
||||
shdr = ntohs(*mtod(m, u_int16_t *));
|
||||
frag->seq = shdr & MP_SHORT_SEQ_MASK;
|
||||
frag->seq = MP_SHORT_EXTEND(shdr);
|
||||
frag->first = (shdr & MP_SHORT_FIRST_FLAG) != 0;
|
||||
frag->last = (shdr & MP_SHORT_LAST_FLAG) != 0;
|
||||
diff = MP_SHORT_SEQ_DIFF(frag->seq, priv->mseq);
|
||||
@ -1053,7 +1095,7 @@ ng_ppp_mp_input(node_p node, int linkNum, struct mbuf *m, meta_p meta)
|
||||
return (ENOBUFS);
|
||||
}
|
||||
lhdr = ntohl(*mtod(m, u_int32_t *));
|
||||
frag->seq = lhdr & MP_LONG_SEQ_MASK;
|
||||
frag->seq = MP_LONG_EXTEND(lhdr);
|
||||
frag->first = (lhdr & MP_LONG_FIRST_FLAG) != 0;
|
||||
frag->last = (lhdr & MP_LONG_LAST_FLAG) != 0;
|
||||
diff = MP_LONG_SEQ_DIFF(frag->seq, priv->mseq);
|
||||
@ -1077,7 +1119,7 @@ ng_ppp_mp_input(node_p node, int linkNum, struct mbuf *m, meta_p meta)
|
||||
struct ng_ppp_link *const alink =
|
||||
&priv->links[priv->activeLinks[i]];
|
||||
|
||||
if (MP_SEQ_DIFF(priv, alink->seq, priv->mseq) < 0)
|
||||
if (MP_RECV_SEQ_DIFF(priv, alink->seq, priv->mseq) < 0)
|
||||
priv->mseq = alink->seq;
|
||||
}
|
||||
|
||||
@ -1093,7 +1135,7 @@ ng_ppp_mp_input(node_p node, int linkNum, struct mbuf *m, meta_p meta)
|
||||
/* Add fragment to queue, which is sorted by sequence number */
|
||||
inserted = 0;
|
||||
CIRCLEQ_FOREACH_REVERSE(qent, &priv->frags, f_qent) {
|
||||
diff = MP_SEQ_DIFF(priv, frag->seq, qent->seq);
|
||||
diff = MP_RECV_SEQ_DIFF(priv, frag->seq, qent->seq);
|
||||
if (diff > 0) {
|
||||
CIRCLEQ_INSERT_AFTER(&priv->frags, qent, frag, f_qent);
|
||||
inserted = 1;
|
||||
@ -1130,7 +1172,7 @@ ng_ppp_check_packet(node_p node)
|
||||
|
||||
/* Check first fragment is the start of a deliverable packet */
|
||||
qent = CIRCLEQ_FIRST(&priv->frags);
|
||||
if (!qent->first || MP_SEQ_DIFF(priv, qent->seq, priv->mseq) > 1)
|
||||
if (!qent->first || MP_RECV_SEQ_DIFF(priv, qent->seq, priv->mseq) > 1)
|
||||
return (0);
|
||||
|
||||
/* Check that all the fragments are there */
|
||||
@ -1138,7 +1180,7 @@ ng_ppp_check_packet(node_p node)
|
||||
qnext = CIRCLEQ_NEXT(qent, f_qent);
|
||||
if (qnext == (void *)&priv->frags) /* end of queue */
|
||||
return (0);
|
||||
if (qnext->seq != MP_NEXT_SEQ(priv, qent->seq))
|
||||
if (qnext->seq != MP_NEXT_RECV_SEQ(priv, qent->seq))
|
||||
return (0);
|
||||
qent = qnext;
|
||||
}
|
||||
@ -1206,12 +1248,12 @@ ng_ppp_frag_trim(node_p node)
|
||||
|
||||
/* Determine whether first fragment can ever be completed */
|
||||
CIRCLEQ_FOREACH(qent, &priv->frags, f_qent) {
|
||||
if (MP_SEQ_DIFF(priv, qent->seq, priv->mseq) >= 0)
|
||||
if (MP_RECV_SEQ_DIFF(priv, qent->seq, priv->mseq) >= 0)
|
||||
break;
|
||||
qnext = CIRCLEQ_NEXT(qent, f_qent);
|
||||
KASSERT(qnext != (void*)&priv->frags,
|
||||
("%s: last frag < MSEQ?", __FUNCTION__));
|
||||
if (qnext->seq != MP_NEXT_SEQ(priv, qent->seq)
|
||||
if (qnext->seq != MP_NEXT_RECV_SEQ(priv, qent->seq)
|
||||
|| qent->last || qnext->first) {
|
||||
dead = 1;
|
||||
break;
|
||||
@ -1273,13 +1315,13 @@ ng_ppp_frag_process(node_p node)
|
||||
qent = CIRCLEQ_FIRST(&priv->frags);
|
||||
|
||||
/* Bump MSEQ if necessary */
|
||||
if (MP_SEQ_DIFF(priv, priv->mseq, qent->seq) < 0) {
|
||||
if (MP_RECV_SEQ_DIFF(priv, priv->mseq, qent->seq) < 0) {
|
||||
priv->mseq = qent->seq;
|
||||
for (i = 0; i < priv->numActiveLinks; i++) {
|
||||
struct ng_ppp_link *const alink =
|
||||
&priv->links[priv->activeLinks[i]];
|
||||
|
||||
if (MP_SEQ_DIFF(priv,
|
||||
if (MP_RECV_SEQ_DIFF(priv,
|
||||
alink->seq, priv->mseq) < 0)
|
||||
alink->seq = priv->mseq;
|
||||
}
|
||||
@ -1341,7 +1383,7 @@ ng_ppp_frag_checkstale(node_p node)
|
||||
end = qent;
|
||||
break;
|
||||
}
|
||||
seq = MP_NEXT_SEQ(priv, seq);
|
||||
seq = MP_NEXT_RECV_SEQ(priv, seq);
|
||||
}
|
||||
|
||||
/* If none found, exit */
|
||||
@ -1373,13 +1415,13 @@ ng_ppp_frag_checkstale(node_p node)
|
||||
ng_ppp_get_packet(node, &m, &meta);
|
||||
|
||||
/* Bump MSEQ if necessary */
|
||||
if (MP_SEQ_DIFF(priv, priv->mseq, end->seq) < 0) {
|
||||
if (MP_RECV_SEQ_DIFF(priv, priv->mseq, end->seq) < 0) {
|
||||
priv->mseq = end->seq;
|
||||
for (i = 0; i < priv->numActiveLinks; i++) {
|
||||
struct ng_ppp_link *const alink =
|
||||
&priv->links[priv->activeLinks[i]];
|
||||
|
||||
if (MP_SEQ_DIFF(priv,
|
||||
if (MP_RECV_SEQ_DIFF(priv,
|
||||
alink->seq, priv->mseq) < 0)
|
||||
alink->seq = priv->mseq;
|
||||
}
|
||||
@ -1508,7 +1550,7 @@ ng_ppp_mp_output(node_p node, struct mbuf *m, meta_p meta)
|
||||
|
||||
shdr = priv->xseq;
|
||||
priv->xseq =
|
||||
(priv->xseq + 1) % MP_SHORT_SEQ_MASK;
|
||||
(priv->xseq + 1) & MP_SHORT_SEQ_MASK;
|
||||
if (firstFragment)
|
||||
shdr |= MP_SHORT_FIRST_FLAG;
|
||||
if (lastFragment)
|
||||
@ -1520,7 +1562,7 @@ ng_ppp_mp_output(node_p node, struct mbuf *m, meta_p meta)
|
||||
|
||||
lhdr = priv->xseq;
|
||||
priv->xseq =
|
||||
(priv->xseq + 1) % MP_LONG_SEQ_MASK;
|
||||
(priv->xseq + 1) & MP_LONG_SEQ_MASK;
|
||||
if (firstFragment)
|
||||
lhdr |= MP_LONG_FIRST_FLAG;
|
||||
if (lastFragment)
|
||||
|
@ -34,7 +34,7 @@
|
||||
* THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* Author: Archie Cobbs <archie@whistle.com>
|
||||
* Author: Archie Cobbs <archie@freebsd.org>
|
||||
*
|
||||
* $FreeBSD$
|
||||
* $Whistle: ng_ppp.h,v 1.8 1999/01/25 02:40:02 archie Exp $
|
||||
@ -45,7 +45,7 @@
|
||||
|
||||
/* Node type name and magic cookie */
|
||||
#define NG_PPP_NODE_TYPE "ppp"
|
||||
#define NGM_PPP_COOKIE 940897794
|
||||
#define NGM_PPP_COOKIE 940897795
|
||||
|
||||
/* Maximum number of supported links */
|
||||
#define NG_PPP_MAX_LINKS 16
|
||||
@ -78,11 +78,29 @@
|
||||
enum {
|
||||
NGM_PPP_SET_CONFIG = 1, /* takes struct ng_ppp_node_conf */
|
||||
NGM_PPP_GET_CONFIG, /* returns ng_ppp_node_conf */
|
||||
NGM_PPP_GET_MP_STATE, /* returns ng_ppp_mp_state */
|
||||
NGM_PPP_GET_LINK_STATS, /* takes link #, returns stats struct */
|
||||
NGM_PPP_CLR_LINK_STATS, /* takes link #, clears link stats */
|
||||
NGM_PPP_GETCLR_LINK_STATS, /* takes link #, returns & clrs stats */
|
||||
};
|
||||
|
||||
/* Multi-link sequence number state (for debugging) */
|
||||
struct ng_ppp_mp_state {
|
||||
int32_t rseq[NG_PPP_MAX_LINKS]; /* highest rec'd MP seq # */
|
||||
int32_t mseq; /* min rseq[i] */
|
||||
int32_t xseq; /* next xmit MP seq # */
|
||||
};
|
||||
|
||||
/* Keep this in sync with the above structure definition */
|
||||
#define NG_PPP_MP_STATE_TYPE_INFO(atype) { \
|
||||
{ \
|
||||
{ "rseq", (atype) }, \
|
||||
{ "mseq", &ng_parse_hint32_type }, \
|
||||
{ "xseq", &ng_parse_hint32_type }, \
|
||||
{ NULL }, \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Per-link config structure */
|
||||
struct ng_ppp_link_conf {
|
||||
u_char enableLink; /* enable this link */
|
||||
|
Loading…
Reference in New Issue
Block a user