Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
75541efd
Commit
75541efd
authored
Jun 07, 2002
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://kernel-acme.bkbits.net:8080/net-cleanups-2.5-datagram
into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents
410e9a9b
64127bdf
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
142 additions
and
104 deletions
+142
-104
net/core/datagram.c
net/core/datagram.c
+142
-104
No files found.
net/core/datagram.c
View file @
75541efd
/*
* SUCS NET3:
*
* Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top
* of these would make sense. Not tonight however 8-).
* This is used because UDP, RAW, PACKET, DDP, IPX, AX.25 and NetROM layer all have identical poll code and mostly
* identical recvmsg() code. So we share it here. The poll was shared before but buried in udp.c so I moved it.
* Generic datagram handling routines. These are generic for all
* protocols. Possibly a generic IP version on top of these would
* make sense. Not tonight however 8-).
* This is used because UDP, RAW, PACKET, DDP, IPX, AX.25 and
* NetROM layer all have identical poll code and mostly
* identical recvmsg() code. So we share it here. The poll was
* shared before but buried in udp.c so I moved it.
*
* Authors: Alan Cox <alan@redhat.com>. (datagram_poll() from old udp.c code)
* Authors: Alan Cox <alan@redhat.com>. (datagram_poll() from old
* udp.c code)
*
* Fixes:
* Alan Cox : NULL return from skb_peek_copy() understood
* Alan Cox : Rewrote skb_read_datagram to avoid the skb_peek_copy stuff.
* Alan Cox : Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but
* AX.25 now works right, and SPX is feasible.
* Alan Cox : Fixed write poll of non IP protocol crash.
* Alan Cox : NULL return from skb_peek_copy()
* understood
* Alan Cox : Rewrote skb_read_datagram to avoid the
* skb_peek_copy stuff.
* Alan Cox : Added support for SOCK_SEQPACKET.
* IPX can no longer use the SO_TYPE hack
* but AX.25 now works right, and SPX is
* feasible.
* Alan Cox : Fixed write poll of non IP protocol
* crash.
* Florian La Roche: Changed for my new skbuff handling.
* Darryl Miles : Fixed non-blocking SOCK_SEQPACKET.
* Linus Torvalds : BSD semantic fixes.
...
...
@@ -48,18 +57,15 @@
/*
* Is a socket 'connection oriented' ?
*/
static
inline
int
connection_based
(
struct
sock
*
sk
)
{
return
(
sk
->
type
==
SOCK_SEQPACKET
||
sk
->
type
==
SOCK_STREAM
)
;
return
sk
->
type
==
SOCK_SEQPACKET
||
sk
->
type
==
SOCK_STREAM
;
}
/*
* Wait for a packet..
*/
static
int
wait_for_packet
(
struct
sock
*
sk
,
int
*
err
,
long
*
timeo_p
)
static
int
wait_for_packet
(
struct
sock
*
sk
,
int
*
err
,
long
*
timeo_p
)
{
int
error
;
...
...
@@ -74,51 +80,57 @@ static int wait_for_packet(struct sock * sk, int *err, long *timeo_p)
goto
out_err
;
if
(
!
skb_queue_empty
(
&
sk
->
receive_queue
))
goto
ready
;
goto
out
;
/* Socket shut down? */
if
(
sk
->
shutdown
&
RCV_SHUTDOWN
)
goto
out_noerr
;
/* Sequenced packets can come disconnected. If so we report the problem */
/* Sequenced packets can come disconnected.
* If so we report the problem
*/
error
=
-
ENOTCONN
;
if
(
connection_based
(
sk
)
&&
!
(
sk
->
state
==
TCP_ESTABLISHED
||
sk
->
state
==
TCP_LISTEN
))
if
(
connection_based
(
sk
)
&&
!
(
sk
->
state
==
TCP_ESTABLISHED
||
sk
->
state
==
TCP_LISTEN
))
goto
out_err
;
/* handle signals */
if
(
signal_pending
(
current
))
goto
interrupted
;
error
=
0
;
*
timeo_p
=
schedule_timeout
(
*
timeo_p
);
ready:
out:
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
return
0
;
return
error
;
interrupted:
error
=
sock_intr_errno
(
*
timeo_p
);
out_err:
*
err
=
error
;
out:
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
return
error
;
goto
out
;
out_noerr:
*
err
=
0
;
error
=
1
;
goto
out
;
}
/*
* Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
* races. This replaces identical code in packet,raw and udp, as well as the IPX
* AX.25 and Appletalk. It also finally fixes the long standing peek and read
* race for datagram sockets. If you alter this routine remember it must be
* re-entrant.
/**
* skb_recv_datagram - Receive a datagram skbuff
* @sk - socket
* @flags - MSG_ flags
* @noblock - blocking operation?
* @err - error code returned
*
* Get a datagram skbuff, understands the peeking, nonblocking wakeups
* and possible races. This replaces identical code in packet, raw and
* udp, as well as the IPX AX.25 and Appletalk. It also finally fixes
* the long standing peek and read race for datagram sockets. If you
* alter this routine remember it must be re-entrant.
*
* This function will lock the socket if a skb is returned, so the caller
* needs to unlock the socket in that case (usually by calling skb_free_datagram)
* needs to unlock the socket in that case (usually by calling
* skb_free_datagram)
*
* * It does not lock socket since today. This function is
* * free of race conditions. This measure should/can improve
...
...
@@ -132,36 +144,35 @@ static int wait_for_packet(struct sock * sk, int *err, long *timeo_p)
* quite explicitly by POSIX 1003.1g, don't change them without having
* the standard around please.
*/
struct
sk_buff
*
skb_recv_datagram
(
struct
sock
*
sk
,
unsigned
flags
,
int
noblock
,
int
*
err
)
struct
sk_buff
*
skb_recv_datagram
(
struct
sock
*
sk
,
unsigned
flags
,
int
noblock
,
int
*
err
)
{
int
error
;
struct
sk_buff
*
skb
;
long
timeo
;
/* Caller is allowed not to check sk->err before skb_recv_datagram() */
error
=
sock_error
(
sk
);
int
error
=
sock_error
(
sk
);
if
(
error
)
goto
no_packet
;
timeo
=
sock_rcvtimeo
(
sk
,
noblock
);
do
{
/* Again only user level code calls this function, so nothing
interrupt level
will suddenly eat the receive_queue.
Look at current nfs client by the way...
However, this function was corrent in any case. 8)
/* Again only user level code calls this function, so nothing
* interrupt level
will suddenly eat the receive_queue.
*
*
Look at current nfs client by the way...
*
However, this function was corrent in any case. 8)
*/
if
(
flags
&
MSG_PEEK
)
{
if
(
flags
&
MSG_PEEK
)
{
unsigned
long
cpu_flags
;
spin_lock_irqsave
(
&
sk
->
receive_queue
.
lock
,
cpu_flags
);
skb
=
skb_peek
(
&
sk
->
receive_queue
);
if
(
skb
!=
NULL
)
if
(
skb
)
atomic_inc
(
&
skb
->
users
);
spin_unlock_irqrestore
(
&
sk
->
receive_queue
.
lock
,
cpu_flags
);
spin_unlock_irqrestore
(
&
sk
->
receive_queue
.
lock
,
cpu_flags
);
}
else
skb
=
skb_dequeue
(
&
sk
->
receive_queue
);
...
...
@@ -173,7 +184,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
if
(
!
timeo
)
goto
no_packet
;
}
while
(
wait_for_packet
(
sk
,
err
,
&
timeo
)
==
0
);
}
while
(
!
wait_for_packet
(
sk
,
err
,
&
timeo
)
);
return
NULL
;
...
...
@@ -182,7 +193,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
return
NULL
;
}
void
skb_free_datagram
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
void
skb_free_datagram
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
{
kfree_skb
(
skb
);
}
...
...
@@ -190,26 +201,33 @@ void skb_free_datagram(struct sock * sk, struct sk_buff *skb)
/*
* Copy a datagram to a linear buffer.
*/
int
skb_copy_datagram
(
const
struct
sk_buff
*
skb
,
int
offset
,
char
*
to
,
int
size
)
{
struct
iovec
iov
=
{
to
,
size
};
struct
iovec
iov
=
{
iov_base:
to
,
iov_len:
size
,
};
return
skb_copy_datagram_iovec
(
skb
,
offset
,
&
iov
,
size
);
}
/*
* Copy a datagram to an iovec.
/**
* skb_copy_datagram_iovec - Copy a datagram to an iovec.
* @skb - buffer to copy
* @offset - offset in the buffer to start copying from
* @iovec - io vector to copy to
* @len - amount of data to copy from buffer to iovec
*
* Note: the iovec is modified during the copy.
*/
int
skb_copy_datagram_iovec
(
const
struct
sk_buff
*
skb
,
int
offset
,
struct
iovec
*
to
,
int
len
)
int
skb_copy_datagram_iovec
(
const
struct
sk_buff
*
skb
,
int
offset
,
struct
iovec
*
to
,
int
len
)
{
int
i
,
copy
;
int
start
=
skb
->
len
-
skb
->
data_len
;
int
i
,
copy
=
start
-
offset
;
/* Copy header. */
if
(
(
copy
=
start
-
offset
)
>
0
)
{
if
(
copy
>
0
)
{
if
(
copy
>
len
)
copy
=
len
;
if
(
memcpy_toiovec
(
to
,
skb
->
data
+
offset
,
copy
))
...
...
@@ -220,13 +238,13 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, struct iovec
}
/* Copy paged appendix. Hmm... why does this look so complicated? */
for
(
i
=
0
;
i
<
skb_shinfo
(
skb
)
->
nr_frags
;
i
++
)
{
for
(
i
=
0
;
i
<
skb_shinfo
(
skb
)
->
nr_frags
;
i
++
)
{
int
end
;
BUG_TRAP
(
start
<=
offset
+
len
);
BUG_TRAP
(
start
<=
offset
+
len
);
end
=
start
+
skb_shinfo
(
skb
)
->
frags
[
i
].
size
;
if
((
copy
=
end
-
offset
)
>
0
)
{
if
((
copy
=
end
-
offset
)
>
0
)
{
int
err
;
u8
*
vaddr
;
skb_frag_t
*
frag
=
&
skb_shinfo
(
skb
)
->
frags
[
i
];
...
...
@@ -236,7 +254,7 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, struct iovec
copy
=
len
;
vaddr
=
kmap
(
page
);
err
=
memcpy_toiovec
(
to
,
vaddr
+
frag
->
page_offset
+
offset
-
start
,
copy
);
offset
-
start
,
copy
);
kunmap
(
page
);
if
(
err
)
goto
fault
;
...
...
@@ -248,18 +266,20 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, struct iovec
}
if
(
skb_shinfo
(
skb
)
->
frag_list
)
{
struct
sk_buff
*
list
;
struct
sk_buff
*
list
=
skb_shinfo
(
skb
)
->
frag_list
;
for
(
list
=
skb_shinfo
(
skb
)
->
frag_list
;
list
;
list
=
list
->
next
)
{
for
(
;
list
;
list
=
list
->
next
)
{
int
end
;
BUG_TRAP
(
start
<=
offset
+
len
);
BUG_TRAP
(
start
<=
offset
+
len
);
end
=
start
+
list
->
len
;
if
((
copy
=
end
-
offset
)
>
0
)
{
if
((
copy
=
end
-
offset
)
>
0
)
{
if
(
copy
>
len
)
copy
=
len
;
if
(
skb_copy_datagram_iovec
(
list
,
offset
-
start
,
to
,
copy
))
if
(
skb_copy_datagram_iovec
(
list
,
offset
-
start
,
to
,
copy
))
goto
fault
;
if
((
len
-=
copy
)
==
0
)
return
0
;
...
...
@@ -268,25 +288,27 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset, struct iovec
start
=
end
;
}
}
if
(
len
==
0
)
if
(
!
len
)
return
0
;
fault:
return
-
EFAULT
;
}
int
skb_copy_and_csum_datagram
(
const
struct
sk_buff
*
skb
,
int
offset
,
u8
*
to
,
int
len
,
unsigned
int
*
csump
)
int
skb_copy_and_csum_datagram
(
const
struct
sk_buff
*
skb
,
int
offset
,
u8
*
to
,
int
len
,
unsigned
int
*
csump
)
{
int
i
,
copy
;
int
start
=
skb
->
len
-
skb
->
data_len
;
int
pos
=
0
;
int
i
,
copy
=
start
-
offset
;
/* Copy header. */
if
(
(
copy
=
start
-
offset
)
>
0
)
{
if
(
copy
>
0
)
{
int
err
=
0
;
if
(
copy
>
len
)
copy
=
len
;
*
csump
=
csum_and_copy_to_user
(
skb
->
data
+
offset
,
to
,
copy
,
*
csump
,
&
err
);
*
csump
=
csum_and_copy_to_user
(
skb
->
data
+
offset
,
to
,
copy
,
*
csump
,
&
err
);
if
(
err
)
goto
fault
;
if
((
len
-=
copy
)
==
0
)
...
...
@@ -296,13 +318,13 @@ int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, in
pos
=
copy
;
}
for
(
i
=
0
;
i
<
skb_shinfo
(
skb
)
->
nr_frags
;
i
++
)
{
for
(
i
=
0
;
i
<
skb_shinfo
(
skb
)
->
nr_frags
;
i
++
)
{
int
end
;
BUG_TRAP
(
start
<=
offset
+
len
);
BUG_TRAP
(
start
<=
offset
+
len
);
end
=
start
+
skb_shinfo
(
skb
)
->
frags
[
i
].
size
;
if
((
copy
=
end
-
offset
)
>
0
)
{
if
((
copy
=
end
-
offset
)
>
0
)
{
unsigned
int
csum2
;
int
err
=
0
;
u8
*
vaddr
;
...
...
@@ -312,8 +334,10 @@ int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, in
if
(
copy
>
len
)
copy
=
len
;
vaddr
=
kmap
(
page
);
csum2
=
csum_and_copy_to_user
(
vaddr
+
frag
->
page_offset
+
offset
-
start
,
to
,
copy
,
0
,
&
err
);
csum2
=
csum_and_copy_to_user
(
vaddr
+
frag
->
page_offset
+
offset
-
start
,
to
,
copy
,
0
,
&
err
);
kunmap
(
page
);
if
(
err
)
goto
fault
;
...
...
@@ -328,19 +352,22 @@ int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, in
}
if
(
skb_shinfo
(
skb
)
->
frag_list
)
{
struct
sk_buff
*
list
;
struct
sk_buff
*
list
=
skb_shinfo
(
skb
)
->
frag_list
;
for
(
list
=
skb_shinfo
(
skb
)
->
frag_list
;
list
;
list
=
list
->
next
)
{
for
(;
list
;
list
=
list
->
next
)
{
int
end
;
BUG_TRAP
(
start
<=
offset
+
len
);
BUG_TRAP
(
start
<=
offset
+
len
);
end
=
start
+
list
->
len
;
if
((
copy
=
end
-
offset
)
>
0
)
{
if
((
copy
=
end
-
offset
)
>
0
)
{
unsigned
int
csum2
=
0
;
if
(
copy
>
len
)
copy
=
len
;
if
(
skb_copy_and_csum_datagram
(
list
,
offset
-
start
,
to
,
copy
,
&
csum2
))
if
(
skb_copy_and_csum_datagram
(
list
,
offset
-
start
,
to
,
copy
,
&
csum2
))
goto
fault
;
*
csump
=
csum_block_add
(
*
csump
,
csum2
,
pos
);
if
((
len
-=
copy
)
==
0
)
...
...
@@ -352,39 +379,48 @@ int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, u8 *to, in
start
=
end
;
}
}
if
(
len
==
0
)
if
(
!
len
)
return
0
;
fault:
return
-
EFAULT
;
}
/* Copy and checkum skb to user iovec. Caller _must_ check that
skb will fit to this iovec.
Returns: 0 - success.
-EINVAL - checksum failure.
-EFAULT - fault during copy. Beware, in this case iovec can be
modified!
/**
* skb_copy_and_csum_datagram_iovec - Copy and checkum skb to user iovec.
* @skb - skbuff
* @hlen - hardware length
* @iovec - io vector
*
* Caller _must_ check that skb will fit to this iovec.
*
* Returns: 0 - success.
* -EINVAL - checksum failure.
* -EFAULT - fault during copy. Beware, in this case iovec
* can be modified!
*/
int
skb_copy_and_csum_datagram_iovec
(
const
struct
sk_buff
*
skb
,
int
hlen
,
struct
iovec
*
iov
)
int
skb_copy_and_csum_datagram_iovec
(
const
struct
sk_buff
*
skb
,
int
hlen
,
struct
iovec
*
iov
)
{
unsigned
int
csum
;
int
chunk
=
skb
->
len
-
hlen
;
/* Skip filled elements. Pretty silly, look at memcpy_toiovec, though 8) */
while
(
iov
->
iov_len
==
0
)
/* Skip filled elements.
* Pretty silly, look at memcpy_toiovec, though 8)
*/
while
(
!
iov
->
iov_len
)
iov
++
;
if
(
iov
->
iov_len
<
chunk
)
{
if
((
unsigned
short
)
csum_fold
(
skb_checksum
(
skb
,
0
,
chunk
+
hlen
,
skb
->
csum
)))
if
((
unsigned
short
)
csum_fold
(
skb_checksum
(
skb
,
0
,
chunk
+
hlen
,
skb
->
csum
)))
goto
csum_error
;
if
(
skb_copy_datagram_iovec
(
skb
,
hlen
,
iov
,
chunk
))
goto
fault
;
}
else
{
csum
=
csum_partial
(
skb
->
data
,
hlen
,
skb
->
csum
);
if
(
skb_copy_and_csum_datagram
(
skb
,
hlen
,
iov
->
iov_base
,
chunk
,
&
csum
))
if
(
skb_copy_and_csum_datagram
(
skb
,
hlen
,
iov
->
iov_base
,
chunk
,
&
csum
))
goto
fault
;
if
((
unsigned
short
)
csum_fold
(
csum
))
goto
csum_error
;
...
...
@@ -392,17 +428,18 @@ int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, int hlen, struct
iov
->
iov_base
+=
chunk
;
}
return
0
;
csum_error:
return
-
EINVAL
;
fault:
return
-
EFAULT
;
}
/*
/**
* datagram_poll - generic datagram poll
* @file - file struct
* @sock - socket
* @wait - poll table
*
* Datagram poll: Again totally generic. This also handles
* sequenced packet sockets providing the socket receive queue
* is only ever holding data ready to receive.
...
...
@@ -411,8 +448,8 @@ int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, int hlen, struct
* and you use a different write policy from sock_writeable()
* then please supply your own write_space callback.
*/
unsigned
int
datagram_poll
(
struct
file
*
file
,
struct
socket
*
sock
,
poll_table
*
wait
)
unsigned
int
datagram_poll
(
struct
file
*
file
,
struct
socket
*
sock
,
poll_table
*
wait
)
{
struct
sock
*
sk
=
sock
->
sk
;
unsigned
int
mask
;
...
...
@@ -427,12 +464,13 @@ unsigned int datagram_poll(struct file * file, struct socket *sock, poll_table *
mask
|=
POLLHUP
;
/* readable? */
if
(
!
skb_queue_empty
(
&
sk
->
receive_queue
)
||
(
sk
->
shutdown
&
RCV_SHUTDOWN
))
if
(
!
skb_queue_empty
(
&
sk
->
receive_queue
)
||
(
sk
->
shutdown
&
RCV_SHUTDOWN
))
mask
|=
POLLIN
|
POLLRDNORM
;
/* Connection-based need to check for termination and startup */
if
(
connection_based
(
sk
))
{
if
(
sk
->
state
==
TCP_CLOSE
)
if
(
sk
->
state
==
TCP_CLOSE
)
mask
|=
POLLHUP
;
/* connection hasn't started yet? */
if
(
sk
->
state
==
TCP_SYN_SENT
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment