aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-02-05 02:31:32 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2007-02-08 15:38:46 -0500
commit8dc4194474159660d7f37c495e3fc3f10d0db8cc (patch)
tree33df4345a29ce4d77ebb716796687753d8f89218 /net
parent8eb9086f21c73b38b5ca27558db4c91d62d0e70b (diff)
[PACKET]: Add optional checksum computation for recvmsg
This patch is needed to make ISC's DHCP server (and probably other DHCP servers/clients using AF_PACKET) to be able to serve another client on the same Xen host. The problem is that packets between different domains on the same Xen host only have partial checksums. Unfortunately this piece of information is not passed along in AF_PACKET unless you're using the mmap interface. Since dhcpd doesn't support packet-mmap, UDP packets from the same host come out with apparently bogus checksums. This patch adds a mechanism for AF_PACKET recvmsg(2) to return the status along with the packet. It does so by adding a new cmsg that contains this information along with some other relevant data such as the original packet length. I didn't include the time stamp information since there is already a cmsg for that. This patch also changes the mmap code to set the CSUMNOTREADY flag on all packets instead of just outoing packets on cooked sockets. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/packet/af_packet.c57
1 files changed, 48 insertions, 9 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 6dc01bdeb76b..8973ea78831e 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -200,7 +200,8 @@ struct packet_sock {
200#endif 200#endif
201 struct packet_type prot_hook; 201 struct packet_type prot_hook;
202 spinlock_t bind_lock; 202 spinlock_t bind_lock;
203 char running; /* prot_hook is attached*/ 203 unsigned int running:1, /* prot_hook is attached*/
204 auxdata:1;
204 int ifindex; /* bound device */ 205 int ifindex; /* bound device */
205 __be16 num; 206 __be16 num;
206#ifdef CONFIG_PACKET_MULTICAST 207#ifdef CONFIG_PACKET_MULTICAST
@@ -214,6 +215,8 @@ struct packet_sock {
214#endif 215#endif
215}; 216};
216 217
218#define PACKET_SKB_CB(__skb) ((struct tpacket_auxdata *)((__skb)->cb))
219
217#ifdef CONFIG_PACKET_MMAP 220#ifdef CONFIG_PACKET_MMAP
218 221
219static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position) 222static inline char *packet_lookup_frame(struct packet_sock *po, unsigned int position)
@@ -462,6 +465,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
462 u8 * skb_head = skb->data; 465 u8 * skb_head = skb->data;
463 int skb_len = skb->len; 466 int skb_len = skb->len;
464 unsigned int snaplen, res; 467 unsigned int snaplen, res;
468 struct tpacket_auxdata *aux;
465 469
466 if (skb->pkt_type == PACKET_LOOPBACK) 470 if (skb->pkt_type == PACKET_LOOPBACK)
467 goto drop; 471 goto drop;
@@ -523,6 +527,15 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
523 if (dev->hard_header_parse) 527 if (dev->hard_header_parse)
524 sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr); 528 sll->sll_halen = dev->hard_header_parse(skb, sll->sll_addr);
525 529
530 aux = PACKET_SKB_CB(skb);
531 aux->tp_status = TP_STATUS_USER;
532 if (skb->ip_summed == CHECKSUM_PARTIAL)
533 aux->tp_status |= TP_STATUS_CSUMNOTREADY;
534 aux->tp_len = skb->len;
535 aux->tp_snaplen = snaplen;
536 aux->tp_mac = 0;
537 aux->tp_net = skb->nh.raw - skb->data;
538
526 if (pskb_trim(skb, snaplen)) 539 if (pskb_trim(skb, snaplen))
527 goto drop_n_acct; 540 goto drop_n_acct;
528 541
@@ -582,11 +595,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
582 else if (skb->pkt_type == PACKET_OUTGOING) { 595 else if (skb->pkt_type == PACKET_OUTGOING) {
583 /* Special case: outgoing packets have ll header at head */ 596 /* Special case: outgoing packets have ll header at head */
584 skb_pull(skb, skb->nh.raw - skb->data); 597 skb_pull(skb, skb->nh.raw - skb->data);
585 if (skb->ip_summed == CHECKSUM_PARTIAL)
586 status |= TP_STATUS_CSUMNOTREADY;
587 } 598 }
588 } 599 }
589 600
601 if (skb->ip_summed == CHECKSUM_PARTIAL)
602 status |= TP_STATUS_CSUMNOTREADY;
603
590 snaplen = skb->len; 604 snaplen = skb->len;
591 605
592 res = run_filter(skb, sk, snaplen); 606 res = run_filter(skb, sk, snaplen);
@@ -1119,6 +1133,11 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
1119 if (msg->msg_name) 1133 if (msg->msg_name)
1120 memcpy(msg->msg_name, skb->cb, msg->msg_namelen); 1134 memcpy(msg->msg_name, skb->cb, msg->msg_namelen);
1121 1135
1136 if (pkt_sk(sk)->auxdata) {
1137 struct tpacket_auxdata *aux = PACKET_SKB_CB(skb);
1138 put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(*aux), aux);
1139 }
1140
1122 /* 1141 /*
1123 * Free or return the buffer as appropriate. Again this 1142 * Free or return the buffer as appropriate. Again this
1124 * hides all the races and re-entrancy issues from us. 1143 * hides all the races and re-entrancy issues from us.
@@ -1317,6 +1336,7 @@ static int
1317packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) 1336packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
1318{ 1337{
1319 struct sock *sk = sock->sk; 1338 struct sock *sk = sock->sk;
1339 struct packet_sock *po = pkt_sk(sk);
1320 int ret; 1340 int ret;
1321 1341
1322 if (level != SOL_PACKET) 1342 if (level != SOL_PACKET)
@@ -1369,6 +1389,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
1369 return 0; 1389 return 0;
1370 } 1390 }
1371#endif 1391#endif
1392 case PACKET_AUXDATA:
1393 {
1394 int val;
1395
1396 if (optlen < sizeof(val))
1397 return -EINVAL;
1398 if (copy_from_user(&val, optval, sizeof(val)))
1399 return -EFAULT;
1400
1401 po->auxdata = !!val;
1402 return 0;
1403 }
1372 default: 1404 default:
1373 return -ENOPROTOOPT; 1405 return -ENOPROTOOPT;
1374 } 1406 }
@@ -1378,8 +1410,11 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
1378 char __user *optval, int __user *optlen) 1410 char __user *optval, int __user *optlen)
1379{ 1411{
1380 int len; 1412 int len;
1413 int val;
1381 struct sock *sk = sock->sk; 1414 struct sock *sk = sock->sk;
1382 struct packet_sock *po = pkt_sk(sk); 1415 struct packet_sock *po = pkt_sk(sk);
1416 void *data;
1417 struct tpacket_stats st;
1383 1418
1384 if (level != SOL_PACKET) 1419 if (level != SOL_PACKET)
1385 return -ENOPROTOOPT; 1420 return -ENOPROTOOPT;
@@ -1392,9 +1427,6 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
1392 1427
1393 switch(optname) { 1428 switch(optname) {
1394 case PACKET_STATISTICS: 1429 case PACKET_STATISTICS:
1395 {
1396 struct tpacket_stats st;
1397
1398 if (len > sizeof(struct tpacket_stats)) 1430 if (len > sizeof(struct tpacket_stats))
1399 len = sizeof(struct tpacket_stats); 1431 len = sizeof(struct tpacket_stats);
1400 spin_lock_bh(&sk->sk_receive_queue.lock); 1432 spin_lock_bh(&sk->sk_receive_queue.lock);
@@ -1403,16 +1435,23 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
1403 spin_unlock_bh(&sk->sk_receive_queue.lock); 1435 spin_unlock_bh(&sk->sk_receive_queue.lock);
1404 st.tp_packets += st.tp_drops; 1436 st.tp_packets += st.tp_drops;
1405 1437
1406 if (copy_to_user(optval, &st, len)) 1438 data = &st;
1407 return -EFAULT; 1439 break;
1440 case PACKET_AUXDATA:
1441 if (len > sizeof(int))
1442 len = sizeof(int);
1443 val = po->auxdata;
1444
1445 data = &val;
1408 break; 1446 break;
1409 }
1410 default: 1447 default:
1411 return -ENOPROTOOPT; 1448 return -ENOPROTOOPT;
1412 } 1449 }
1413 1450
1414 if (put_user(len, optlen)) 1451 if (put_user(len, optlen))
1415 return -EFAULT; 1452 return -EFAULT;
1453 if (copy_to_user(optval, data, len))
1454 return -EFAULT;
1416 return 0; 1455 return 0;
1417} 1456}
1418 1457