datagram.c revision c752f0739f09b803aed191c4765a3b6650a08653
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SUCS NET3: 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Generic datagram handling routines. These are generic for all 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * protocols. Possibly a generic IP version on top of these would 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * make sense. Not tonight however 8-). 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is used because UDP, RAW, PACKET, DDP, IPX, AX.25 and 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NetROM layer all have identical poll code and mostly 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * identical recvmsg() code. So we share it here. The poll was 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * shared before but buried in udp.c so I moved it. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Authors: Alan Cox <alan@redhat.com>. (datagram_poll() from old 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * udp.c code) 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fixes: 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Alan Cox : NULL return from skb_peek_copy() 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * understood 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Alan Cox : Rewrote skb_read_datagram to avoid the 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * skb_peek_copy stuff. 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Alan Cox : Added support for SOCK_SEQPACKET. 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IPX can no longer use the SO_TYPE hack 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but AX.25 now works right, and SPX is 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * feasible. 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Alan Cox : Fixed write poll of non IP protocol 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * crash. 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Florian La Roche: Changed for my new skbuff handling. 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Darryl Miles : Fixed non-blocking SOCK_SEQPACKET. 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linus Torvalds : BSD semantic fixes. 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Alan Cox : Datagram iovec handling 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Darryl Miles : Fixed non-blocking SOCK_STREAM. 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Alan Cox : POSIXisms 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Pete Wyckoff : Unconnected accept() fix. 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/inet.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rtnetlink.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/poll.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/highmem.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/protocol.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54c752f0739f09b803aed191c4765a3b6650a08653Arnaldo Carvalho de Melo#include <net/checksum.h> 55c752f0739f09b803aed191c4765a3b6650a08653Arnaldo Carvalho de Melo#include <net/sock.h> 56c752f0739f09b803aed191c4765a3b6650a08653Arnaldo Carvalho de Melo#include <net/tcp_states.h> 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Is a socket 'connection oriented' ? 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int connection_based(struct sock *sk) 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for a packet.. 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_for_packet(struct sock *sk, int *err, long *timeo_p) 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DEFINE_WAIT(wait); 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Socket errors? */ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = sock_error(sk); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_err; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb_queue_empty(&sk->sk_receive_queue)) 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Socket shut down? */ 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sk->sk_shutdown & RCV_SHUTDOWN) 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_noerr; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Sequenced packets can come disconnected. 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If so we report the problem 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -ENOTCONN; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (connection_based(sk) && 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !(sk->sk_state == TCP_ESTABLISHED || sk->sk_state == TCP_LISTEN)) 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_err; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* handle signals */ 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto interrupted; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = 0; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *timeo_p = schedule_timeout(*timeo_p); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds finish_wait(sk->sk_sleep, &wait); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsinterrupted: 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = sock_intr_errno(*timeo_p); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_err: 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *err = error; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_noerr: 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *err = 0; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = 1; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * skb_recv_datagram - Receive a datagram skbuff 1184dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @sk: socket 1194dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @flags: MSG_ flags 1204dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @noblock: blocking operation? 1214dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @err: error code returned 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get a datagram skbuff, understands the peeking, nonblocking wakeups 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and possible races. This replaces identical code in packet, raw and 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * udp, as well as the IPX AX.25 and Appletalk. It also finally fixes 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the long standing peek and read race for datagram sockets. If you 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * alter this routine remember it must be re-entrant. 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function will lock the socket if a skb is returned, so the caller 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * needs to unlock the socket in that case (usually by calling 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * skb_free_datagram) 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * * It does not lock socket since today. This function is 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * * free of race conditions. This measure should/can improve 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * * significantly datagram socket latencies at high loads, 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * * when data copying to user space takes lots of time. 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * * (BTW I've just killed the last cli() in IP/IPv6/core/netlink/packet 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * * 8) Great win.) 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * * --ANK (980729) 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The order of the tests when we find no data waiting are specified 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * quite explicitly by POSIX 1003.1g, don't change them without having 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the standard around please. 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int noblock, int *err) 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long timeo; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Caller is allowed not to check sk->sk_err before skb_recv_datagram() 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error = sock_error(sk); 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto no_packet; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeo = sock_rcvtimeo(sk, noblock); 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Again only user level code calls this function, so nothing 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupt level will suddenly eat the receive_queue. 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Look at current nfs client by the way... 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * However, this function was corrent in any case. 8) 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (flags & MSG_PEEK) { 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long cpu_flags; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&sk->sk_receive_queue.lock, 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_flags); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = skb_peek(&sk->sk_receive_queue); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb) 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&skb->users); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&sk->sk_receive_queue.lock, 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_flags); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = skb_dequeue(&sk->sk_receive_queue); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb) 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return skb; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* User doesn't want to wait */ 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -EAGAIN; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!timeo) 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto no_packet; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (!wait_for_packet(sk, err, &timeo)); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsno_packet: 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *err = error; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid skb_free_datagram(struct sock *sk, struct sk_buff *skb) 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * skb_copy_datagram_iovec - Copy a datagram to an iovec. 2044dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @skb: buffer to copy 2054dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @offset: offset in the buffer to start copying from 20667be2dd1bace0ec7ce2dbc1bba3f8df3d7be597eMartin Waitz * @to: io vector to copy to 2074dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @len: amount of data to copy from buffer to iovec 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: the iovec is modified during the copy. 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct iovec *to, int len) 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int start = skb_headlen(skb); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, copy = start - offset; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Copy header. */ 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy > 0) { 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy > len) 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copy = len; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (memcpy_toiovec(to, skb->data + offset, copy)) 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fault; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((len -= copy) == 0) 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset += copy; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Copy paged appendix. Hmm... why does this look so complicated? */ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int end; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_TRAP(start <= offset + len); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end = start + skb_shinfo(skb)->frags[i].size; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((copy = end - offset) > 0) { 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *vaddr; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct page *page = frag->page; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy > len) 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copy = len; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vaddr = kmap(page); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = memcpy_toiovec(to, vaddr + frag->page_offset + 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset - start, copy); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kunmap(page); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fault; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(len -= copy)) 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset += copy; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = end; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb_shinfo(skb)->frag_list) { 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *list = skb_shinfo(skb)->frag_list; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (; list; list = list->next) { 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int end; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_TRAP(start <= offset + len); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end = start + list->len; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((copy = end - offset) > 0) { 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy > len) 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copy = len; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb_copy_datagram_iovec(list, 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset - start, 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to, copy)) 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fault; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((len -= copy) == 0) 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset += copy; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = end; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!len) 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfault: 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 __user *to, int len, 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int *csump) 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int start = skb_headlen(skb); 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pos = 0; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, copy = start - offset; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Copy header. */ 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy > 0) { 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy > len) 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copy = len; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *csump = csum_and_copy_to_user(skb->data + offset, to, copy, 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *csump, &err); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fault; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((len -= copy) == 0) 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset += copy; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to += copy; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pos = copy; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int end; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_TRAP(start <= offset + len); 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end = start + skb_shinfo(skb)->frags[i].size; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((copy = end - offset) > 0) { 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int csum2; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *vaddr; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct page *page = frag->page; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy > len) 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copy = len; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vaddr = kmap(page); 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csum2 = csum_and_copy_to_user(vaddr + 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds frag->page_offset + 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset - start, 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to, copy, 0, &err); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kunmap(page); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fault; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *csump = csum_block_add(*csump, csum2, pos); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(len -= copy)) 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset += copy; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to += copy; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pos += copy; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = end; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb_shinfo(skb)->frag_list) { 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *list = skb_shinfo(skb)->frag_list; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (; list; list=list->next) { 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int end; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_TRAP(start <= offset + len); 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds end = start + list->len; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((copy = end - offset) > 0) { 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int csum2 = 0; 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy > len) 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copy = len; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb_copy_and_csum_datagram(list, 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset - start, 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to, copy, 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &csum2)) 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fault; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *csump = csum_block_add(*csump, csum2, pos); 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((len -= copy) == 0) 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset += copy; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to += copy; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pos += copy; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = end; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!len) 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfault: 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * skb_copy_and_csum_datagram_iovec - Copy and checkum skb to user iovec. 3804dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @skb: skbuff 3814dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @hlen: hardware length 38267be2dd1bace0ec7ce2dbc1bba3f8df3d7be597eMartin Waitz * @iov: io vector 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Caller _must_ check that skb will fit to this iovec. 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns: 0 - success. 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -EINVAL - checksum failure. 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * -EFAULT - fault during copy. Beware, in this case iovec 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can be modified! 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int hlen, struct iovec *iov) 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int csum; 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int chunk = skb->len - hlen; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Skip filled elements. 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Pretty silly, look at memcpy_toiovec, though 8) 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!iov->iov_len) 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iov++; 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (iov->iov_len < chunk) { 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((unsigned short)csum_fold(skb_checksum(skb, 0, chunk + hlen, 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->csum))) 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto csum_error; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb_copy_datagram_iovec(skb, hlen, iov, chunk)) 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fault; 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csum = csum_partial(skb->data, hlen, skb->csum); 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb_copy_and_csum_datagram(skb, hlen, iov->iov_base, 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chunk, &csum)) 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fault; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((unsigned short)csum_fold(csum)) 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto csum_error; 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iov->iov_len -= chunk; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iov->iov_base += chunk; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscsum_error: 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfault: 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * datagram_poll - generic datagram poll 4284dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @file: file struct 4294dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @sock: socket 4304dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa * @wait: poll table 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Datagram poll: Again totally generic. This also handles 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sequenced packet sockets providing the socket receive queue 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is only ever holding data ready to receive. 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: when you _don't_ use this routine for this protocol, 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and you use a different write policy from sock_writeable() 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * then please supply your own write_space callback. 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunsigned int datagram_poll(struct file *file, struct socket *sock, 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds poll_table *wait) 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sock *sk = sock->sk; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int mask; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds poll_wait(file, sk->sk_sleep, wait); 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask = 0; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* exceptional events? */ 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask |= POLLERR; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sk->sk_shutdown == SHUTDOWN_MASK) 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask |= POLLHUP; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* readable? */ 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!skb_queue_empty(&sk->sk_receive_queue) || 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (sk->sk_shutdown & RCV_SHUTDOWN)) 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask |= POLLIN | POLLRDNORM; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Connection-based need to check for termination and startup */ 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (connection_based(sk)) { 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sk->sk_state == TCP_CLOSE) 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask |= POLLHUP; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* connection hasn't started yet? */ 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sk->sk_state == TCP_SYN_SENT) 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return mask; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* writable? */ 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sock_writeable(sk)) 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask |= POLLOUT | POLLWRNORM | POLLWRBAND; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return mask; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(datagram_poll); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec); 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(skb_copy_datagram_iovec); 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(skb_free_datagram); 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(skb_recv_datagram); 483