diff options
| -rw-r--r-- | net/packet/af_packet.c | 71 |
1 files changed, 31 insertions, 40 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 020562164b56..e0516a22be2e 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
| @@ -415,7 +415,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, | |||
| 415 | { | 415 | { |
| 416 | struct sock *sk = sock->sk; | 416 | struct sock *sk = sock->sk; |
| 417 | struct sockaddr_pkt *saddr = (struct sockaddr_pkt *)msg->msg_name; | 417 | struct sockaddr_pkt *saddr = (struct sockaddr_pkt *)msg->msg_name; |
| 418 | struct sk_buff *skb; | 418 | struct sk_buff *skb = NULL; |
| 419 | struct net_device *dev; | 419 | struct net_device *dev; |
| 420 | __be16 proto = 0; | 420 | __be16 proto = 0; |
| 421 | int err; | 421 | int err; |
| @@ -437,6 +437,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, | |||
| 437 | */ | 437 | */ |
| 438 | 438 | ||
| 439 | saddr->spkt_device[13] = 0; | 439 | saddr->spkt_device[13] = 0; |
| 440 | retry: | ||
| 440 | rcu_read_lock(); | 441 | rcu_read_lock(); |
| 441 | dev = dev_get_by_name_rcu(sock_net(sk), saddr->spkt_device); | 442 | dev = dev_get_by_name_rcu(sock_net(sk), saddr->spkt_device); |
| 442 | err = -ENODEV; | 443 | err = -ENODEV; |
| @@ -456,58 +457,48 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, | |||
| 456 | if (len > dev->mtu + dev->hard_header_len) | 457 | if (len > dev->mtu + dev->hard_header_len) |
| 457 | goto out_unlock; | 458 | goto out_unlock; |
| 458 | 459 | ||
| 459 | err = -ENOBUFS; | 460 | if (!skb) { |
| 460 | skb = sock_wmalloc(sk, len + LL_RESERVED_SPACE(dev), 0, GFP_KERNEL); | 461 | size_t reserved = LL_RESERVED_SPACE(dev); |
| 461 | 462 | unsigned int hhlen = dev->header_ops ? dev->hard_header_len : 0; | |
| 462 | /* | 463 | |
| 463 | * If the write buffer is full, then tough. At this level the user | 464 | rcu_read_unlock(); |
| 464 | * gets to deal with the problem - do your own algorithmic backoffs. | 465 | skb = sock_wmalloc(sk, len + reserved, 0, GFP_KERNEL); |
| 465 | * That's far more flexible. | 466 | if (skb == NULL) |
| 466 | */ | 467 | return -ENOBUFS; |
| 467 | 468 | /* FIXME: Save some space for broken drivers that write a hard | |
| 468 | if (skb == NULL) | 469 | * header at transmission time by themselves. PPP is the notable |
| 469 | goto out_unlock; | 470 | * one here. This should really be fixed at the driver level. |
| 470 | 471 | */ | |
| 471 | /* | 472 | skb_reserve(skb, reserved); |
| 472 | * Fill it in | 473 | skb_reset_network_header(skb); |
| 473 | */ | 474 | |
| 474 | 475 | /* Try to align data part correctly */ | |
| 475 | /* FIXME: Save some space for broken drivers that write a | 476 | if (hhlen) { |
| 476 | * hard header at transmission time by themselves. PPP is the | 477 | skb->data -= hhlen; |
| 477 | * notable one here. This should really be fixed at the driver level. | 478 | skb->tail -= hhlen; |
| 478 | */ | 479 | if (len < hhlen) |
| 479 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); | 480 | skb_reset_network_header(skb); |
| 480 | skb_reset_network_header(skb); | 481 | } |
| 481 | 482 | err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); | |
| 482 | /* Try to align data part correctly */ | 483 | if (err) |
| 483 | if (dev->header_ops) { | 484 | goto out_free; |
| 484 | skb->data -= dev->hard_header_len; | 485 | goto retry; |
| 485 | skb->tail -= dev->hard_header_len; | ||
| 486 | if (len < dev->hard_header_len) | ||
| 487 | skb_reset_network_header(skb); | ||
| 488 | } | 486 | } |
| 489 | 487 | ||
| 490 | /* Returns -EFAULT on error */ | 488 | |
| 491 | err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); | ||
| 492 | skb->protocol = proto; | 489 | skb->protocol = proto; |
| 493 | skb->dev = dev; | 490 | skb->dev = dev; |
| 494 | skb->priority = sk->sk_priority; | 491 | skb->priority = sk->sk_priority; |
| 495 | skb->mark = sk->sk_mark; | 492 | skb->mark = sk->sk_mark; |
| 496 | if (err) | ||
| 497 | goto out_free; | ||
| 498 | |||
| 499 | /* | ||
| 500 | * Now send it | ||
| 501 | */ | ||
| 502 | 493 | ||
| 503 | dev_queue_xmit(skb); | 494 | dev_queue_xmit(skb); |
| 504 | rcu_read_unlock(); | 495 | rcu_read_unlock(); |
| 505 | return len; | 496 | return len; |
| 506 | 497 | ||
| 507 | out_free: | ||
| 508 | kfree_skb(skb); | ||
| 509 | out_unlock: | 498 | out_unlock: |
| 510 | rcu_read_unlock(); | 499 | rcu_read_unlock(); |
| 500 | out_free: | ||
| 501 | kfree_skb(skb); | ||
| 511 | return err; | 502 | return err; |
| 512 | } | 503 | } |
| 513 | 504 | ||
