OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [before_ORP/] [uclinux/] [uClinux-2.0.x/] [net/] [core/] [datagram.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 200 simons
/*
2
 *      SUCS NET3:
3
 *
4
 *      Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top
5
 *      of these would make sense. Not tonight however 8-).
6
 *      This is used because UDP, RAW, PACKET, DDP, IPX, AX.25 and NetROM layer all have identical select code and mostly
7
 *      identical recvmsg() code. So we share it here. The select was shared before but buried in udp.c so I moved it.
8
 *
9
 *      Authors:        Alan Cox <alan@cymru.net>. (datagram_select() from old udp.c code)
10
 *
11
 *      Fixes:
12
 *              Alan Cox        :       NULL return from skb_peek_copy() understood
13
 *              Alan Cox        :       Rewrote skb_read_datagram to avoid the skb_peek_copy stuff.
14
 *              Alan Cox        :       Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but
15
 *                                      AX.25 now works right, and SPX is feasible.
16
 *              Alan Cox        :       Fixed write select of non IP protocol crash.
17
 *              Florian  La Roche:      Changed for my new skbuff handling.
18
 *              Darryl Miles    :       Fixed non-blocking SOCK_SEQPACKET.
19
 *              Linus Torvalds  :       BSD semantic fixes.
20
 *              Alan Cox        :       Datagram iovec handling
21
 *              Darryl Miles    :       Fixed non-blocking SOCK_STREAM.
22
 *
23
 */
24
 
25
#include <linux/types.h>
26
#include <linux/kernel.h>
27
#include <asm/segment.h>
28
#include <asm/system.h>
29
#include <linux/mm.h>
30
#include <linux/interrupt.h>
31
#include <linux/in.h>
32
#include <linux/errno.h>
33
#include <linux/sched.h>
34
#include <linux/inet.h>
35
#include <linux/netdevice.h>
36
#include <net/ip.h>
37
#include <net/protocol.h>
38
#include <net/route.h>
39
#include <net/tcp.h>
40
#include <net/udp.h>
41
#include <linux/skbuff.h>
42
#include <net/sock.h>
43
 
44
 
45
/*
46
 * Wait for a packet..
47
 *
48
 * Interrupts off so that no packet arrives before we begin sleeping.
49
 * Otherwise we might miss our wake up
50
 */
51
 
52
static inline void wait_for_packet(struct sock * sk)
53
{
54
        unsigned long flags;
55
 
56
        release_sock(sk);
57
        save_flags(flags);
58
        cli();
59
        if (skb_peek(&sk->receive_queue) == NULL)
60
                interruptible_sleep_on(sk->sleep);
61
        restore_flags(flags);
62
        lock_sock(sk);
63
}
64
 
65
/*
66
 *      Is a socket 'connection oriented' ?
67
 */
68
 
69
static inline int connection_based(struct sock *sk)
70
{
71
        if(sk->type==SOCK_SEQPACKET || sk->type==SOCK_STREAM)
72
                return 1;
73
        return 0;
74
}
75
 
76
/*
77
 *      Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
78
 *      races. This replaces identical code in packet,raw and udp, as well as the IPX
79
 *      AX.25 and Appletalk. It also finally fixes the long standing peek and read
80
 *      race for datagram sockets. If you alter this routine remember it must be
81
 *      re-entrant.
82
 *
83
 *      This function will lock the socket if a skb is returned, so the caller
84
 *      needs to unlock the socket in that case (usually by calling skb_free_datagram)
85
 */
86
 
87
struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err)
88
{
89
        int error;
90
        struct sk_buff *skb;
91
 
92
        lock_sock(sk);
93
restart:
94
        while(skb_queue_empty(&sk->receive_queue))      /* No data */
95
        {
96
                /* Socket errors? */
97
                error = sock_error(sk);
98
                if (error)
99
                        goto no_packet;
100
 
101
                /* Socket shut down? */
102
                if (sk->shutdown & RCV_SHUTDOWN)
103
                        goto no_packet;
104
 
105
                /* Sequenced packets can come disconnected. If so we report the problem */
106
                error = -ENOTCONN;
107
                if(connection_based(sk) && sk->state!=TCP_ESTABLISHED)
108
                        goto no_packet;
109
 
110
                /* User doesn't want to wait */
111
                error = -EAGAIN;
112
                if (noblock)
113
                        goto no_packet;
114
 
115
                /* handle signals */
116
                error = -ERESTARTSYS;
117
                if (current->signal & ~current->blocked)
118
                        goto no_packet;
119
 
120
                wait_for_packet(sk);
121
          }
122
 
123
        /* Again only user level code calls this function, so nothing interrupt level
124
           will suddenly eat the receive_queue */
125
        if (flags & MSG_PEEK)
126
        {
127
                unsigned long flags;
128
                save_flags(flags);
129
                cli();
130
                skb=skb_peek(&sk->receive_queue);
131
                if(skb!=NULL)
132
                        skb->users++;
133
                restore_flags(flags);
134
                if(skb==NULL)           /* shouldn't happen but .. */
135
                        goto restart;
136
                return skb;
137
        }
138
        skb = skb_dequeue(&sk->receive_queue);
139
        if (!skb)       /* Avoid race if someone beats us to the data */
140
                goto restart;
141
        skb->users++;
142
        return skb;
143
 
144
no_packet:
145
        release_sock(sk);
146
        *err = error;
147
        return NULL;
148
}
149
 
150
void skb_free_datagram(struct sock * sk, struct sk_buff *skb)
151
{
152
        unsigned long flags;
153
 
154
        save_flags(flags);
155
        cli();
156
        skb->users--;
157
        if(skb->users <= 0) {
158
                /* See if it needs destroying */
159
                /* Been dequeued by someone - ie it's read */
160
                if(!skb->next && !skb->prev)
161
                        kfree_skb(skb,FREE_READ);
162
        }
163
        restore_flags(flags);
164
        release_sock(sk);
165
}
166
 
167
/*
168
 *      Copy a datagram to a linear buffer.
169
 */
170
 
171
void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
172
{
173
        memcpy_tofs(to,skb->h.raw+offset,size);
174
}
175
 
176
 
177
/*
178
 *      Copy a datagram to an iovec.
179
 */
180
 
181
void skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to, int size)
182
{
183
        memcpy_toiovec(to,skb->h.raw+offset,size);
184
}
185
 
186
/*
187
 *      Datagram select: Again totally generic. Moved from udp.c
188
 *      Now does seqpacket.
189
 */
190
 
191
int datagram_select(struct sock *sk, int sel_type, select_table *wait)
192
{
193
        select_wait(sk->sleep, wait);
194
        switch(sel_type)
195
        {
196
                case SEL_IN:
197
                        if (sk->err)
198
                                return 1;
199
                        if (sk->shutdown & RCV_SHUTDOWN)
200
                                return 1;
201
                        if (connection_based(sk) && sk->state==TCP_CLOSE)
202
                        {
203
                                /* Connection closed: Wake up */
204
                                return(1);
205
                        }
206
                        if (skb_peek(&sk->receive_queue) != NULL)
207
                        {       /* This appears to be consistent
208
                                   with other stacks */
209
                                return(1);
210
                        }
211
                        return(0);
212
 
213
                case SEL_OUT:
214
                        if (sk->err)
215
                                return 1;
216
                        if (sk->shutdown & SEND_SHUTDOWN)
217
                                return 1;
218
                        if (connection_based(sk) && sk->state==TCP_SYN_SENT)
219
                        {
220
                                /* Connection still in progress */
221
                                break;
222
                        }
223
                        if (sk->prot && sock_wspace(sk) >= MIN_WRITE_SPACE)
224
                        {
225
                                return(1);
226
                        }
227
                        if (sk->prot==NULL && sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE)
228
                        {
229
                                return(1);
230
                        }
231
                        return(0);
232
 
233
                case SEL_EX:
234
                        if (sk->err)
235
                                return(1); /* Socket has gone into error state (eg icmp error) */
236
                        return(0);
237
        }
238
        return(0);
239
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.