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:
Archie Cobbs 2000-10-06 23:42:02 +00:00
parent e6e7337683
commit 6f16db8137
2 changed files with 99 additions and 39 deletions

View File

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

View File

@ -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 */