diff options
Diffstat (limited to 'net/core/netpoll.c')
| -rw-r--r-- | net/core/netpoll.c | 169 |
1 files changed, 106 insertions, 63 deletions
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 0b4d0d35ef40..7aa697253765 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
| @@ -407,11 +407,24 @@ static void arp_reply(struct sk_buff *skb) | |||
| 407 | __be32 sip, tip; | 407 | __be32 sip, tip; |
| 408 | unsigned char *sha; | 408 | unsigned char *sha; |
| 409 | struct sk_buff *send_skb; | 409 | struct sk_buff *send_skb; |
| 410 | struct netpoll *np = NULL; | 410 | struct netpoll *np, *tmp; |
| 411 | unsigned long flags; | ||
| 412 | int hits = 0; | ||
| 413 | |||
| 414 | if (list_empty(&npinfo->rx_np)) | ||
| 415 | return; | ||
| 416 | |||
| 417 | /* Before checking the packet, we do some early | ||
| 418 | inspection whether this is interesting at all */ | ||
| 419 | spin_lock_irqsave(&npinfo->rx_lock, flags); | ||
| 420 | list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { | ||
| 421 | if (np->dev == skb->dev) | ||
| 422 | hits++; | ||
| 423 | } | ||
| 424 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | ||
| 411 | 425 | ||
| 412 | if (npinfo->rx_np && npinfo->rx_np->dev == skb->dev) | 426 | /* No netpoll struct is using this dev */ |
| 413 | np = npinfo->rx_np; | 427 | if (!hits) |
| 414 | if (!np) | ||
| 415 | return; | 428 | return; |
| 416 | 429 | ||
| 417 | /* No arp on this interface */ | 430 | /* No arp on this interface */ |
| @@ -437,77 +450,91 @@ static void arp_reply(struct sk_buff *skb) | |||
| 437 | arp_ptr += skb->dev->addr_len; | 450 | arp_ptr += skb->dev->addr_len; |
| 438 | memcpy(&sip, arp_ptr, 4); | 451 | memcpy(&sip, arp_ptr, 4); |
| 439 | arp_ptr += 4; | 452 | arp_ptr += 4; |
| 440 | /* if we actually cared about dst hw addr, it would get copied here */ | 453 | /* If we actually cared about dst hw addr, |
| 454 | it would get copied here */ | ||
| 441 | arp_ptr += skb->dev->addr_len; | 455 | arp_ptr += skb->dev->addr_len; |
| 442 | memcpy(&tip, arp_ptr, 4); | 456 | memcpy(&tip, arp_ptr, 4); |
| 443 | 457 | ||
| 444 | /* Should we ignore arp? */ | 458 | /* Should we ignore arp? */ |
| 445 | if (tip != np->local_ip || | 459 | if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) |
| 446 | ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) | ||
| 447 | return; | 460 | return; |
| 448 | 461 | ||
| 449 | size = arp_hdr_len(skb->dev); | 462 | size = arp_hdr_len(skb->dev); |
| 450 | send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev), | ||
| 451 | LL_RESERVED_SPACE(np->dev)); | ||
| 452 | 463 | ||
| 453 | if (!send_skb) | 464 | spin_lock_irqsave(&npinfo->rx_lock, flags); |
| 454 | return; | 465 | list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { |
| 455 | 466 | if (tip != np->local_ip) | |
| 456 | skb_reset_network_header(send_skb); | 467 | continue; |
| 457 | arp = (struct arphdr *) skb_put(send_skb, size); | ||
| 458 | send_skb->dev = skb->dev; | ||
| 459 | send_skb->protocol = htons(ETH_P_ARP); | ||
| 460 | 468 | ||
| 461 | /* Fill the device header for the ARP frame */ | 469 | send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev), |
| 462 | if (dev_hard_header(send_skb, skb->dev, ptype, | 470 | LL_RESERVED_SPACE(np->dev)); |
| 463 | sha, np->dev->dev_addr, | 471 | if (!send_skb) |
| 464 | send_skb->len) < 0) { | 472 | continue; |
| 465 | kfree_skb(send_skb); | ||
| 466 | return; | ||
| 467 | } | ||
| 468 | 473 | ||
| 469 | /* | 474 | skb_reset_network_header(send_skb); |
| 470 | * Fill out the arp protocol part. | 475 | arp = (struct arphdr *) skb_put(send_skb, size); |
| 471 | * | 476 | send_skb->dev = skb->dev; |
| 472 | * we only support ethernet device type, | 477 | send_skb->protocol = htons(ETH_P_ARP); |
| 473 | * which (according to RFC 1390) should always equal 1 (Ethernet). | ||
| 474 | */ | ||
| 475 | 478 | ||
| 476 | arp->ar_hrd = htons(np->dev->type); | 479 | /* Fill the device header for the ARP frame */ |
| 477 | arp->ar_pro = htons(ETH_P_IP); | 480 | if (dev_hard_header(send_skb, skb->dev, ptype, |
| 478 | arp->ar_hln = np->dev->addr_len; | 481 | sha, np->dev->dev_addr, |
| 479 | arp->ar_pln = 4; | 482 | send_skb->len) < 0) { |
| 480 | arp->ar_op = htons(type); | 483 | kfree_skb(send_skb); |
| 484 | continue; | ||
| 485 | } | ||
| 481 | 486 | ||
| 482 | arp_ptr=(unsigned char *)(arp + 1); | 487 | /* |
| 483 | memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len); | 488 | * Fill out the arp protocol part. |
| 484 | arp_ptr += np->dev->addr_len; | 489 | * |
| 485 | memcpy(arp_ptr, &tip, 4); | 490 | * we only support ethernet device type, |
| 486 | arp_ptr += 4; | 491 | * which (according to RFC 1390) should |
| 487 | memcpy(arp_ptr, sha, np->dev->addr_len); | 492 | * always equal 1 (Ethernet). |
| 488 | arp_ptr += np->dev->addr_len; | 493 | */ |
| 489 | memcpy(arp_ptr, &sip, 4); | ||
| 490 | 494 | ||
| 491 | netpoll_send_skb(np, send_skb); | 495 | arp->ar_hrd = htons(np->dev->type); |
| 496 | arp->ar_pro = htons(ETH_P_IP); | ||
| 497 | arp->ar_hln = np->dev->addr_len; | ||
| 498 | arp->ar_pln = 4; | ||
| 499 | arp->ar_op = htons(type); | ||
| 500 | |||
| 501 | arp_ptr = (unsigned char *)(arp + 1); | ||
| 502 | memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len); | ||
| 503 | arp_ptr += np->dev->addr_len; | ||
| 504 | memcpy(arp_ptr, &tip, 4); | ||
| 505 | arp_ptr += 4; | ||
| 506 | memcpy(arp_ptr, sha, np->dev->addr_len); | ||
| 507 | arp_ptr += np->dev->addr_len; | ||
| 508 | memcpy(arp_ptr, &sip, 4); | ||
| 509 | |||
| 510 | netpoll_send_skb(np, send_skb); | ||
| 511 | |||
| 512 | /* If there are several rx_hooks for the same address, | ||
| 513 | we're fine by sending a single reply */ | ||
| 514 | break; | ||
| 515 | } | ||
| 516 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | ||
| 492 | } | 517 | } |
| 493 | 518 | ||
| 494 | int __netpoll_rx(struct sk_buff *skb) | 519 | int __netpoll_rx(struct sk_buff *skb) |
| 495 | { | 520 | { |
| 496 | int proto, len, ulen; | 521 | int proto, len, ulen; |
| 522 | int hits = 0; | ||
| 497 | struct iphdr *iph; | 523 | struct iphdr *iph; |
| 498 | struct udphdr *uh; | 524 | struct udphdr *uh; |
| 499 | struct netpoll_info *npi = skb->dev->npinfo; | 525 | struct netpoll_info *npinfo = skb->dev->npinfo; |
| 500 | struct netpoll *np = npi->rx_np; | 526 | struct netpoll *np, *tmp; |
| 501 | 527 | ||
| 502 | if (!np) | 528 | if (list_empty(&npinfo->rx_np)) |
| 503 | goto out; | 529 | goto out; |
| 530 | |||
| 504 | if (skb->dev->type != ARPHRD_ETHER) | 531 | if (skb->dev->type != ARPHRD_ETHER) |
| 505 | goto out; | 532 | goto out; |
| 506 | 533 | ||
| 507 | /* check if netpoll clients need ARP */ | 534 | /* check if netpoll clients need ARP */ |
| 508 | if (skb->protocol == htons(ETH_P_ARP) && | 535 | if (skb->protocol == htons(ETH_P_ARP) && |
| 509 | atomic_read(&trapped)) { | 536 | atomic_read(&trapped)) { |
| 510 | skb_queue_tail(&npi->arp_tx, skb); | 537 | skb_queue_tail(&npinfo->arp_tx, skb); |
| 511 | return 1; | 538 | return 1; |
| 512 | } | 539 | } |
| 513 | 540 | ||
| @@ -551,16 +578,23 @@ int __netpoll_rx(struct sk_buff *skb) | |||
| 551 | goto out; | 578 | goto out; |
| 552 | if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr)) | 579 | if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr)) |
| 553 | goto out; | 580 | goto out; |
| 554 | if (np->local_ip && np->local_ip != iph->daddr) | ||
| 555 | goto out; | ||
| 556 | if (np->remote_ip && np->remote_ip != iph->saddr) | ||
| 557 | goto out; | ||
| 558 | if (np->local_port && np->local_port != ntohs(uh->dest)) | ||
| 559 | goto out; | ||
| 560 | 581 | ||
| 561 | np->rx_hook(np, ntohs(uh->source), | 582 | list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { |
| 562 | (char *)(uh+1), | 583 | if (np->local_ip && np->local_ip != iph->daddr) |
| 563 | ulen - sizeof(struct udphdr)); | 584 | continue; |
| 585 | if (np->remote_ip && np->remote_ip != iph->saddr) | ||
| 586 | continue; | ||
| 587 | if (np->local_port && np->local_port != ntohs(uh->dest)) | ||
| 588 | continue; | ||
| 589 | |||
| 590 | np->rx_hook(np, ntohs(uh->source), | ||
| 591 | (char *)(uh+1), | ||
| 592 | ulen - sizeof(struct udphdr)); | ||
| 593 | hits++; | ||
| 594 | } | ||
| 595 | |||
| 596 | if (!hits) | ||
| 597 | goto out; | ||
| 564 | 598 | ||
| 565 | kfree_skb(skb); | 599 | kfree_skb(skb); |
| 566 | return 1; | 600 | return 1; |
| @@ -684,6 +718,7 @@ int netpoll_setup(struct netpoll *np) | |||
| 684 | struct net_device *ndev = NULL; | 718 | struct net_device *ndev = NULL; |
| 685 | struct in_device *in_dev; | 719 | struct in_device *in_dev; |
| 686 | struct netpoll_info *npinfo; | 720 | struct netpoll_info *npinfo; |
| 721 | struct netpoll *npe, *tmp; | ||
| 687 | unsigned long flags; | 722 | unsigned long flags; |
| 688 | int err; | 723 | int err; |
| 689 | 724 | ||
| @@ -704,7 +739,7 @@ int netpoll_setup(struct netpoll *np) | |||
| 704 | } | 739 | } |
| 705 | 740 | ||
| 706 | npinfo->rx_flags = 0; | 741 | npinfo->rx_flags = 0; |
| 707 | npinfo->rx_np = NULL; | 742 | INIT_LIST_HEAD(&npinfo->rx_np); |
| 708 | 743 | ||
| 709 | spin_lock_init(&npinfo->rx_lock); | 744 | spin_lock_init(&npinfo->rx_lock); |
| 710 | skb_queue_head_init(&npinfo->arp_tx); | 745 | skb_queue_head_init(&npinfo->arp_tx); |
| @@ -785,7 +820,7 @@ int netpoll_setup(struct netpoll *np) | |||
| 785 | if (np->rx_hook) { | 820 | if (np->rx_hook) { |
| 786 | spin_lock_irqsave(&npinfo->rx_lock, flags); | 821 | spin_lock_irqsave(&npinfo->rx_lock, flags); |
| 787 | npinfo->rx_flags |= NETPOLL_RX_ENABLED; | 822 | npinfo->rx_flags |= NETPOLL_RX_ENABLED; |
| 788 | npinfo->rx_np = np; | 823 | list_add_tail(&np->rx, &npinfo->rx_np); |
| 789 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | 824 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); |
| 790 | } | 825 | } |
| 791 | 826 | ||
| @@ -801,9 +836,16 @@ int netpoll_setup(struct netpoll *np) | |||
| 801 | return 0; | 836 | return 0; |
| 802 | 837 | ||
| 803 | release: | 838 | release: |
| 804 | if (!ndev->npinfo) | 839 | if (!ndev->npinfo) { |
| 840 | spin_lock_irqsave(&npinfo->rx_lock, flags); | ||
| 841 | list_for_each_entry_safe(npe, tmp, &npinfo->rx_np, rx) { | ||
| 842 | npe->dev = NULL; | ||
| 843 | } | ||
| 844 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | ||
| 845 | |||
| 805 | kfree(npinfo); | 846 | kfree(npinfo); |
| 806 | np->dev = NULL; | 847 | } |
| 848 | |||
| 807 | dev_put(ndev); | 849 | dev_put(ndev); |
| 808 | return err; | 850 | return err; |
| 809 | } | 851 | } |
| @@ -823,10 +865,11 @@ void netpoll_cleanup(struct netpoll *np) | |||
| 823 | if (np->dev) { | 865 | if (np->dev) { |
| 824 | npinfo = np->dev->npinfo; | 866 | npinfo = np->dev->npinfo; |
| 825 | if (npinfo) { | 867 | if (npinfo) { |
| 826 | if (npinfo->rx_np == np) { | 868 | if (!list_empty(&npinfo->rx_np)) { |
| 827 | spin_lock_irqsave(&npinfo->rx_lock, flags); | 869 | spin_lock_irqsave(&npinfo->rx_lock, flags); |
| 828 | npinfo->rx_np = NULL; | 870 | list_del(&np->rx); |
| 829 | npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; | 871 | if (list_empty(&npinfo->rx_np)) |
| 872 | npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; | ||
| 830 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | 873 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); |
| 831 | } | 874 | } |
| 832 | 875 | ||
