diff options
Diffstat (limited to 'drivers/net/pppoe.c')
| -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, |
