diff options
| author | Rémi Denis-Courmont <remi.denis-courmont@nokia.com> | 2011-02-24 18:15:01 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2011-02-25 14:19:37 -0500 |
| commit | 8f44fcc72a454c5eb7cbc138bd53f0963f23e87f (patch) | |
| tree | 41b21091270d76526b13782fb0e134b79f15e409 /net/phonet | |
| parent | 0165d69bcb18c5aa220538389c872852243f9725 (diff) | |
Phonet: fix flawed "SYN/ACK" logic
* Do not fail if the peer supports more or less than 3 algorithms.
* Ignore unknown congestion control algorithms instead of failing.
* Simplify congestion algorithm negotiation (largest is best).
* Do not use a static buffer.
* Fix off-by-two read overflow.
* Avoid extra memory copy (in addition to skb_copy_bits()).
The previous code really made no sense.
Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/phonet')
| -rw-r--r-- | net/phonet/pep.c | 125 |
1 files changed, 47 insertions, 78 deletions
diff --git a/net/phonet/pep.c b/net/phonet/pep.c index 0ecab59963e0..b8c31fc928e1 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c | |||
| @@ -108,70 +108,6 @@ static int pep_reply(struct sock *sk, struct sk_buff *oskb, | |||
| 108 | #define PAD 0x00 | 108 | #define PAD 0x00 |
| 109 | 109 | ||
| 110 | #ifdef CONFIG_PHONET_PIPECTRLR | 110 | #ifdef CONFIG_PHONET_PIPECTRLR |
| 111 | static u8 pipe_negotiate_fc(u8 *host_fc, u8 *remote_fc, int len) | ||
| 112 | { | ||
| 113 | int i, j; | ||
| 114 | u8 base_fc, final_fc; | ||
| 115 | |||
| 116 | for (i = 0; i < len; i++) { | ||
| 117 | base_fc = host_fc[i]; | ||
| 118 | for (j = 0; j < len; j++) { | ||
| 119 | if (remote_fc[j] == base_fc) { | ||
| 120 | final_fc = base_fc; | ||
| 121 | goto done; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
| 125 | return -EINVAL; | ||
| 126 | |||
| 127 | done: | ||
| 128 | return final_fc; | ||
| 129 | |||
| 130 | } | ||
| 131 | |||
| 132 | static int pipe_get_flow_info(struct sock *sk, struct sk_buff *skb, | ||
| 133 | u8 *pref_rx_fc, u8 *req_tx_fc) | ||
| 134 | { | ||
| 135 | struct pnpipehdr *hdr; | ||
| 136 | u8 n_sb; | ||
| 137 | |||
| 138 | if (!pskb_may_pull(skb, sizeof(*hdr) + 4)) | ||
| 139 | return -EINVAL; | ||
| 140 | |||
| 141 | hdr = pnp_hdr(skb); | ||
| 142 | n_sb = hdr->data[4]; | ||
| 143 | |||
| 144 | __skb_pull(skb, sizeof(*hdr) + 4); | ||
| 145 | while (n_sb > 0) { | ||
| 146 | u8 type, buf[3], len = sizeof(buf); | ||
| 147 | u8 *data = pep_get_sb(skb, &type, &len, buf); | ||
| 148 | |||
| 149 | if (data == NULL) | ||
| 150 | return -EINVAL; | ||
| 151 | |||
| 152 | switch (type) { | ||
| 153 | case PN_PIPE_SB_REQUIRED_FC_TX: | ||
| 154 | if (len < 3 || (data[2] | data[3] | data[4]) > 3) | ||
| 155 | break; | ||
| 156 | req_tx_fc[0] = data[2]; | ||
| 157 | req_tx_fc[1] = data[3]; | ||
| 158 | req_tx_fc[2] = data[4]; | ||
| 159 | break; | ||
| 160 | |||
| 161 | case PN_PIPE_SB_PREFERRED_FC_RX: | ||
| 162 | if (len < 3 || (data[2] | data[3] | data[4]) > 3) | ||
| 163 | break; | ||
| 164 | pref_rx_fc[0] = data[2]; | ||
| 165 | pref_rx_fc[1] = data[3]; | ||
| 166 | pref_rx_fc[2] = data[4]; | ||
| 167 | break; | ||
| 168 | |||
| 169 | } | ||
| 170 | n_sb--; | ||
| 171 | } | ||
| 172 | return 0; | ||
| 173 | } | ||
| 174 | |||
| 175 | static int pipe_handler_send_req(struct sock *sk, u8 msg_id, gfp_t priority) | 111 | static int pipe_handler_send_req(struct sock *sk, u8 msg_id, gfp_t priority) |
| 176 | { | 112 | { |
| 177 | int len; | 113 | int len; |
| @@ -661,28 +597,61 @@ static void pipe_destruct(struct sock *sk) | |||
| 661 | } | 597 | } |
| 662 | 598 | ||
| 663 | #ifdef CONFIG_PHONET_PIPECTRLR | 599 | #ifdef CONFIG_PHONET_PIPECTRLR |
| 600 | static u8 pipe_negotiate_fc(const u8 *fcs, unsigned n) | ||
| 601 | { | ||
| 602 | unsigned i; | ||
| 603 | u8 final_fc = PN_NO_FLOW_CONTROL; | ||
| 604 | |||
| 605 | for (i = 0; i < n; i++) { | ||
| 606 | u8 fc = fcs[i]; | ||
| 607 | |||
| 608 | if (fc > final_fc && fc < PN_MAX_FLOW_CONTROL) | ||
| 609 | final_fc = fc; | ||
| 610 | } | ||
| 611 | return final_fc; | ||
| 612 | } | ||
| 613 | |||
| 664 | static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb) | 614 | static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb) |
| 665 | { | 615 | { |
| 666 | struct pep_sock *pn = pep_sk(sk); | 616 | struct pep_sock *pn = pep_sk(sk); |
| 667 | u8 host_pref_rx_fc[3] = {3, 2, 1}, host_req_tx_fc[3] = {3, 2, 1}; | 617 | struct pnpipehdr *hdr; |
| 668 | u8 remote_pref_rx_fc[3], remote_req_tx_fc[3]; | 618 | u8 n_sb; |
| 669 | u8 negotiated_rx_fc, negotiated_tx_fc; | 619 | |
| 670 | 620 | if (!pskb_pull(skb, sizeof(*hdr) + 4)) | |
| 671 | pipe_get_flow_info(sk, skb, remote_pref_rx_fc, | 621 | return -EINVAL; |
| 672 | remote_req_tx_fc); | 622 | |
| 673 | negotiated_tx_fc = pipe_negotiate_fc(remote_req_tx_fc, | 623 | hdr = pnp_hdr(skb); |
| 674 | host_pref_rx_fc, | 624 | |
| 675 | sizeof(host_pref_rx_fc)); | 625 | /* Parse sub-blocks */ |
| 676 | negotiated_rx_fc = pipe_negotiate_fc(host_req_tx_fc, | 626 | n_sb = hdr->data[4]; |
| 677 | remote_pref_rx_fc, | 627 | while (n_sb > 0) { |
| 678 | sizeof(host_pref_rx_fc)); | 628 | u8 type, buf[6], len = sizeof(buf); |
| 629 | const u8 *data = pep_get_sb(skb, &type, &len, buf); | ||
| 630 | |||
| 631 | if (data == NULL) | ||
| 632 | return -EINVAL; | ||
| 633 | |||
| 634 | switch (type) { | ||
| 635 | case PN_PIPE_SB_REQUIRED_FC_TX: | ||
| 636 | if (len < 2 || len < data[0]) | ||
| 637 | break; | ||
| 638 | pn->tx_fc = pipe_negotiate_fc(data + 2, len - 2); | ||
| 639 | break; | ||
| 640 | |||
| 641 | case PN_PIPE_SB_PREFERRED_FC_RX: | ||
| 642 | if (len < 2 || len < data[0]) | ||
| 643 | break; | ||
| 644 | pn->rx_fc = pipe_negotiate_fc(data + 2, len - 2); | ||
| 645 | break; | ||
| 646 | |||
| 647 | } | ||
| 648 | n_sb--; | ||
| 649 | } | ||
| 679 | 650 | ||
| 680 | sk->sk_state = TCP_SYN_RECV; | 651 | sk->sk_state = TCP_SYN_RECV; |
| 681 | sk->sk_backlog_rcv = pipe_do_rcv; | 652 | sk->sk_backlog_rcv = pipe_do_rcv; |
| 682 | sk->sk_destruct = pipe_destruct; | 653 | sk->sk_destruct = pipe_destruct; |
| 683 | pn->rx_credits = 0; | 654 | pn->rx_credits = 0; |
| 684 | pn->rx_fc = negotiated_rx_fc; | ||
| 685 | pn->tx_fc = negotiated_tx_fc; | ||
| 686 | sk->sk_state_change(sk); | 655 | sk->sk_state_change(sk); |
| 687 | 656 | ||
| 688 | return pipe_handler_send_created_ind(sk, PNS_PIPE_CREATED_IND); | 657 | return pipe_handler_send_created_ind(sk, PNS_PIPE_CREATED_IND); |
