Deleted Added
sdiff udiff text old ( 129823 ) new ( 131155 )
full compact
1
2/*
3 * ng_ppp.c
4 *
5 * Copyright (c) 1996-2000 Whistle Communications, Inc.
6 * All rights reserved.
7 *
8 * Subject to the following obligations and disclaimer of warranty, use and

--- 22 unchanged lines hidden (view full) ---

31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35 * OF SUCH DAMAGE.
36 *
37 * Author: Archie Cobbs <archie@freebsd.org>
38 *
39 * $FreeBSD: head/sys/netgraph/ng_ppp.c 131155 2004-06-26 22:24:16Z julian $
40 * $Whistle: ng_ppp.c,v 1.24 1999/11/01 09:24:52 julian Exp $
41 */
42
43/*
44 * PPP node type.
45 */
46
47#include <sys/param.h>

--- 85 unchanged lines hidden (view full) ---

133
134/* We store incoming fragments this way */
135struct ng_ppp_frag {
136 int seq; /* fragment seq# */
137 u_char first; /* First in packet? */
138 u_char last; /* Last in packet? */
139 struct timeval timestamp; /* time of reception */
140 struct mbuf *data; /* Fragment data */
141 TAILQ_ENTRY(ng_ppp_frag) f_qent; /* Fragment queue */
142};
143
144/* We use integer indicies to refer to the non-link hooks */
145static const char *const ng_ppp_hook_names[] = {
146 NG_PPP_HOOK_ATALK,
147#define HOOK_INDEX_ATALK 0
148 NG_PPP_HOOK_BYPASS,

--- 72 unchanged lines hidden (view full) ---

221
222/* Helper functions */
223static int ng_ppp_input(node_p node, int bypass,
224 int linkNum, item_p item);
225static int ng_ppp_output(node_p node, int bypass, int proto,
226 int linkNum, item_p item);
227static int ng_ppp_mp_input(node_p node, int linkNum, item_p item);
228static int ng_ppp_check_packet(node_p node);
229static void ng_ppp_get_packet(node_p node, struct mbuf **mp);
230static int ng_ppp_frag_process(node_p node);
231static int ng_ppp_frag_trim(node_p node);
232static void ng_ppp_frag_timeout(void *arg);
233static void ng_ppp_frag_checkstale(node_p node);
234static void ng_ppp_frag_reset(node_p node);
235static int ng_ppp_mp_output(node_p node, struct mbuf *m);
236static void ng_ppp_mp_strategy(node_p node, int len, int *distrib);
237static int ng_ppp_intcmp(const void *v1, const void *v2);
238static struct mbuf *ng_ppp_addproto(struct mbuf *m, int proto, int compOK);
239static struct mbuf *ng_ppp_prepend(struct mbuf *m, const void *buf, int len);
240static int ng_ppp_config_valid(node_p node,
241 const struct ng_ppp_node_conf *newConf);
242static void ng_ppp_update(node_p node, int newConf);
243static void ng_ppp_start_frag_timer(node_p node);

--- 753 unchanged lines hidden (view full) ---

997 linkNum == NG_PPP_BUNDLE_LINKNUM
998 || link->conf.enableProtoComp)) == NULL) {
999 NG_FREE_ITEM(item);
1000 return (ENOBUFS);
1001 }
1002
1003 /* Special handling for the MP virtual link */
1004 if (linkNum == NG_PPP_BUNDLE_LINKNUM) {
1005 /* discard the queue item */
1006 NG_FREE_ITEM(item);
1007 return ng_ppp_mp_output(node, m);
1008 }
1009
1010 /* Prepend address and control field (unless compressed) */
1011 if (proto == PROT_LCP || !link->conf.enableACFComp) {
1012 if ((m = ng_ppp_prepend(m, &ng_ppp_acf, 2)) == NULL) {
1013 NG_FREE_ITEM(item);
1014 return (ENOBUFS);
1015 }

--- 69 unchanged lines hidden (view full) ---

1085ng_ppp_mp_input(node_p node, int linkNum, item_p item)
1086{
1087 const priv_p priv = NG_NODE_PRIVATE(node);
1088 struct ng_ppp_link *const link = &priv->links[linkNum];
1089 struct ng_ppp_frag frag0, *frag = &frag0;
1090 struct ng_ppp_frag *qent;
1091 int i, diff, inserted;
1092 struct mbuf *m;
1093
1094 NGI_GET_M(item, m);
1095 NG_FREE_ITEM(item);
1096 /* Stats */
1097 priv->bundleStats.recvFrames++;
1098 priv->bundleStats.recvOctets += m->m_pkthdr.len;
1099
1100 /* Extract fragment information from MP header */
1101 if (priv->conf.recvShortSeq) {
1102 u_int16_t shdr;
1103
1104 if (m->m_pkthdr.len < 2) {
1105 link->stats.runts++;
1106 NG_FREE_M(m);
1107 return (EINVAL);
1108 }
1109 if (m->m_len < 2 && (m = m_pullup(m, 2)) == NULL)
1110 return (ENOBUFS);
1111
1112 shdr = ntohs(*mtod(m, u_int16_t *));
1113 frag->seq = MP_SHORT_EXTEND(shdr);
1114 frag->first = (shdr & MP_SHORT_FIRST_FLAG) != 0;
1115 frag->last = (shdr & MP_SHORT_LAST_FLAG) != 0;
1116 diff = MP_SHORT_SEQ_DIFF(frag->seq, priv->mseq);
1117 m_adj(m, 2);
1118 } else {
1119 u_int32_t lhdr;
1120
1121 if (m->m_pkthdr.len < 4) {
1122 link->stats.runts++;
1123 NG_FREE_M(m);
1124 return (EINVAL);
1125 }
1126 if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL)
1127 return (ENOBUFS);
1128
1129 lhdr = ntohl(*mtod(m, u_int32_t *));
1130 frag->seq = MP_LONG_EXTEND(lhdr);
1131 frag->first = (lhdr & MP_LONG_FIRST_FLAG) != 0;
1132 frag->last = (lhdr & MP_LONG_LAST_FLAG) != 0;
1133 diff = MP_LONG_SEQ_DIFF(frag->seq, priv->mseq);
1134 m_adj(m, 4);
1135 }
1136 frag->data = m;
1137 getmicrouptime(&frag->timestamp);
1138
1139 /* If sequence number is < MSEQ, we've already declared this
1140 fragment as lost, so we have no choice now but to drop it */
1141 if (diff < 0) {
1142 link->stats.dropFragments++;
1143 NG_FREE_M(m);
1144 return (0);
1145 }
1146
1147 /* Update highest received sequence number on this link and MSEQ */
1148 priv->mseq = link->seq = frag->seq;
1149 for (i = 0; i < priv->numActiveLinks; i++) {
1150 struct ng_ppp_link *const alink =
1151 &priv->links[priv->activeLinks[i]];
1152
1153 if (MP_RECV_SEQ_DIFF(priv, alink->seq, priv->mseq) < 0)
1154 priv->mseq = alink->seq;
1155 }
1156
1157 /* Allocate a new frag struct for the queue */
1158 MALLOC(frag, struct ng_ppp_frag *, sizeof(*frag), M_NETGRAPH_PPP, M_NOWAIT);
1159 if (frag == NULL) {
1160 NG_FREE_M(m);
1161 ng_ppp_frag_process(node);
1162 return (ENOMEM);
1163 }
1164 *frag = frag0;
1165
1166 /* Add fragment to queue, which is sorted by sequence number */
1167 inserted = 0;
1168 TAILQ_FOREACH_REVERSE(qent, &priv->frags, ng_ppp_fraglist, f_qent) {
1169 diff = MP_RECV_SEQ_DIFF(priv, frag->seq, qent->seq);
1170 if (diff > 0) {
1171 TAILQ_INSERT_AFTER(&priv->frags, qent, frag, f_qent);
1172 inserted = 1;
1173 break;
1174 } else if (diff == 0) { /* should never happen! */
1175 link->stats.dupFragments++;
1176 NG_FREE_M(frag->data);
1177 FREE(frag, M_NETGRAPH_PPP);
1178 return (EINVAL);
1179 }
1180 }
1181 if (!inserted)
1182 TAILQ_INSERT_HEAD(&priv->frags, frag, f_qent);
1183 priv->qlen++;
1184

--- 35 unchanged lines hidden (view full) ---

1220 return (1);
1221}
1222
1223/*
1224 * Pull a completed packet off the head of the incoming fragment queue.
1225 * This assumes there is a completed packet there to pull off.
1226 */
1227static void
1228ng_ppp_get_packet(node_p node, struct mbuf **mp)
1229{
1230 const priv_p priv = NG_NODE_PRIVATE(node);
1231 struct ng_ppp_frag *qent, *qnext;
1232 struct mbuf *m = NULL, *tail;
1233
1234 qent = TAILQ_FIRST(&priv->frags);
1235 KASSERT(!TAILQ_EMPTY(&priv->frags) && qent->first,
1236 ("%s: no packet", __func__));
1237 for (tail = NULL; qent != NULL; qent = qnext) {
1238 qnext = TAILQ_NEXT(qent, f_qent);
1239 KASSERT(!TAILQ_EMPTY(&priv->frags),
1240 ("%s: empty q", __func__));
1241 TAILQ_REMOVE(&priv->frags, qent, f_qent);
1242 if (tail == NULL)
1243 tail = m = qent->data;
1244 else {
1245 m->m_pkthdr.len += qent->data->m_pkthdr.len;
1246 tail->m_next = qent->data;
1247 }
1248 while (tail->m_next != NULL)
1249 tail = tail->m_next;
1250 if (qent->last)
1251 qnext = NULL;
1252 FREE(qent, M_NETGRAPH_PPP);
1253 priv->qlen--;
1254 }

--- 38 unchanged lines hidden (view full) ---

1293
1294 /* Remove fragment and all others in the same packet */
1295 while ((qent = TAILQ_FIRST(&priv->frags)) != qnext) {
1296 KASSERT(!TAILQ_EMPTY(&priv->frags),
1297 ("%s: empty q", __func__));
1298 priv->bundleStats.dropFragments++;
1299 TAILQ_REMOVE(&priv->frags, qent, f_qent);
1300 NG_FREE_M(qent->data);
1301 FREE(qent, M_NETGRAPH_PPP);
1302 priv->qlen--;
1303 removed = 1;
1304 }
1305 }
1306 return (removed);
1307}
1308
1309/*
1310 * Run the queue, restoring the queue invariants
1311 */
1312static int
1313ng_ppp_frag_process(node_p node)
1314{
1315 const priv_p priv = NG_NODE_PRIVATE(node);
1316 struct mbuf *m;
1317 item_p item;
1318
1319 /* Deliver any deliverable packets */
1320 while (ng_ppp_check_packet(node)) {
1321 ng_ppp_get_packet(node, &m);
1322 item = ng_package_data(m, NULL);
1323 ng_ppp_input(node, 0, NG_PPP_BUNDLE_LINKNUM, item);
1324 }
1325
1326 /* Delete dead fragments and try again */
1327 if (ng_ppp_frag_trim(node)) {
1328 while (ng_ppp_check_packet(node)) {
1329 ng_ppp_get_packet(node, &m);
1330 item = ng_package_data(m, NULL);
1331 ng_ppp_input(node, 0, NG_PPP_BUNDLE_LINKNUM, item);
1332 }
1333 }
1334
1335 /* Check for stale fragments while we're here */
1336 ng_ppp_frag_checkstale(node);
1337
1338 /* Check queue length */

--- 18 unchanged lines hidden (view full) ---

1357 alink->seq = priv->mseq;
1358 }
1359 }
1360
1361 /* Drop it */
1362 priv->bundleStats.dropFragments++;
1363 TAILQ_REMOVE(&priv->frags, qent, f_qent);
1364 NG_FREE_M(qent->data);
1365 FREE(qent, M_NETGRAPH_PPP);
1366 priv->qlen--;
1367
1368 /* Process queue again */
1369 return ng_ppp_frag_process(node);
1370 }
1371
1372 /* Done */

--- 14 unchanged lines hidden (view full) ---

1387 */
1388static void
1389ng_ppp_frag_checkstale(node_p node)
1390{
1391 const priv_p priv = NG_NODE_PRIVATE(node);
1392 struct ng_ppp_frag *qent, *beg, *end;
1393 struct timeval now, age;
1394 struct mbuf *m;
1395 int i, seq;
1396 item_p item;
1397 int endseq;
1398
1399 now.tv_sec = 0; /* uninitialized state */
1400 while (1) {
1401
1402 /* If queue is empty, we're done */

--- 31 unchanged lines hidden (view full) ---

1434
1435 /* Throw away junk fragments in front of the completed packet */
1436 while ((qent = TAILQ_FIRST(&priv->frags)) != beg) {
1437 KASSERT(!TAILQ_EMPTY(&priv->frags),
1438 ("%s: empty q", __func__));
1439 priv->bundleStats.dropFragments++;
1440 TAILQ_REMOVE(&priv->frags, qent, f_qent);
1441 NG_FREE_M(qent->data);
1442 FREE(qent, M_NETGRAPH_PPP);
1443 priv->qlen--;
1444 }
1445
1446 /* Extract completed packet */
1447 endseq = end->seq;
1448 ng_ppp_get_packet(node, &m);
1449
1450 /* Bump MSEQ if necessary */
1451 if (MP_RECV_SEQ_DIFF(priv, priv->mseq, endseq) < 0) {
1452 priv->mseq = endseq;
1453 for (i = 0; i < priv->numActiveLinks; i++) {
1454 struct ng_ppp_link *const alink =
1455 &priv->links[priv->activeLinks[i]];
1456
1457 if (MP_RECV_SEQ_DIFF(priv,
1458 alink->seq, priv->mseq) < 0)
1459 alink->seq = priv->mseq;
1460 }
1461 }
1462
1463 /* Deliver packet */
1464 item = ng_package_data(m, NULL);
1465 ng_ppp_input(node, 0, NG_PPP_BUNDLE_LINKNUM, item);
1466 }
1467}
1468
1469/*
1470 * Periodically call ng_ppp_frag_checkstale()
1471 */
1472static void

--- 24 unchanged lines hidden (view full) ---

1497 splx(s);
1498}
1499
1500/*
1501 * Deliver a frame out on the bundle, i.e., figure out how to fragment
1502 * the frame across the individual PPP links and do so.
1503 */
1504static int
1505ng_ppp_mp_output(node_p node, struct mbuf *m)
1506{
1507 const priv_p priv = NG_NODE_PRIVATE(node);
1508 const int hdr_len = priv->conf.xmitShortSeq ? 2 : 4;
1509 int distrib[NG_PPP_MAX_LINKS];
1510 int firstFragment;
1511 int activeLinkNum;
1512 item_p item;
1513
1514 /* At least one link must be active */
1515 if (priv->numActiveLinks == 0) {
1516 NG_FREE_M(m);
1517 return (ENETDOWN);
1518 }
1519
1520 /* Round-robin strategy */
1521 if (priv->conf.enableRoundRobin || m->m_pkthdr.len < MP_MIN_FRAG_LEN) {
1522 activeLinkNum = priv->lastLink++ % priv->numActiveLinks;
1523 bzero(&distrib, priv->numActiveLinks * sizeof(distrib[0]));
1524 distrib[activeLinkNum] = m->m_pkthdr.len;

--- 29 unchanged lines hidden (view full) ---

1554 activeLinkNum >= 0; activeLinkNum--) {
1555 const int linkNum = priv->activeLinks[activeLinkNum];
1556 struct ng_ppp_link *const link = &priv->links[linkNum];
1557
1558 /* Deliver fragment(s) out the next link */
1559 for ( ; distrib[activeLinkNum] > 0; firstFragment = 0) {
1560 int len, lastFragment, error;
1561 struct mbuf *m2;
1562
1563 /* Calculate fragment length; don't exceed link MTU */
1564 len = distrib[activeLinkNum];
1565 if (len > link->conf.mru - hdr_len)
1566 len = link->conf.mru - hdr_len;
1567 distrib[activeLinkNum] -= len;
1568 lastFragment = (len == m->m_pkthdr.len);
1569
1570 /* Split off next fragment as "m2" */
1571 m2 = m;
1572 if (!lastFragment) {
1573 struct mbuf *n = m_split(m, len, M_DONTWAIT);
1574
1575 if (n == NULL) {
1576 NG_FREE_M(m);
1577 return (ENOMEM);
1578 }
1579 m = n;
1580 }
1581
1582 /* Prepend MP header */
1583 if (priv->conf.xmitShortSeq) {
1584 u_int16_t shdr;

--- 18 unchanged lines hidden (view full) ---

1603 if (lastFragment)
1604 lhdr |= MP_LONG_LAST_FLAG;
1605 lhdr = htonl(lhdr);
1606 m2 = ng_ppp_prepend(m2, &lhdr, 4);
1607 }
1608 if (m2 == NULL) {
1609 if (!lastFragment)
1610 m_freem(m);
1611 return (ENOBUFS);
1612 }
1613
1614 /* Send fragment */
1615 item = ng_package_data(m2, NULL);
1616 error = ng_ppp_output(node, 0, PROT_MP, linkNum, item);
1617 if (error != 0) {
1618 if (!lastFragment)
1619 NG_FREE_M(m);
1620 return (error);
1621 }
1622 }
1623 }
1624
1625 /* Done */
1626 return (0);
1627}

--- 393 unchanged lines hidden (view full) ---

2021ng_ppp_frag_reset(node_p node)
2022{
2023 const priv_p priv = NG_NODE_PRIVATE(node);
2024 struct ng_ppp_frag *qent, *qnext;
2025
2026 for (qent = TAILQ_FIRST(&priv->frags); qent; qent = qnext) {
2027 qnext = TAILQ_NEXT(qent, f_qent);
2028 NG_FREE_M(qent->data);
2029 FREE(qent, M_NETGRAPH_PPP);
2030 }
2031 TAILQ_INIT(&priv->frags);
2032 priv->qlen = 0;
2033}
2034
2035/*
2036 * Start fragment queue timer

--- 31 unchanged lines hidden ---