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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [net/] [ipv4/] [raw.c] - Blame information for rev 1772

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1629 jcastillo
/*
2
 * INET         An implementation of the TCP/IP protocol suite for the LINUX
3
 *              operating system.  INET is implemented using the  BSD Socket
4
 *              interface as the means of communication with the user level.
5
 *
6
 *              RAW - implementation of IP "raw" sockets.
7
 *
8
 * Version:     @(#)raw.c       1.0.4   05/25/93
9
 *
10
 * Authors:     Ross Biro, <bir7@leland.Stanford.Edu>
11
 *              Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
12
 *
13
 * Fixes:
14
 *              Alan Cox        :       verify_area() fixed up
15
 *              Alan Cox        :       ICMP error handling
16
 *              Alan Cox        :       EMSGSIZE if you send too big a packet
17
 *              Alan Cox        :       Now uses generic datagrams and shared skbuff
18
 *                                      library. No more peek crashes, no more backlogs
19
 *              Alan Cox        :       Checks sk->broadcast.
20
 *              Alan Cox        :       Uses skb_free_datagram/skb_copy_datagram
21
 *              Alan Cox        :       Raw passes ip options too
22
 *              Alan Cox        :       Setsocketopt added
23
 *              Alan Cox        :       Fixed error return for broadcasts
24
 *              Alan Cox        :       Removed wake_up calls
25
 *              Alan Cox        :       Use ttl/tos
26
 *              Alan Cox        :       Cleaned up old debugging
27
 *              Alan Cox        :       Use new kernel side addresses
28
 *      Arnt Gulbrandsen        :       Fixed MSG_DONTROUTE in raw sockets.
29
 *              Alan Cox        :       BSD style RAW socket demultiplexing.
30
 *              Alan Cox        :       Beginnings of mrouted support.
31
 *              Alan Cox        :       Added IP_HDRINCL option.
32
 *              Alan Cox        :       Skip broadcast check if BSDism set.
33
 *              David S. Miller :       New socket lookup architecture for ISS.
34
 *
35
 *              This program is free software; you can redistribute it and/or
36
 *              modify it under the terms of the GNU General Public License
37
 *              as published by the Free Software Foundation; either version
38
 *              2 of the License, or (at your option) any later version.
39
 */
40
 
41
#include <linux/config.h> 
42
#include <asm/system.h>
43
#include <asm/segment.h>
44
#include <linux/types.h>
45
#include <linux/sched.h>
46
#include <linux/errno.h>
47
#include <linux/timer.h>
48
#include <linux/mm.h>
49
#include <linux/kernel.h>
50
#include <linux/fcntl.h>
51
#include <linux/socket.h>
52
#include <linux/in.h>
53
#include <linux/inet.h>
54
#include <linux/netdevice.h>
55
#include <linux/mroute.h>
56
#include <net/ip.h>
57
#include <net/protocol.h>
58
#include <linux/skbuff.h>
59
#include <net/sock.h>
60
#include <net/icmp.h>
61
#include <net/udp.h>
62
#include <net/raw.h>
63
#include <net/checksum.h>
64
 
65
#ifdef CONFIG_IP_MROUTE
66
struct sock *mroute_socket=NULL;
67
#endif
68
 
69
struct sock *raw_v4_htable[RAWV4_HTABLE_SIZE];
70
 
71
static void raw_v4_hash(struct sock *sk)
72
{
73
        struct sock **skp;
74
        int num = sk->num;
75
 
76
        num &= (RAWV4_HTABLE_SIZE - 1);
77
        skp = &raw_v4_htable[num];
78
        SOCKHASH_LOCK();
79
        sk->next = *skp;
80
        *skp = sk;
81
        sk->hashent = num;
82
        SOCKHASH_UNLOCK();
83
}
84
 
85
static void raw_v4_unhash(struct sock *sk)
86
{
87
        struct sock **skp;
88
        int num = sk->num;
89
 
90
        num &= (RAWV4_HTABLE_SIZE - 1);
91
        skp = &raw_v4_htable[num];
92
 
93
        SOCKHASH_LOCK();
94
        while(*skp != NULL) {
95
                if(*skp == sk) {
96
                        *skp = sk->next;
97
                        break;
98
                }
99
                skp = &((*skp)->next);
100
        }
101
        SOCKHASH_UNLOCK();
102
}
103
 
104
static void raw_v4_rehash(struct sock *sk)
105
{
106
        struct sock **skp;
107
        int num = sk->num;
108
        int oldnum = sk->hashent;
109
 
110
        num &= (RAWV4_HTABLE_SIZE - 1);
111
        skp = &raw_v4_htable[oldnum];
112
 
113
        SOCKHASH_LOCK();
114
        while(*skp != NULL) {
115
                if(*skp == sk) {
116
                        *skp = sk->next;
117
                        break;
118
                }
119
                skp = &((*skp)->next);
120
        }
121
        sk->next = raw_v4_htable[num];
122
        raw_v4_htable[num] = sk;
123
        sk->hashent = num;
124
        SOCKHASH_UNLOCK();
125
}
126
 
127
/* Grumble... icmp and ip_input want to get at this... */
128
struct sock *raw_v4_lookup(struct sock *sk, unsigned short num,
129
                           unsigned long raddr, unsigned long laddr)
130
{
131
        struct sock *s = sk;
132
 
133
        SOCKHASH_LOCK();
134
        for(s = sk; s; s = s->next) {
135
                if((s->num == num)                              &&
136
                   !(s->dead && (s->state == TCP_CLOSE))        &&
137
                   !(s->daddr && s->daddr != raddr)             &&
138
                   !(s->rcv_saddr && s->rcv_saddr != laddr))
139
                        break; /* gotcha */
140
        }
141
        SOCKHASH_UNLOCK();
142
        return s;
143
}
144
 
145
static inline unsigned long min(unsigned long a, unsigned long b)
146
{
147
        if (a < b)
148
                return(a);
149
        return(b);
150
}
151
 
152
 
153
/*
154
 *      Raw_err does not currently get called by the icmp module - FIXME:
155
 */
156
 
157
void raw_err (int type, int code, unsigned char *header, __u32 daddr,
158
         __u32 saddr, struct inet_protocol *protocol)
159
{
160
        struct sock *sk;
161
 
162
        if (protocol == NULL)
163
                return;
164
        sk = (struct sock *) protocol->data;
165
        if (sk == NULL)
166
                return;
167
 
168
        /* This is meaningless in raw sockets. */
169
        if (type == ICMP_SOURCE_QUENCH)
170
        {
171
                if (sk->cong_window > 1) sk->cong_window = sk->cong_window/2;
172
                return;
173
        }
174
 
175
        if(type == ICMP_PARAMETERPROB)
176
        {
177
                sk->err = EPROTO;
178
                sk->error_report(sk);
179
        }
180
 
181
        if(code<=NR_ICMP_UNREACH)
182
        {
183
                sk->err = icmp_err_convert[code & 0xff].errno;
184
                sk->error_report(sk);
185
        }
186
 
187
        return;
188
}
189
 
190
static inline void raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
191
{
192
        /* Charge it to the socket. */
193
 
194
        if (__sock_queue_rcv_skb(sk,skb)<0)
195
        {
196
                ip_statistics.IpInDiscards++;
197
                skb->sk=NULL;
198
                kfree_skb(skb, FREE_READ);
199
                return;
200
        }
201
 
202
        ip_statistics.IpInDelivers++;
203
}
204
 
205
/*
206
 * This is the prot->rcv() function. It's called when we have
207
 * backlogged packets from core/sock.c if we couldn't receive it
208
 * when the packet arrived.
209
 */
210
static int raw_rcv_redo(struct sk_buff *skb, struct device *dev, struct options *opt,
211
        __u32 daddr, unsigned short len,
212
        __u32 saddr, int redo, struct inet_protocol * protocol)
213
{
214
        raw_rcv_skb(skb->sk, skb);
215
        return 0;
216
}
217
 
218
/* This gets rid of all the nasties in af_inet. -DaveM */
219
static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
220
{
221
        struct sockaddr_in *addr = (struct sockaddr_in *) uaddr;
222
        int chk_addr_ret;
223
 
224
        if((sk->state != TCP_CLOSE) || (addr_len < sizeof(struct sockaddr_in)))
225
                return -EINVAL;
226
        chk_addr_ret = ip_chk_addr(addr->sin_addr.s_addr);
227
        if(addr->sin_addr.s_addr != 0 && chk_addr_ret != IS_MYADDR &&
228
           chk_addr_ret != IS_MULTICAST && chk_addr_ret != IS_BROADCAST) {
229
#ifdef CONFIG_IP_TRANSPARENT_PROXY
230
                /* Superuser may bind to any address to allow transparent proxying. */
231
                if(!suser())
232
#endif
233
                        return -EADDRNOTAVAIL;
234
        }
235
        sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr;
236
        if(chk_addr_ret == IS_MULTICAST || chk_addr_ret == IS_BROADCAST)
237
                sk->saddr = 0;  /* Use device */
238
        ip_rt_put(sk->ip_route_cache);
239
        sk->ip_route_cache = NULL;
240
        return 0;
241
}
242
 
243
/*
244
 *      This should be the easiest of all, all we do is
245
 *      copy it into a buffer. All demultiplexing is done
246
 *      in ip.c
247
 */
248
 
249
int raw_rcv(struct sock *sk, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr)
250
{
251
        /* Now we need to copy this into memory. */
252
        skb->sk = sk;
253
        skb_trim(skb,ntohs(skb->ip_hdr->tot_len));
254
 
255
        skb->h.raw = (unsigned char *) skb->ip_hdr;
256
        skb->dev = dev;
257
        skb->saddr = daddr;
258
        skb->daddr = saddr;
259
 
260
#if 0   
261
        /*
262
         *      For no adequately explained reasons BSD likes to mess up the header of
263
         *      the received frame.
264
         */
265
 
266
        if(sk->bsdism)
267
                skb->ip_hdr->tot_len=ntohs(skb->ip_hdr->tot_len-4*skb->ip_hdr->ihl);
268
#endif
269
 
270
        if (sk->users) {
271
                __skb_queue_tail(&sk->back_log, skb);
272
                return 0;
273
        }
274
        raw_rcv_skb(sk, skb);
275
        return 0;
276
}
277
 
278
/*
279
 *      Send a RAW IP packet.
280
 */
281
 
282
/*
283
 *      Callback support is trivial for SOCK_RAW
284
 */
285
 
286
static void raw_getfrag(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen)
287
{
288
        memcpy_fromfs(to, (const unsigned char *)p+offset, fraglen);
289
}
290
 
291
/*
292
 *      IPPROTO_RAW needs extra work.
293
 */
294
 
295
static void raw_getrawfrag(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen)
296
{
297
        memcpy_fromfs(to, (const unsigned char *)p+offset, fraglen);
298
        if(offset==0)
299
        {
300
                struct iphdr *iph=(struct iphdr *)to;
301
                if(!iph->saddr)
302
                        iph->saddr=saddr;
303
                iph->check=0;
304
                iph->tot_len=htons(fraglen);    /* This is right as you can't frag
305
                                           RAW packets */
306
                /*
307
                 *      Deliberate breach of modularity to keep
308
                 *      ip_build_xmit clean (well less messy).
309
                 */
310
                if (!iph->id)
311
                        iph->id = htons(ip_id_count++);
312
                iph->check=ip_fast_csum((unsigned char *)iph, iph->ihl);
313
        }
314
}
315
 
316
static int raw_sendto(struct sock *sk, const unsigned char *from,
317
        int len, int noblock, unsigned flags, struct sockaddr_in *usin, int addr_len)
318
{
319
        int err;
320
        struct sockaddr_in sin;
321
 
322
        /*
323
         *      Check the flags. Only MSG_DONTROUTE is permitted.
324
         */
325
 
326
        if (flags & MSG_OOB)            /* Mirror BSD error message compatibility */
327
                return -EOPNOTSUPP;
328
 
329
        if (flags & ~MSG_DONTROUTE)
330
                return(-EINVAL);
331
        /*
332
         *      Get and verify the address.
333
         */
334
 
335
        if (usin)
336
        {
337
                if (addr_len < sizeof(sin))
338
                        return(-EINVAL);
339
                memcpy(&sin, usin, sizeof(sin));
340
                if (sin.sin_family && sin.sin_family != AF_INET)
341
                        return(-EINVAL);
342
                /*
343
                 *      Protocol type is host ordered byte.
344
                 */
345
                sin.sin_port=ntohs(sin.sin_port);
346
        }
347
        else
348
        {
349
                if (sk->state != TCP_ESTABLISHED)
350
                        return(-EINVAL);
351
                sin.sin_family = AF_INET;
352
                sin.sin_port = sk->num;
353
                sin.sin_addr.s_addr = sk->daddr;
354
        }
355
        if (sin.sin_port == 0)
356
                sin.sin_port = sk->num;
357
 
358
        if (sin.sin_addr.s_addr == INADDR_ANY)
359
                sin.sin_addr.s_addr = ip_my_addr();
360
 
361
        /*
362
         *      BSD raw sockets forget to check SO_BROADCAST ....
363
         */
364
 
365
        if (!sk->bsdism && sk->broadcast == 0 && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
366
                return -EACCES;
367
 
368
        if(sk->ip_hdrincl)
369
        {
370
                if(len>65535)
371
                        return -EMSGSIZE;
372
                err=ip_build_xmit(sk, raw_getrawfrag, from, len, sin.sin_addr.s_addr, 0, sk->opt, flags, sin.sin_port, noblock);
373
        }
374
        else
375
        {
376
                if(len>65535-sizeof(struct iphdr))
377
                        return -EMSGSIZE;
378
                err=ip_build_xmit(sk, raw_getfrag, from, len, sin.sin_addr.s_addr, 0, sk->opt, flags, sin.sin_port, noblock);
379
        }
380
        return err<0?err:len;
381
}
382
 
383
/*
384
 *      Temporary
385
 */
386
 
387
static int raw_sendmsg(struct sock *sk, struct msghdr *msg, int len, int noblock,
388
        int flags)
389
{
390
        if(msg->msg_iovlen==1)
391
                return raw_sendto(sk,msg->msg_iov[0].iov_base,len, noblock, flags, msg->msg_name, msg->msg_namelen);
392
        else
393
        {
394
                /*
395
                 *      For awkward cases we linearise the buffer first. In theory this is only frames
396
                 *      whose iovec's don't split on 4 byte boundaries, and soon encrypted stuff (to keep
397
                 *      skip happy). We are a bit more general about it.
398
                 */
399
 
400
                unsigned char *buf;
401
                int fs;
402
                int err;
403
                if(len>65515)
404
                        return -EMSGSIZE;
405
                buf=kmalloc(len, GFP_KERNEL);
406
                if(buf==NULL)
407
                        return -ENOBUFS;
408
                memcpy_fromiovec(buf, msg->msg_iov, len);
409
                fs=get_fs();
410
                set_fs(get_ds());
411
                err=raw_sendto(sk,buf,len, noblock, flags, msg->msg_name, msg->msg_namelen);
412
                set_fs(fs);
413
                kfree_s(buf,len);
414
                return err;
415
        }
416
}
417
 
418
static void raw_close(struct sock *sk, unsigned long timeout)
419
{
420
        sk->state = TCP_CLOSE;
421
#ifdef CONFIG_IP_MROUTE 
422
        if(sk==mroute_socket)
423
        {
424
                mroute_close(sk);
425
                mroute_socket=NULL;
426
        }
427
#endif  
428
        sk->dead=1;
429
        destroy_sock(sk);
430
}
431
 
432
 
433
static int raw_init(struct sock *sk)
434
{
435
        return(0);
436
}
437
 
438
 
439
/*
440
 *      This should be easy, if there is something there
441
 *      we return it, otherwise we block.
442
 */
443
 
444
int raw_recvmsg(struct sock *sk, struct msghdr *msg, int len,
445
     int noblock, int flags,int *addr_len)
446
{
447
        int copied=0;
448
        struct sk_buff *skb;
449
        int err;
450
        struct sockaddr_in *sin=(struct sockaddr_in *)msg->msg_name;
451
 
452
        if (flags & MSG_OOB)
453
                return -EOPNOTSUPP;
454
 
455
        if (sk->shutdown & RCV_SHUTDOWN)
456
                return(0);
457
 
458
        if (addr_len)
459
                *addr_len=sizeof(*sin);
460
 
461
        skb=skb_recv_datagram(sk,flags,noblock,&err);
462
        if(skb==NULL)
463
                return err;
464
 
465
        copied = min(len, skb->len);
466
 
467
        skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
468
        sk->stamp=skb->stamp;
469
 
470
        /* Copy the address. */
471
        if (sin)
472
        {
473
                sin->sin_family = AF_INET;
474
                sin->sin_addr.s_addr = skb->daddr;
475
        }
476
        skb_free_datagram(sk, skb);
477
        return (copied);
478
}
479
 
480
 
481
struct proto raw_prot = {
482
        (struct sock *)&raw_prot,       /* sklist_next */
483
        (struct sock *)&raw_prot,       /* sklist_prev */
484
        raw_close,                      /* close */
485
        ip_build_header,                /* build_header */
486
        udp_connect,                    /* connect */
487
        NULL,                           /* accept */
488
        ip_queue_xmit,                  /* queue_xmit */
489
        NULL,                           /* retransmit */
490
        NULL,                           /* write_wakeup */
491
        NULL,                           /* read_wakeup */
492
        raw_rcv_redo,                   /* rcv */
493
        datagram_select,                /* select */
494
#ifdef CONFIG_IP_MROUTE 
495
        ipmr_ioctl,                     /* ioctl */
496
#else
497
        NULL,                           /* ioctl */
498
#endif          
499
        raw_init,                       /* init */
500
        NULL,                           /* shutdown */
501
        ip_setsockopt,                  /* setsockopt */
502
        ip_getsockopt,                  /* getsockopt */
503
        raw_sendmsg,                    /* sendmsg */
504
        raw_recvmsg,                    /* recvmsg */
505
        raw_bind,                       /* bind */
506
        raw_v4_hash,                    /* hash */
507
        raw_v4_unhash,                  /* unhash */
508
        raw_v4_rehash,                  /* rehash */
509
        NULL,                           /* good_socknum */
510
        NULL,                           /* verify_bind */
511
        128,                            /* max_header */
512
        0,                               /* retransmits */
513
        "RAW",                          /* name */
514
        0,                               /* inuse */
515
 
516
};

powered by: WebSVN 2.1.0

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