* Transmit an outgoing frame, or just an ack if m is NULL. */
| 583 | * Transmit an outgoing frame, or just an ack if m is NULL. |
| 584 | */ |
| 585 | static int |
| 586 | ng_pptpgre_xmit(hpriv_p hpriv, item_p item) |
| 587 | { |
| 588 | const priv_p priv = NG_NODE_PRIVATE(hpriv->node); |
| 589 | u_char buf[sizeof(struct greheader) + 2 * sizeof(u_int32_t)]; |
| 590 | struct greheader *const gre = (struct greheader *)buf; |
| 591 | int grelen, error; |
| 592 | struct mbuf *m; |
| 593 | |
| 594 | mtx_assert(&hpriv->mtx, MA_OWNED); |
| 595 | |
| 596 | if (item) { |
| 597 | NGI_GET_M(item, m); |
| 598 | } else { |
| 599 | m = NULL; |
| 600 | } |
| 601 | /* Check if there's data */ |
| 602 | if (m != NULL) { |
| 603 | /* Check if windowing is enabled */ |
| 604 | if (hpriv->conf.enableWindowing) { |
| 605 | /* Is our transmit window full? */ |
| 606 | if ((u_int32_t)PPTP_SEQ_DIFF(hpriv->xmitSeq, |
| 607 | hpriv->recvAck) >= hpriv->xmitWin) { |
| 608 | priv->stats.xmitDrops++; |
| 609 | ERROUT(ENOBUFS); |
| 610 | } |
| 611 | } |
| 612 | |
| 613 | /* Sanity check frame length */ |
| 614 | if (m->m_pkthdr.len > PPTP_MAX_PAYLOAD) { |
| 615 | priv->stats.xmitTooBig++; |
| 616 | ERROUT(EMSGSIZE); |
| 617 | } |
| 618 | } else { |
| 619 | priv->stats.xmitLoneAcks++; |
| 620 | } |
| 621 | |
| 622 | /* Build GRE header */ |
| 623 | be32enc(gre, PPTP_INIT_VALUE); |
| 624 | be16enc(&gre->length, (m != NULL) ? m->m_pkthdr.len : 0); |
| 625 | be16enc(&gre->cid, hpriv->conf.peerCid); |
| 626 | |
| 627 | /* Include sequence number if packet contains any data */ |
| 628 | if (m != NULL) { |
| 629 | gre->hasSeq = 1; |
| 630 | if (hpriv->conf.enableWindowing) { |
| 631 | hpriv->timeSent[hpriv->xmitSeq - hpriv->recvAck] |
| 632 | = ng_pptpgre_time(); |
| 633 | } |
| 634 | hpriv->xmitSeq++; |
| 635 | be32enc(&gre->data[0], hpriv->xmitSeq); |
| 636 | } |
| 637 | |
| 638 | /* Include acknowledgement (and stop send ack timer) if needed */ |
| 639 | if (hpriv->conf.enableAlwaysAck || hpriv->xmitAck != hpriv->recvSeq) { |
| 640 | gre->hasAck = 1; |
| 641 | be32enc(&gre->data[gre->hasSeq], hpriv->recvSeq); |
| 642 | hpriv->xmitAck = hpriv->recvSeq; |
no test coverage detected