diff options
-rw-r--r-- | drivers/net/pppoe.c | 52 |
1 files changed, 32 insertions, 20 deletions
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 860bb0f60f68..86e56f1f2f0b 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c | |||
@@ -7,6 +7,12 @@ | |||
7 | * | 7 | * |
8 | * Version: 0.7.0 | 8 | * Version: 0.7.0 |
9 | * | 9 | * |
10 | * 070228 : Fix to allow multiple sessions with same remote MAC and same | ||
11 | * session id by including the local device ifindex in the | ||
12 | * tuple identifying a session. This also ensures packets can't | ||
13 | * be injected into a session from interfaces other than the one | ||
14 | * specified by userspace. Florian Zumbiehl <florz@florz.de> | ||
15 | * (Oh, BTW, this one is YYMMDD, in case you were wondering ...) | ||
10 | * 220102 : Fix module use count on failure in pppoe_create, pppox_sk -acme | 16 | * 220102 : Fix module use count on failure in pppoe_create, pppox_sk -acme |
11 | * 030700 : Fixed connect logic to allow for disconnect. | 17 | * 030700 : Fixed connect logic to allow for disconnect. |
12 | * 270700 : Fixed potential SMP problems; we must protect against | 18 | * 270700 : Fixed potential SMP problems; we must protect against |
@@ -127,14 +133,14 @@ static struct pppox_sock *item_hash_table[PPPOE_HASH_SIZE]; | |||
127 | * Set/get/delete/rehash items (internal versions) | 133 | * Set/get/delete/rehash items (internal versions) |
128 | * | 134 | * |
129 | **********************************************************************/ | 135 | **********************************************************************/ |
130 | static struct pppox_sock *__get_item(unsigned long sid, unsigned char *addr) | 136 | static struct pppox_sock *__get_item(unsigned long sid, unsigned char *addr, int ifindex) |
131 | { | 137 | { |
132 | int hash = hash_item(sid, addr); | 138 | int hash = hash_item(sid, addr); |
133 | struct pppox_sock *ret; | 139 | struct pppox_sock *ret; |
134 | 140 | ||
135 | ret = item_hash_table[hash]; | 141 | ret = item_hash_table[hash]; |
136 | 142 | ||
137 | while (ret && !cmp_addr(&ret->pppoe_pa, sid, addr)) | 143 | while (ret && !(cmp_addr(&ret->pppoe_pa, sid, addr) && ret->pppoe_dev->ifindex == ifindex)) |
138 | ret = ret->next; | 144 | ret = ret->next; |
139 | 145 | ||
140 | return ret; | 146 | return ret; |
@@ -147,21 +153,19 @@ static int __set_item(struct pppox_sock *po) | |||
147 | 153 | ||
148 | ret = item_hash_table[hash]; | 154 | ret = item_hash_table[hash]; |
149 | while (ret) { | 155 | while (ret) { |
150 | if (cmp_2_addr(&ret->pppoe_pa, &po->pppoe_pa)) | 156 | if (cmp_2_addr(&ret->pppoe_pa, &po->pppoe_pa) && ret->pppoe_dev->ifindex == po->pppoe_dev->ifindex) |
151 | return -EALREADY; | 157 | return -EALREADY; |
152 | 158 | ||
153 | ret = ret->next; | 159 | ret = ret->next; |
154 | } | 160 | } |
155 | 161 | ||
156 | if (!ret) { | 162 | po->next = item_hash_table[hash]; |
157 | po->next = item_hash_table[hash]; | 163 | item_hash_table[hash] = po; |
158 | item_hash_table[hash] = po; | ||
159 | } | ||
160 | 164 | ||
161 | return 0; | 165 | return 0; |
162 | } | 166 | } |
163 | 167 | ||
164 | static struct pppox_sock *__delete_item(unsigned long sid, char *addr) | 168 | static struct pppox_sock *__delete_item(unsigned long sid, char *addr, int ifindex) |
165 | { | 169 | { |
166 | int hash = hash_item(sid, addr); | 170 | int hash = hash_item(sid, addr); |
167 | struct pppox_sock *ret, **src; | 171 | struct pppox_sock *ret, **src; |
@@ -170,7 +174,7 @@ static struct pppox_sock *__delete_item(unsigned long sid, char *addr) | |||
170 | src = &item_hash_table[hash]; | 174 | src = &item_hash_table[hash]; |
171 | 175 | ||
172 | while (ret) { | 176 | while (ret) { |
173 | if (cmp_addr(&ret->pppoe_pa, sid, addr)) { | 177 | if (cmp_addr(&ret->pppoe_pa, sid, addr) && ret->pppoe_dev->ifindex == ifindex) { |
174 | *src = ret->next; | 178 | *src = ret->next; |
175 | break; | 179 | break; |
176 | } | 180 | } |
@@ -188,12 +192,12 @@ static struct pppox_sock *__delete_item(unsigned long sid, char *addr) | |||
188 | * | 192 | * |
189 | **********************************************************************/ | 193 | **********************************************************************/ |
190 | static inline struct pppox_sock *get_item(unsigned long sid, | 194 | static inline struct pppox_sock *get_item(unsigned long sid, |
191 | unsigned char *addr) | 195 | unsigned char *addr, int ifindex) |
192 | { | 196 | { |
193 | struct pppox_sock *po; | 197 | struct pppox_sock *po; |
194 | 198 | ||
195 | read_lock_bh(&pppoe_hash_lock); | 199 | read_lock_bh(&pppoe_hash_lock); |
196 | po = __get_item(sid, addr); | 200 | po = __get_item(sid, addr, ifindex); |
197 | if (po) | 201 | if (po) |
198 | sock_hold(sk_pppox(po)); | 202 | sock_hold(sk_pppox(po)); |
199 | read_unlock_bh(&pppoe_hash_lock); | 203 | read_unlock_bh(&pppoe_hash_lock); |
@@ -203,7 +207,15 @@ static inline struct pppox_sock *get_item(unsigned long sid, | |||
203 | 207 | ||
204 | static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp) | 208 | static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp) |
205 | { | 209 | { |
206 | return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote); | 210 | struct net_device *dev = NULL; |
211 | int ifindex; | ||
212 | |||
213 | dev = dev_get_by_name(sp->sa_addr.pppoe.dev); | ||
214 | if(!dev) | ||
215 | return NULL; | ||
216 | ifindex = dev->ifindex; | ||
217 | dev_put(dev); | ||
218 | return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote, ifindex); | ||
207 | } | 219 | } |
208 | 220 | ||
209 | static inline int set_item(struct pppox_sock *po) | 221 | static inline int set_item(struct pppox_sock *po) |
@@ -220,12 +232,12 @@ static inline int set_item(struct pppox_sock *po) | |||
220 | return i; | 232 | return i; |
221 | } | 233 | } |
222 | 234 | ||
223 | static inline struct pppox_sock *delete_item(unsigned long sid, char *addr) | 235 | static inline struct pppox_sock *delete_item(unsigned long sid, char *addr, int ifindex) |
224 | { | 236 | { |
225 | struct pppox_sock *ret; | 237 | struct pppox_sock *ret; |
226 | 238 | ||
227 | write_lock_bh(&pppoe_hash_lock); | 239 | write_lock_bh(&pppoe_hash_lock); |
228 | ret = __delete_item(sid, addr); | 240 | ret = __delete_item(sid, addr, ifindex); |
229 | write_unlock_bh(&pppoe_hash_lock); | 241 | write_unlock_bh(&pppoe_hash_lock); |
230 | 242 | ||
231 | return ret; | 243 | return ret; |
@@ -391,7 +403,7 @@ static int pppoe_rcv(struct sk_buff *skb, | |||
391 | 403 | ||
392 | ph = (struct pppoe_hdr *) skb->nh.raw; | 404 | ph = (struct pppoe_hdr *) skb->nh.raw; |
393 | 405 | ||
394 | po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source); | 406 | po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex); |
395 | if (po != NULL) | 407 | if (po != NULL) |
396 | return sk_receive_skb(sk_pppox(po), skb, 0); | 408 | return sk_receive_skb(sk_pppox(po), skb, 0); |
397 | drop: | 409 | drop: |
@@ -425,7 +437,7 @@ static int pppoe_disc_rcv(struct sk_buff *skb, | |||
425 | if (ph->code != PADT_CODE) | 437 | if (ph->code != PADT_CODE) |
426 | goto abort; | 438 | goto abort; |
427 | 439 | ||
428 | po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source); | 440 | po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex); |
429 | if (po) { | 441 | if (po) { |
430 | struct sock *sk = sk_pppox(po); | 442 | struct sock *sk = sk_pppox(po); |
431 | 443 | ||
@@ -517,7 +529,7 @@ static int pppoe_release(struct socket *sock) | |||
517 | 529 | ||
518 | po = pppox_sk(sk); | 530 | po = pppox_sk(sk); |
519 | if (po->pppoe_pa.sid) { | 531 | if (po->pppoe_pa.sid) { |
520 | delete_item(po->pppoe_pa.sid, po->pppoe_pa.remote); | 532 | delete_item(po->pppoe_pa.sid, po->pppoe_pa.remote, po->pppoe_dev->ifindex); |
521 | } | 533 | } |
522 | 534 | ||
523 | if (po->pppoe_dev) | 535 | if (po->pppoe_dev) |
@@ -539,7 +551,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
539 | int sockaddr_len, int flags) | 551 | int sockaddr_len, int flags) |
540 | { | 552 | { |
541 | struct sock *sk = sock->sk; | 553 | struct sock *sk = sock->sk; |
542 | struct net_device *dev = NULL; | 554 | struct net_device *dev; |
543 | struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr; | 555 | struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr; |
544 | struct pppox_sock *po = pppox_sk(sk); | 556 | struct pppox_sock *po = pppox_sk(sk); |
545 | int error; | 557 | int error; |
@@ -565,7 +577,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
565 | pppox_unbind_sock(sk); | 577 | pppox_unbind_sock(sk); |
566 | 578 | ||
567 | /* Delete the old binding */ | 579 | /* Delete the old binding */ |
568 | delete_item(po->pppoe_pa.sid,po->pppoe_pa.remote); | 580 | delete_item(po->pppoe_pa.sid,po->pppoe_pa.remote,po->pppoe_dev->ifindex); |
569 | 581 | ||
570 | if(po->pppoe_dev) | 582 | if(po->pppoe_dev) |
571 | dev_put(po->pppoe_dev); | 583 | dev_put(po->pppoe_dev); |
@@ -705,7 +717,7 @@ static int pppoe_ioctl(struct socket *sock, unsigned int cmd, | |||
705 | break; | 717 | break; |
706 | 718 | ||
707 | /* PPPoE address from the user specifies an outbound | 719 | /* PPPoE address from the user specifies an outbound |
708 | PPPoE address to which frames are forwarded to */ | 720 | PPPoE address which frames are forwarded to */ |
709 | err = -EFAULT; | 721 | err = -EFAULT; |
710 | if (copy_from_user(&po->pppoe_relay, | 722 | if (copy_from_user(&po->pppoe_relay, |
711 | (void __user *)arg, | 723 | (void __user *)arg, |