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