diff options
-rw-r--r-- | drivers/net/netconsole.c | 12 | ||||
-rw-r--r-- | include/linux/netpoll.h | 13 | ||||
-rw-r--r-- | net/core/netpoll.c | 402 |
3 files changed, 243 insertions, 184 deletions
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 6989ebe2bc79..998fa0257a92 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c | |||
@@ -269,12 +269,14 @@ static ssize_t show_remote_port(struct netconsole_target *nt, char *buf) | |||
269 | 269 | ||
270 | static ssize_t show_local_ip(struct netconsole_target *nt, char *buf) | 270 | static ssize_t show_local_ip(struct netconsole_target *nt, char *buf) |
271 | { | 271 | { |
272 | return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip); | 272 | if (!nt->np.ipv6) |
273 | return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip); | ||
273 | } | 274 | } |
274 | 275 | ||
275 | static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf) | 276 | static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf) |
276 | { | 277 | { |
277 | return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip); | 278 | if (!nt->np.ipv6) |
279 | return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip); | ||
278 | } | 280 | } |
279 | 281 | ||
280 | static ssize_t show_local_mac(struct netconsole_target *nt, char *buf) | 282 | static ssize_t show_local_mac(struct netconsole_target *nt, char *buf) |
@@ -410,7 +412,8 @@ static ssize_t store_local_ip(struct netconsole_target *nt, | |||
410 | return -EINVAL; | 412 | return -EINVAL; |
411 | } | 413 | } |
412 | 414 | ||
413 | nt->np.local_ip = in_aton(buf); | 415 | if (!strnchr(buf, count, ':')) |
416 | nt->np.local_ip.ip = in_aton(buf); | ||
414 | 417 | ||
415 | return strnlen(buf, count); | 418 | return strnlen(buf, count); |
416 | } | 419 | } |
@@ -426,7 +429,8 @@ static ssize_t store_remote_ip(struct netconsole_target *nt, | |||
426 | return -EINVAL; | 429 | return -EINVAL; |
427 | } | 430 | } |
428 | 431 | ||
429 | nt->np.remote_ip = in_aton(buf); | 432 | if (!strnchr(buf, count, ':')) |
433 | nt->np.remote_ip.ip = in_aton(buf); | ||
430 | 434 | ||
431 | return strnlen(buf, count); | 435 | return strnlen(buf, count); |
432 | } | 436 | } |
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 66d5379c305e..f54c3bb6a22b 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h | |||
@@ -12,13 +12,22 @@ | |||
12 | #include <linux/rcupdate.h> | 12 | #include <linux/rcupdate.h> |
13 | #include <linux/list.h> | 13 | #include <linux/list.h> |
14 | 14 | ||
15 | union inet_addr { | ||
16 | __u32 all[4]; | ||
17 | __be32 ip; | ||
18 | __be32 ip6[4]; | ||
19 | struct in_addr in; | ||
20 | struct in6_addr in6; | ||
21 | }; | ||
22 | |||
15 | struct netpoll { | 23 | struct netpoll { |
16 | struct net_device *dev; | 24 | struct net_device *dev; |
17 | char dev_name[IFNAMSIZ]; | 25 | char dev_name[IFNAMSIZ]; |
18 | const char *name; | 26 | const char *name; |
19 | void (*rx_hook)(struct netpoll *, int, char *, int); | 27 | void (*rx_hook)(struct netpoll *, int, char *, int); |
20 | 28 | ||
21 | __be32 local_ip, remote_ip; | 29 | union inet_addr local_ip, remote_ip; |
30 | bool ipv6; | ||
22 | u16 local_port, remote_port; | 31 | u16 local_port, remote_port; |
23 | u8 remote_mac[ETH_ALEN]; | 32 | u8 remote_mac[ETH_ALEN]; |
24 | 33 | ||
@@ -33,7 +42,7 @@ struct netpoll_info { | |||
33 | spinlock_t rx_lock; | 42 | spinlock_t rx_lock; |
34 | struct list_head rx_np; /* netpolls that registered an rx_hook */ | 43 | struct list_head rx_np; /* netpolls that registered an rx_hook */ |
35 | 44 | ||
36 | struct sk_buff_head arp_tx; /* list of arp requests to reply to */ | 45 | struct sk_buff_head neigh_tx; /* list of neigh requests to reply to */ |
37 | struct sk_buff_head txq; | 46 | struct sk_buff_head txq; |
38 | 47 | ||
39 | struct delayed_work tx_work; | 48 | struct delayed_work tx_work; |
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index d2bda8eb08ec..6bd073688f68 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
@@ -55,7 +55,7 @@ static atomic_t trapped; | |||
55 | MAX_UDP_CHUNK) | 55 | MAX_UDP_CHUNK) |
56 | 56 | ||
57 | static void zap_completion_queue(void); | 57 | static void zap_completion_queue(void); |
58 | static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo); | 58 | static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo); |
59 | 59 | ||
60 | static unsigned int carrier_timeout = 4; | 60 | static unsigned int carrier_timeout = 4; |
61 | module_param(carrier_timeout, uint, 0644); | 61 | module_param(carrier_timeout, uint, 0644); |
@@ -181,13 +181,13 @@ static void poll_napi(struct net_device *dev) | |||
181 | } | 181 | } |
182 | } | 182 | } |
183 | 183 | ||
184 | static void service_arp_queue(struct netpoll_info *npi) | 184 | static void service_neigh_queue(struct netpoll_info *npi) |
185 | { | 185 | { |
186 | if (npi) { | 186 | if (npi) { |
187 | struct sk_buff *skb; | 187 | struct sk_buff *skb; |
188 | 188 | ||
189 | while ((skb = skb_dequeue(&npi->arp_tx))) | 189 | while ((skb = skb_dequeue(&npi->neigh_tx))) |
190 | netpoll_arp_reply(skb, npi); | 190 | netpoll_neigh_reply(skb, npi); |
191 | } | 191 | } |
192 | } | 192 | } |
193 | 193 | ||
@@ -216,14 +216,14 @@ static void netpoll_poll_dev(struct net_device *dev) | |||
216 | 216 | ||
217 | bond_dev = netdev_master_upper_dev_get_rcu(dev); | 217 | bond_dev = netdev_master_upper_dev_get_rcu(dev); |
218 | bond_ni = rcu_dereference_bh(bond_dev->npinfo); | 218 | bond_ni = rcu_dereference_bh(bond_dev->npinfo); |
219 | while ((skb = skb_dequeue(&ni->arp_tx))) { | 219 | while ((skb = skb_dequeue(&ni->neigh_tx))) { |
220 | skb->dev = bond_dev; | 220 | skb->dev = bond_dev; |
221 | skb_queue_tail(&bond_ni->arp_tx, skb); | 221 | skb_queue_tail(&bond_ni->neigh_tx, skb); |
222 | } | 222 | } |
223 | } | 223 | } |
224 | } | 224 | } |
225 | 225 | ||
226 | service_arp_queue(ni); | 226 | service_neigh_queue(ni); |
227 | 227 | ||
228 | zap_completion_queue(); | 228 | zap_completion_queue(); |
229 | } | 229 | } |
@@ -386,7 +386,9 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len) | |||
386 | static atomic_t ip_ident; | 386 | static atomic_t ip_ident; |
387 | 387 | ||
388 | udp_len = len + sizeof(*udph); | 388 | udp_len = len + sizeof(*udph); |
389 | ip_len = udp_len + sizeof(*iph); | 389 | if (!np->ipv6) |
390 | ip_len = udp_len + sizeof(*iph); | ||
391 | |||
390 | total_len = ip_len + LL_RESERVED_SPACE(np->dev); | 392 | total_len = ip_len + LL_RESERVED_SPACE(np->dev); |
391 | 393 | ||
392 | skb = find_skb(np, total_len + np->dev->needed_tailroom, | 394 | skb = find_skb(np, total_len + np->dev->needed_tailroom, |
@@ -403,34 +405,38 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len) | |||
403 | udph->source = htons(np->local_port); | 405 | udph->source = htons(np->local_port); |
404 | udph->dest = htons(np->remote_port); | 406 | udph->dest = htons(np->remote_port); |
405 | udph->len = htons(udp_len); | 407 | udph->len = htons(udp_len); |
406 | udph->check = 0; | 408 | |
407 | udph->check = csum_tcpudp_magic(np->local_ip, | 409 | if (!np->ipv6) { |
408 | np->remote_ip, | 410 | udph->check = 0; |
409 | udp_len, IPPROTO_UDP, | 411 | udph->check = csum_tcpudp_magic(np->local_ip.ip, |
410 | csum_partial(udph, udp_len, 0)); | 412 | np->remote_ip.ip, |
411 | if (udph->check == 0) | 413 | udp_len, IPPROTO_UDP, |
412 | udph->check = CSUM_MANGLED_0; | 414 | csum_partial(udph, udp_len, 0)); |
413 | 415 | if (udph->check == 0) | |
414 | skb_push(skb, sizeof(*iph)); | 416 | udph->check = CSUM_MANGLED_0; |
415 | skb_reset_network_header(skb); | 417 | |
416 | iph = ip_hdr(skb); | 418 | skb_push(skb, sizeof(*iph)); |
417 | 419 | skb_reset_network_header(skb); | |
418 | /* iph->version = 4; iph->ihl = 5; */ | 420 | iph = ip_hdr(skb); |
419 | put_unaligned(0x45, (unsigned char *)iph); | 421 | |
420 | iph->tos = 0; | 422 | /* iph->version = 4; iph->ihl = 5; */ |
421 | put_unaligned(htons(ip_len), &(iph->tot_len)); | 423 | put_unaligned(0x45, (unsigned char *)iph); |
422 | iph->id = htons(atomic_inc_return(&ip_ident)); | 424 | iph->tos = 0; |
423 | iph->frag_off = 0; | 425 | put_unaligned(htons(ip_len), &(iph->tot_len)); |
424 | iph->ttl = 64; | 426 | iph->id = htons(atomic_inc_return(&ip_ident)); |
425 | iph->protocol = IPPROTO_UDP; | 427 | iph->frag_off = 0; |
426 | iph->check = 0; | 428 | iph->ttl = 64; |
427 | put_unaligned(np->local_ip, &(iph->saddr)); | 429 | iph->protocol = IPPROTO_UDP; |
428 | put_unaligned(np->remote_ip, &(iph->daddr)); | 430 | iph->check = 0; |
429 | iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); | 431 | put_unaligned(np->local_ip.ip, &(iph->saddr)); |
430 | 432 | put_unaligned(np->remote_ip.ip, &(iph->daddr)); | |
431 | eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); | 433 | iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); |
432 | skb_reset_mac_header(skb); | 434 | |
433 | skb->protocol = eth->h_proto = htons(ETH_P_IP); | 435 | eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); |
436 | skb_reset_mac_header(skb); | ||
437 | skb->protocol = eth->h_proto = htons(ETH_P_IP); | ||
438 | } | ||
439 | |||
434 | memcpy(eth->h_source, np->dev->dev_addr, ETH_ALEN); | 440 | memcpy(eth->h_source, np->dev->dev_addr, ETH_ALEN); |
435 | memcpy(eth->h_dest, np->remote_mac, ETH_ALEN); | 441 | memcpy(eth->h_dest, np->remote_mac, ETH_ALEN); |
436 | 442 | ||
@@ -440,7 +446,7 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len) | |||
440 | } | 446 | } |
441 | EXPORT_SYMBOL(netpoll_send_udp); | 447 | EXPORT_SYMBOL(netpoll_send_udp); |
442 | 448 | ||
443 | static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo) | 449 | static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo) |
444 | { | 450 | { |
445 | struct arphdr *arp; | 451 | struct arphdr *arp; |
446 | unsigned char *arp_ptr; | 452 | unsigned char *arp_ptr; |
@@ -451,7 +457,7 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo) | |||
451 | struct netpoll *np, *tmp; | 457 | struct netpoll *np, *tmp; |
452 | unsigned long flags; | 458 | unsigned long flags; |
453 | int hlen, tlen; | 459 | int hlen, tlen; |
454 | int hits = 0; | 460 | int hits = 0, proto; |
455 | 461 | ||
456 | if (list_empty(&npinfo->rx_np)) | 462 | if (list_empty(&npinfo->rx_np)) |
457 | return; | 463 | return; |
@@ -469,94 +475,97 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo) | |||
469 | if (!hits) | 475 | if (!hits) |
470 | return; | 476 | return; |
471 | 477 | ||
472 | /* No arp on this interface */ | 478 | proto = ntohs(eth_hdr(skb)->h_proto); |
473 | if (skb->dev->flags & IFF_NOARP) | 479 | if (proto == ETH_P_IP) { |
474 | return; | 480 | /* No arp on this interface */ |
475 | 481 | if (skb->dev->flags & IFF_NOARP) | |
476 | if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) | 482 | return; |
477 | return; | ||
478 | 483 | ||
479 | skb_reset_network_header(skb); | 484 | if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) |
480 | skb_reset_transport_header(skb); | 485 | return; |
481 | arp = arp_hdr(skb); | ||
482 | 486 | ||
483 | if ((arp->ar_hrd != htons(ARPHRD_ETHER) && | 487 | skb_reset_network_header(skb); |
484 | arp->ar_hrd != htons(ARPHRD_IEEE802)) || | 488 | skb_reset_transport_header(skb); |
485 | arp->ar_pro != htons(ETH_P_IP) || | 489 | arp = arp_hdr(skb); |
486 | arp->ar_op != htons(ARPOP_REQUEST)) | ||
487 | return; | ||
488 | 490 | ||
489 | arp_ptr = (unsigned char *)(arp+1); | 491 | if ((arp->ar_hrd != htons(ARPHRD_ETHER) && |
490 | /* save the location of the src hw addr */ | 492 | arp->ar_hrd != htons(ARPHRD_IEEE802)) || |
491 | sha = arp_ptr; | 493 | arp->ar_pro != htons(ETH_P_IP) || |
492 | arp_ptr += skb->dev->addr_len; | 494 | arp->ar_op != htons(ARPOP_REQUEST)) |
493 | memcpy(&sip, arp_ptr, 4); | 495 | return; |
494 | arp_ptr += 4; | ||
495 | /* If we actually cared about dst hw addr, | ||
496 | it would get copied here */ | ||
497 | arp_ptr += skb->dev->addr_len; | ||
498 | memcpy(&tip, arp_ptr, 4); | ||
499 | |||
500 | /* Should we ignore arp? */ | ||
501 | if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) | ||
502 | return; | ||
503 | 496 | ||
504 | size = arp_hdr_len(skb->dev); | 497 | arp_ptr = (unsigned char *)(arp+1); |
498 | /* save the location of the src hw addr */ | ||
499 | sha = arp_ptr; | ||
500 | arp_ptr += skb->dev->addr_len; | ||
501 | memcpy(&sip, arp_ptr, 4); | ||
502 | arp_ptr += 4; | ||
503 | /* If we actually cared about dst hw addr, | ||
504 | it would get copied here */ | ||
505 | arp_ptr += skb->dev->addr_len; | ||
506 | memcpy(&tip, arp_ptr, 4); | ||
505 | 507 | ||
506 | spin_lock_irqsave(&npinfo->rx_lock, flags); | 508 | /* Should we ignore arp? */ |
507 | list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { | 509 | if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) |
508 | if (tip != np->local_ip) | 510 | return; |
509 | continue; | ||
510 | 511 | ||
511 | hlen = LL_RESERVED_SPACE(np->dev); | 512 | size = arp_hdr_len(skb->dev); |
512 | tlen = np->dev->needed_tailroom; | ||
513 | send_skb = find_skb(np, size + hlen + tlen, hlen); | ||
514 | if (!send_skb) | ||
515 | continue; | ||
516 | 513 | ||
517 | skb_reset_network_header(send_skb); | 514 | spin_lock_irqsave(&npinfo->rx_lock, flags); |
518 | arp = (struct arphdr *) skb_put(send_skb, size); | 515 | list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { |
519 | send_skb->dev = skb->dev; | 516 | if (tip != np->local_ip.ip) |
520 | send_skb->protocol = htons(ETH_P_ARP); | 517 | continue; |
518 | |||
519 | hlen = LL_RESERVED_SPACE(np->dev); | ||
520 | tlen = np->dev->needed_tailroom; | ||
521 | send_skb = find_skb(np, size + hlen + tlen, hlen); | ||
522 | if (!send_skb) | ||
523 | continue; | ||
524 | |||
525 | skb_reset_network_header(send_skb); | ||
526 | arp = (struct arphdr *) skb_put(send_skb, size); | ||
527 | send_skb->dev = skb->dev; | ||
528 | send_skb->protocol = htons(ETH_P_ARP); | ||
529 | |||
530 | /* Fill the device header for the ARP frame */ | ||
531 | if (dev_hard_header(send_skb, skb->dev, ptype, | ||
532 | sha, np->dev->dev_addr, | ||
533 | send_skb->len) < 0) { | ||
534 | kfree_skb(send_skb); | ||
535 | continue; | ||
536 | } | ||
521 | 537 | ||
522 | /* Fill the device header for the ARP frame */ | 538 | /* |
523 | if (dev_hard_header(send_skb, skb->dev, ptype, | 539 | * Fill out the arp protocol part. |
524 | sha, np->dev->dev_addr, | 540 | * |
525 | send_skb->len) < 0) { | 541 | * we only support ethernet device type, |
526 | kfree_skb(send_skb); | 542 | * which (according to RFC 1390) should |
527 | continue; | 543 | * always equal 1 (Ethernet). |
544 | */ | ||
545 | |||
546 | arp->ar_hrd = htons(np->dev->type); | ||
547 | arp->ar_pro = htons(ETH_P_IP); | ||
548 | arp->ar_hln = np->dev->addr_len; | ||
549 | arp->ar_pln = 4; | ||
550 | arp->ar_op = htons(type); | ||
551 | |||
552 | arp_ptr = (unsigned char *)(arp + 1); | ||
553 | memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len); | ||
554 | arp_ptr += np->dev->addr_len; | ||
555 | memcpy(arp_ptr, &tip, 4); | ||
556 | arp_ptr += 4; | ||
557 | memcpy(arp_ptr, sha, np->dev->addr_len); | ||
558 | arp_ptr += np->dev->addr_len; | ||
559 | memcpy(arp_ptr, &sip, 4); | ||
560 | |||
561 | netpoll_send_skb(np, send_skb); | ||
562 | |||
563 | /* If there are several rx_hooks for the same address, | ||
564 | we're fine by sending a single reply */ | ||
565 | break; | ||
528 | } | 566 | } |
529 | 567 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | |
530 | /* | ||
531 | * Fill out the arp protocol part. | ||
532 | * | ||
533 | * we only support ethernet device type, | ||
534 | * which (according to RFC 1390) should | ||
535 | * always equal 1 (Ethernet). | ||
536 | */ | ||
537 | |||
538 | arp->ar_hrd = htons(np->dev->type); | ||
539 | arp->ar_pro = htons(ETH_P_IP); | ||
540 | arp->ar_hln = np->dev->addr_len; | ||
541 | arp->ar_pln = 4; | ||
542 | arp->ar_op = htons(type); | ||
543 | |||
544 | arp_ptr = (unsigned char *)(arp + 1); | ||
545 | memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len); | ||
546 | arp_ptr += np->dev->addr_len; | ||
547 | memcpy(arp_ptr, &tip, 4); | ||
548 | arp_ptr += 4; | ||
549 | memcpy(arp_ptr, sha, np->dev->addr_len); | ||
550 | arp_ptr += np->dev->addr_len; | ||
551 | memcpy(arp_ptr, &sip, 4); | ||
552 | |||
553 | netpoll_send_skb(np, send_skb); | ||
554 | |||
555 | /* If there are several rx_hooks for the same address, | ||
556 | we're fine by sending a single reply */ | ||
557 | break; | ||
558 | } | 568 | } |
559 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | ||
560 | } | 569 | } |
561 | 570 | ||
562 | int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) | 571 | int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) |
@@ -576,7 +585,7 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) | |||
576 | /* check if netpoll clients need ARP */ | 585 | /* check if netpoll clients need ARP */ |
577 | if (skb->protocol == htons(ETH_P_ARP) && | 586 | if (skb->protocol == htons(ETH_P_ARP) && |
578 | atomic_read(&trapped)) { | 587 | atomic_read(&trapped)) { |
579 | skb_queue_tail(&npinfo->arp_tx, skb); | 588 | skb_queue_tail(&npinfo->neigh_tx, skb); |
580 | return 1; | 589 | return 1; |
581 | } | 590 | } |
582 | 591 | ||
@@ -587,60 +596,61 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo) | |||
587 | } | 596 | } |
588 | 597 | ||
589 | proto = ntohs(eth_hdr(skb)->h_proto); | 598 | proto = ntohs(eth_hdr(skb)->h_proto); |
590 | if (proto != ETH_P_IP) | 599 | if (proto != ETH_P_IP && proto != ETH_P_IPV6) |
591 | goto out; | 600 | goto out; |
592 | if (skb->pkt_type == PACKET_OTHERHOST) | 601 | if (skb->pkt_type == PACKET_OTHERHOST) |
593 | goto out; | 602 | goto out; |
594 | if (skb_shared(skb)) | 603 | if (skb_shared(skb)) |
595 | goto out; | 604 | goto out; |
596 | 605 | ||
597 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | 606 | if (proto == ETH_P_IP) { |
598 | goto out; | 607 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) |
599 | iph = (struct iphdr *)skb->data; | 608 | goto out; |
600 | if (iph->ihl < 5 || iph->version != 4) | 609 | iph = (struct iphdr *)skb->data; |
601 | goto out; | 610 | if (iph->ihl < 5 || iph->version != 4) |
602 | if (!pskb_may_pull(skb, iph->ihl*4)) | 611 | goto out; |
603 | goto out; | 612 | if (!pskb_may_pull(skb, iph->ihl*4)) |
604 | iph = (struct iphdr *)skb->data; | 613 | goto out; |
605 | if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) | 614 | iph = (struct iphdr *)skb->data; |
606 | goto out; | 615 | if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) |
607 | 616 | goto out; | |
608 | len = ntohs(iph->tot_len); | ||
609 | if (skb->len < len || len < iph->ihl*4) | ||
610 | goto out; | ||
611 | |||
612 | /* | ||
613 | * Our transport medium may have padded the buffer out. | ||
614 | * Now We trim to the true length of the frame. | ||
615 | */ | ||
616 | if (pskb_trim_rcsum(skb, len)) | ||
617 | goto out; | ||
618 | 617 | ||
619 | iph = (struct iphdr *)skb->data; | 618 | len = ntohs(iph->tot_len); |
620 | if (iph->protocol != IPPROTO_UDP) | 619 | if (skb->len < len || len < iph->ihl*4) |
621 | goto out; | 620 | goto out; |
622 | 621 | ||
623 | len -= iph->ihl*4; | 622 | /* |
624 | uh = (struct udphdr *)(((char *)iph) + iph->ihl*4); | 623 | * Our transport medium may have padded the buffer out. |
625 | ulen = ntohs(uh->len); | 624 | * Now We trim to the true length of the frame. |
625 | */ | ||
626 | if (pskb_trim_rcsum(skb, len)) | ||
627 | goto out; | ||
626 | 628 | ||
627 | if (ulen != len) | 629 | iph = (struct iphdr *)skb->data; |
628 | goto out; | 630 | if (iph->protocol != IPPROTO_UDP) |
629 | if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr)) | 631 | goto out; |
630 | goto out; | ||
631 | 632 | ||
632 | list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { | 633 | len -= iph->ihl*4; |
633 | if (np->local_ip && np->local_ip != iph->daddr) | 634 | uh = (struct udphdr *)(((char *)iph) + iph->ihl*4); |
634 | continue; | 635 | ulen = ntohs(uh->len); |
635 | if (np->remote_ip && np->remote_ip != iph->saddr) | ||
636 | continue; | ||
637 | if (np->local_port && np->local_port != ntohs(uh->dest)) | ||
638 | continue; | ||
639 | 636 | ||
640 | np->rx_hook(np, ntohs(uh->source), | 637 | if (ulen != len) |
641 | (char *)(uh+1), | 638 | goto out; |
642 | ulen - sizeof(struct udphdr)); | 639 | if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr)) |
643 | hits++; | 640 | goto out; |
641 | list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { | ||
642 | if (np->local_ip.ip && np->local_ip.ip != iph->daddr) | ||
643 | continue; | ||
644 | if (np->remote_ip.ip && np->remote_ip.ip != iph->saddr) | ||
645 | continue; | ||
646 | if (np->local_port && np->local_port != ntohs(uh->dest)) | ||
647 | continue; | ||
648 | |||
649 | np->rx_hook(np, ntohs(uh->source), | ||
650 | (char *)(uh+1), | ||
651 | ulen - sizeof(struct udphdr)); | ||
652 | hits++; | ||
653 | } | ||
644 | } | 654 | } |
645 | 655 | ||
646 | if (!hits) | 656 | if (!hits) |
@@ -661,17 +671,40 @@ out: | |||
661 | void netpoll_print_options(struct netpoll *np) | 671 | void netpoll_print_options(struct netpoll *np) |
662 | { | 672 | { |
663 | np_info(np, "local port %d\n", np->local_port); | 673 | np_info(np, "local port %d\n", np->local_port); |
664 | np_info(np, "local IP %pI4\n", &np->local_ip); | 674 | if (!np->ipv6) |
675 | np_info(np, "local IPv4 address %pI4\n", &np->local_ip.ip); | ||
665 | np_info(np, "interface '%s'\n", np->dev_name); | 676 | np_info(np, "interface '%s'\n", np->dev_name); |
666 | np_info(np, "remote port %d\n", np->remote_port); | 677 | np_info(np, "remote port %d\n", np->remote_port); |
667 | np_info(np, "remote IP %pI4\n", &np->remote_ip); | 678 | if (!np->ipv6) |
679 | np_info(np, "remote IPv4 address %pI4\n", &np->remote_ip.ip); | ||
668 | np_info(np, "remote ethernet address %pM\n", np->remote_mac); | 680 | np_info(np, "remote ethernet address %pM\n", np->remote_mac); |
669 | } | 681 | } |
670 | EXPORT_SYMBOL(netpoll_print_options); | 682 | EXPORT_SYMBOL(netpoll_print_options); |
671 | 683 | ||
684 | static int netpoll_parse_ip_addr(const char *str, union inet_addr *addr) | ||
685 | { | ||
686 | const char *end; | ||
687 | |||
688 | if (!strchr(str, ':') && | ||
689 | in4_pton(str, -1, (void *)addr, -1, &end) > 0) { | ||
690 | if (!*end) | ||
691 | return 0; | ||
692 | } | ||
693 | if (in6_pton(str, -1, addr->in6.s6_addr, -1, &end) > 0) { | ||
694 | #if IS_ENABLED(CONFIG_IPV6) | ||
695 | if (!*end) | ||
696 | return 1; | ||
697 | #else | ||
698 | return -1; | ||
699 | #endif | ||
700 | } | ||
701 | return -1; | ||
702 | } | ||
703 | |||
672 | int netpoll_parse_options(struct netpoll *np, char *opt) | 704 | int netpoll_parse_options(struct netpoll *np, char *opt) |
673 | { | 705 | { |
674 | char *cur=opt, *delim; | 706 | char *cur=opt, *delim; |
707 | int ipv6; | ||
675 | 708 | ||
676 | if (*cur != '@') { | 709 | if (*cur != '@') { |
677 | if ((delim = strchr(cur, '@')) == NULL) | 710 | if ((delim = strchr(cur, '@')) == NULL) |
@@ -687,7 +720,11 @@ int netpoll_parse_options(struct netpoll *np, char *opt) | |||
687 | if ((delim = strchr(cur, '/')) == NULL) | 720 | if ((delim = strchr(cur, '/')) == NULL) |
688 | goto parse_failed; | 721 | goto parse_failed; |
689 | *delim = 0; | 722 | *delim = 0; |
690 | np->local_ip = in_aton(cur); | 723 | ipv6 = netpoll_parse_ip_addr(cur, &np->local_ip); |
724 | if (ipv6 < 0) | ||
725 | goto parse_failed; | ||
726 | else | ||
727 | np->ipv6 = (bool)ipv6; | ||
691 | cur = delim; | 728 | cur = delim; |
692 | } | 729 | } |
693 | cur++; | 730 | cur++; |
@@ -719,7 +756,13 @@ int netpoll_parse_options(struct netpoll *np, char *opt) | |||
719 | if ((delim = strchr(cur, '/')) == NULL) | 756 | if ((delim = strchr(cur, '/')) == NULL) |
720 | goto parse_failed; | 757 | goto parse_failed; |
721 | *delim = 0; | 758 | *delim = 0; |
722 | np->remote_ip = in_aton(cur); | 759 | ipv6 = netpoll_parse_ip_addr(cur, &np->remote_ip); |
760 | if (ipv6 < 0) | ||
761 | goto parse_failed; | ||
762 | else if (np->ipv6 != (bool)ipv6) | ||
763 | goto parse_failed; | ||
764 | else | ||
765 | np->ipv6 = (bool)ipv6; | ||
723 | cur = delim + 1; | 766 | cur = delim + 1; |
724 | 767 | ||
725 | if (*cur != 0) { | 768 | if (*cur != 0) { |
@@ -767,7 +810,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp) | |||
767 | INIT_LIST_HEAD(&npinfo->rx_np); | 810 | INIT_LIST_HEAD(&npinfo->rx_np); |
768 | 811 | ||
769 | spin_lock_init(&npinfo->rx_lock); | 812 | spin_lock_init(&npinfo->rx_lock); |
770 | skb_queue_head_init(&npinfo->arp_tx); | 813 | skb_queue_head_init(&npinfo->neigh_tx); |
771 | skb_queue_head_init(&npinfo->txq); | 814 | skb_queue_head_init(&npinfo->txq); |
772 | INIT_DELAYED_WORK(&npinfo->tx_work, queue_process); | 815 | INIT_DELAYED_WORK(&npinfo->tx_work, queue_process); |
773 | 816 | ||
@@ -859,21 +902,24 @@ int netpoll_setup(struct netpoll *np) | |||
859 | } | 902 | } |
860 | } | 903 | } |
861 | 904 | ||
862 | if (!np->local_ip) { | 905 | if (!np->local_ip.ip) { |
863 | rcu_read_lock(); | 906 | if (!np->ipv6) { |
864 | in_dev = __in_dev_get_rcu(ndev); | 907 | rcu_read_lock(); |
908 | in_dev = __in_dev_get_rcu(ndev); | ||
865 | 909 | ||
866 | if (!in_dev || !in_dev->ifa_list) { | 910 | |
911 | if (!in_dev || !in_dev->ifa_list) { | ||
912 | rcu_read_unlock(); | ||
913 | np_err(np, "no IP address for %s, aborting\n", | ||
914 | np->dev_name); | ||
915 | err = -EDESTADDRREQ; | ||
916 | goto put; | ||
917 | } | ||
918 | |||
919 | np->local_ip.ip = in_dev->ifa_list->ifa_local; | ||
867 | rcu_read_unlock(); | 920 | rcu_read_unlock(); |
868 | np_err(np, "no IP address for %s, aborting\n", | 921 | np_info(np, "local IP %pI4\n", &np->local_ip.ip); |
869 | np->dev_name); | ||
870 | err = -EDESTADDRREQ; | ||
871 | goto put; | ||
872 | } | 922 | } |
873 | |||
874 | np->local_ip = in_dev->ifa_list->ifa_local; | ||
875 | rcu_read_unlock(); | ||
876 | np_info(np, "local IP %pI4\n", &np->local_ip); | ||
877 | } | 923 | } |
878 | 924 | ||
879 | /* fill up the skb queue */ | 925 | /* fill up the skb queue */ |
@@ -906,7 +952,7 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head) | |||
906 | struct netpoll_info *npinfo = | 952 | struct netpoll_info *npinfo = |
907 | container_of(rcu_head, struct netpoll_info, rcu); | 953 | container_of(rcu_head, struct netpoll_info, rcu); |
908 | 954 | ||
909 | skb_queue_purge(&npinfo->arp_tx); | 955 | skb_queue_purge(&npinfo->neigh_tx); |
910 | skb_queue_purge(&npinfo->txq); | 956 | skb_queue_purge(&npinfo->txq); |
911 | 957 | ||
912 | /* we can't call cancel_delayed_work_sync here, as we are in softirq */ | 958 | /* we can't call cancel_delayed_work_sync here, as we are in softirq */ |