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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [core/] [iovec.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1278 phoenix
/*
2
 *      iovec manipulation routines.
3
 *
4
 *
5
 *              This program is free software; you can redistribute it and/or
6
 *              modify it under the terms of the GNU General Public License
7
 *              as published by the Free Software Foundation; either version
8
 *              2 of the License, or (at your option) any later version.
9
 *
10
 *      Fixes:
11
 *              Andrew Lunn     :       Errors in iovec copying.
12
 *              Pedro Roque     :       Added memcpy_fromiovecend and
13
 *                                      csum_..._fromiovecend.
14
 *              Andi Kleen      :       fixed error handling for 2.1
15
 *              Alexey Kuznetsov:       2.1 optimisations
16
 *              Andi Kleen      :       Fix csum*fromiovecend for IPv6.
17
 */
18
 
19
 
20
#include <linux/errno.h>
21
#include <linux/sched.h>
22
#include <linux/kernel.h>
23
#include <linux/mm.h>
24
#include <linux/slab.h>
25
#include <linux/net.h>
26
#include <linux/in6.h>
27
#include <asm/uaccess.h>
28
#include <asm/byteorder.h>
29
#include <net/checksum.h>
30
#include <net/sock.h>
31
 
32
/*
33
 *      Verify iovec. The caller must ensure that the iovec is big enough
34
 *      to hold the message iovec.
35
 *
36
 *      Save time not doing verify_area. copy_*_user will make this work
37
 *      in any case.
38
 */
39
 
40
int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
41
{
42
        int size, err, ct;
43
 
44
        if(m->msg_namelen)
45
        {
46
                if(mode==VERIFY_READ)
47
                {
48
                        err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address);
49
                        if(err<0)
50
                                goto out;
51
                }
52
 
53
                m->msg_name = address;
54
        } else
55
                m->msg_name = NULL;
56
 
57
        err = -EFAULT;
58
        size = m->msg_iovlen * sizeof(struct iovec);
59
        if (copy_from_user(iov, m->msg_iov, size))
60
                goto out;
61
        m->msg_iov=iov;
62
 
63
        for (err = 0, ct = 0; ct < m->msg_iovlen; ct++) {
64
                err += iov[ct].iov_len;
65
                /* Goal is not to verify user data, but to prevent returning
66
                   negative value, which is interpreted as errno.
67
                   Overflow is still possible, but it is harmless.
68
                 */
69
                if (err < 0)
70
                        return -EMSGSIZE;
71
        }
72
out:
73
        return err;
74
}
75
 
76
/*
77
 *      Copy kernel to iovec. Returns -EFAULT on error.
78
 *
79
 *      Note: this modifies the original iovec.
80
 */
81
 
82
int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
83
{
84
        int err = -EFAULT;
85
 
86
        while(len>0)
87
        {
88
                if(iov->iov_len)
89
                {
90
                        int copy = min_t(unsigned int, iov->iov_len, len);
91
                        if (copy_to_user(iov->iov_base, kdata, copy))
92
                                goto out;
93
                        kdata+=copy;
94
                        len-=copy;
95
                        iov->iov_len-=copy;
96
                        iov->iov_base+=copy;
97
                }
98
                iov++;
99
        }
100
        err = 0;
101
out:
102
        return err;
103
}
104
 
105
/*
106
 *      In kernel copy to iovec. Returns -EFAULT on error.
107
 *
108
 *      Note: this modifies the original iovec.
109
 */
110
 
111
void memcpy_tokerneliovec(struct iovec *iov, unsigned char *kdata, int len)
112
{
113
        while(len>0)
114
        {
115
                if(iov->iov_len)
116
                {
117
                        int copy = min_t(unsigned int, iov->iov_len, len);
118
                        memcpy(iov->iov_base, kdata, copy);
119
                        kdata+=copy;
120
                        len-=copy;
121
                        iov->iov_len-=copy;
122
                        iov->iov_base+=copy;
123
                }
124
                iov++;
125
        }
126
}
127
 
128
 
129
/*
130
 *      Copy iovec to kernel. Returns -EFAULT on error.
131
 *
132
 *      Note: this modifies the original iovec.
133
 */
134
 
135
int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
136
{
137
        int err = -EFAULT;
138
 
139
        while(len>0)
140
        {
141
                if(iov->iov_len)
142
                {
143
                        int copy = min_t(unsigned int, len, iov->iov_len);
144
                        if (copy_from_user(kdata, iov->iov_base, copy))
145
                                goto out;
146
                        len-=copy;
147
                        kdata+=copy;
148
                        iov->iov_base+=copy;
149
                        iov->iov_len-=copy;
150
                }
151
                iov++;
152
        }
153
        err = 0;
154
out:
155
        return err;
156
}
157
 
158
 
159
/*
160
 *      For use with ip_build_xmit
161
 */
162
 
163
int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
164
                        int len)
165
{
166
        int err = -EFAULT;
167
 
168
        /* Skip over the finished iovecs */
169
        while(offset >= iov->iov_len)
170
        {
171
                offset -= iov->iov_len;
172
                iov++;
173
        }
174
 
175
        while (len > 0)
176
        {
177
                u8 *base = iov->iov_base + offset;
178
                int copy = min_t(unsigned int, len, iov->iov_len - offset);
179
 
180
                offset = 0;
181
                if (copy_from_user(kdata, base, copy))
182
                        goto out;
183
                len   -= copy;
184
                kdata += copy;
185
                iov++;
186
        }
187
        err = 0;
188
out:
189
        return err;
190
}
191
 
192
/*
193
 *      And now for the all-in-one: copy and checksum from a user iovec
194
 *      directly to a datagram
195
 *      Calls to csum_partial but the last must be in 32 bit chunks
196
 *
197
 *      ip_build_xmit must ensure that when fragmenting only the last
198
 *      call to this function will be unaligned also.
199
 */
200
 
201
int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov,
202
                                 int offset, unsigned int len, int *csump)
203
{
204
        int csum = *csump;
205
        int partial_cnt = 0, err = 0;
206
 
207
        /* Skip over the finished iovecs */
208
        while (offset >= iov->iov_len)
209
        {
210
                offset -= iov->iov_len;
211
                iov++;
212
        }
213
 
214
        while (len > 0)
215
        {
216
                u8 *base = iov->iov_base + offset;
217
                int copy = min_t(unsigned int, len, iov->iov_len - offset);
218
 
219
                offset = 0;
220
                /* There is a remnant from previous iov. */
221
                if (partial_cnt)
222
                {
223
                        int par_len = 4 - partial_cnt;
224
 
225
                        /* iov component is too short ... */
226
                        if (par_len > copy) {
227
                                if (copy_from_user(kdata, base, copy))
228
                                        goto out_fault;
229
                                kdata += copy;
230
                                base  += copy;
231
                                partial_cnt += copy;
232
                                len   -= copy;
233
                                iov++;
234
                                if (len)
235
                                        continue;
236
                                *csump = csum_partial(kdata - partial_cnt,
237
                                                         partial_cnt, csum);
238
                                goto out;
239
                        }
240
                        if (copy_from_user(kdata, base, par_len))
241
                                goto out_fault;
242
                        csum = csum_partial(kdata - partial_cnt, 4, csum);
243
                        kdata += par_len;
244
                        base  += par_len;
245
                        copy  -= par_len;
246
                        len   -= par_len;
247
                        partial_cnt = 0;
248
                }
249
 
250
                if (len > copy)
251
                {
252
                        partial_cnt = copy % 4;
253
                        if (partial_cnt)
254
                        {
255
                                copy -= partial_cnt;
256
                                if (copy_from_user(kdata + copy, base + copy,
257
                                                partial_cnt))
258
                                        goto out_fault;
259
                        }
260
                }
261
 
262
                if (copy) {
263
                        csum = csum_and_copy_from_user(base, kdata, copy,
264
                                                        csum, &err);
265
                        if (err)
266
                                goto out;
267
                }
268
                len   -= copy + partial_cnt;
269
                kdata += copy + partial_cnt;
270
                iov++;
271
        }
272
        *csump = csum;
273
out:
274
        return err;
275
 
276
out_fault:
277
        err = -EFAULT;
278
        goto out;
279
}

powered by: WebSVN 2.1.0

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