root/net/inet/raw.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. min
  2. raw_err
  3. raw_rcv
  4. raw_sendto
  5. raw_write
  6. raw_close
  7. raw_init
  8. raw_recvfrom
  9. raw_read

   1 /*
   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  *
  29  *              This program is free software; you can redistribute it and/or
  30  *              modify it under the terms of the GNU General Public License
  31  *              as published by the Free Software Foundation; either version
  32  *              2 of the License, or (at your option) any later version.
  33  */
  34 #include <asm/system.h>
  35 #include <asm/segment.h>
  36 #include <linux/types.h>
  37 #include <linux/sched.h>
  38 #include <linux/errno.h>
  39 #include <linux/timer.h>
  40 #include <linux/mm.h>
  41 #include <linux/kernel.h>
  42 #include <linux/fcntl.h>
  43 #include <linux/socket.h>
  44 #include <linux/in.h>
  45 #include <linux/inet.h>
  46 #include <linux/netdevice.h>
  47 #include "ip.h"
  48 #include "protocol.h"
  49 #include <linux/skbuff.h>
  50 #include "sock.h"
  51 #include "icmp.h"
  52 #include "udp.h"
  53 
  54 
  55 static inline unsigned long min(unsigned long a, unsigned long b)
     /* [previous][next][first][last][top][bottom][index][help] */
  56 {
  57         if (a < b) 
  58                 return(a);
  59         return(b);
  60 }
  61 
  62 
  63 /* raw_err gets called by the icmp module. */
  64 void raw_err (int err, unsigned char *header, unsigned long daddr,
     /* [previous][next][first][last][top][bottom][index][help] */
  65          unsigned long saddr, struct inet_protocol *protocol)
  66 {
  67         struct sock *sk;
  68    
  69         if (protocol == NULL) 
  70                 return;
  71         sk = (struct sock *) protocol->data;
  72         if (sk == NULL) 
  73                 return;
  74 
  75         /* This is meaningless in raw sockets. */
  76         if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8)) 
  77         {
  78                 if (sk->cong_window > 1) sk->cong_window = sk->cong_window/2;
  79                 return;
  80         }
  81 
  82         sk->err = icmp_err_convert[err & 0xff].errno;
  83         sk->error_report(sk);
  84   
  85         return;
  86 }
  87 
  88 
  89 /*
  90  *      This should be the easiest of all, all we do is
  91  *      copy it into a buffer.
  92  */
  93 
  94 int raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
     /* [previous][next][first][last][top][bottom][index][help] */
  95         unsigned long daddr, unsigned short len, unsigned long saddr,
  96         int redo, struct inet_protocol *protocol)
  97 {
  98         struct sock *sk;
  99 
 100         if (skb == NULL)
 101                 return(0);
 102         
 103         if (protocol == NULL) 
 104         {
 105                 kfree_skb(skb, FREE_READ);
 106                 return(0);
 107         }
 108   
 109         sk = (struct sock *) protocol->data;
 110         if (sk == NULL) 
 111         {
 112                 kfree_skb(skb, FREE_READ);
 113                 return(0);
 114         }
 115 
 116         /* Now we need to copy this into memory. */
 117 
 118         skb->sk = sk;
 119         skb->len = len + skb->ip_hdr->ihl*sizeof(long);
 120         skb->h.raw = (unsigned char *) skb->ip_hdr;
 121         skb->dev = dev;
 122         skb->saddr = daddr;
 123         skb->daddr = saddr;
 124 
 125         /* Charge it to the socket. */
 126         
 127         if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) 
 128         {
 129                 ip_statistics.IpInDiscards++;
 130                 skb->sk=NULL;
 131                 kfree_skb(skb, FREE_READ);
 132                 return(0);
 133         }
 134 
 135         sk->rmem_alloc += skb->mem_len;
 136         ip_statistics.IpInDelivers++;
 137         skb_queue_tail(&sk->receive_queue,skb);
 138         sk->data_ready(sk,skb->len);
 139         release_sock(sk);
 140         return(0);
 141 }
 142 
 143 /*
 144  *      Send a RAW IP packet.
 145  */
 146 
 147 static int raw_sendto(struct sock *sk, unsigned char *from, 
     /* [previous][next][first][last][top][bottom][index][help] */
 148         int len, int noblock, unsigned flags, struct sockaddr_in *usin, int addr_len)
 149 {
 150         struct sk_buff *skb;
 151         struct device *dev=NULL;
 152         struct sockaddr_in sin;
 153         int tmp;
 154         int err;
 155 
 156         /*
 157          *      Check the flags. Only MSG_DONTROUTE is permitted.
 158          */
 159          
 160         if (flags&MSG_DONTROUTE)
 161                 return(-EINVAL);
 162         /*
 163          *      Get and verify the address. 
 164          */
 165 
 166         if (usin) 
 167         {
 168                 if (addr_len < sizeof(sin)) 
 169                         return(-EINVAL);
 170                 memcpy(&sin, usin, sizeof(sin));
 171                 if (sin.sin_family && sin.sin_family != AF_INET) 
 172                         return(-EINVAL);
 173         }
 174         else 
 175         {
 176                 if (sk->state != TCP_ESTABLISHED) 
 177                         return(-EINVAL);
 178                 sin.sin_family = AF_INET;
 179                 sin.sin_port = sk->protocol;
 180                 sin.sin_addr.s_addr = sk->daddr;
 181         }
 182         if (sin.sin_port == 0) 
 183                 sin.sin_port = sk->protocol;
 184   
 185         if (sin.sin_addr.s_addr == INADDR_ANY)
 186                 sin.sin_addr.s_addr = ip_my_addr();
 187 
 188         if (sk->broadcast == 0 && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
 189                 return -EACCES;
 190 
 191         sk->inuse = 1;
 192         skb = NULL;
 193         while (skb == NULL) 
 194         {
 195                 if(sk->err!=0)
 196                 {
 197                         err= -sk->err;
 198                         sk->err=0;
 199                         release_sock(sk);
 200                         return(err);
 201                 }
 202         
 203                 skb = sk->prot->wmalloc(sk,
 204                                 len + sk->prot->max_header,
 205                                 0, GFP_KERNEL);
 206                 if (skb == NULL) 
 207                 {
 208                         int tmp;
 209 
 210                         if (noblock) 
 211                                 return(-EAGAIN);
 212                         tmp = sk->wmem_alloc;
 213                         release_sock(sk);
 214                         cli();
 215                         if (tmp <= sk->wmem_alloc) {
 216                                 interruptible_sleep_on(sk->sleep);
 217                                 if (current->signal & ~current->blocked) {
 218                                         sti();
 219                                         return(-ERESTARTSYS);
 220                                 }
 221                         }
 222                         sk->inuse = 1;
 223                         sti();
 224                 }
 225         }
 226         skb->sk = sk;
 227         skb->free = 1;
 228         skb->localroute = sk->localroute | (flags&MSG_DONTROUTE);
 229 
 230         tmp = sk->prot->build_header(skb, sk->saddr, 
 231                                sin.sin_addr.s_addr, &dev,
 232                                sk->protocol, sk->opt, skb->mem_len, sk->ip_tos,sk->ip_ttl);
 233         if (tmp < 0) 
 234         {
 235                 kfree_skb(skb,FREE_WRITE);
 236                 release_sock(sk);
 237                 return(tmp);
 238         }
 239 
 240         memcpy_fromfs(skb->data + tmp, from, len);
 241 
 242         /*
 243          *      If we are using IPPROTO_RAW, we need to fill in the source address in
 244          *      the IP header 
 245          */
 246 
 247         if(sk->protocol==IPPROTO_RAW) 
 248         {
 249                 unsigned char *buff;
 250                 struct iphdr *iph;
 251 
 252                 buff = skb->data;
 253                 buff += tmp;
 254 
 255                 iph = (struct iphdr *)buff;
 256                 iph->saddr = sk->saddr;
 257         }
 258 
 259         skb->len = tmp + len;
 260   
 261         sk->prot->queue_xmit(sk, dev, skb, 1);
 262         release_sock(sk);
 263         return(len);
 264 }
 265 
 266 
 267 static int raw_write(struct sock *sk, unsigned char *buff, int len, int noblock,
     /* [previous][next][first][last][top][bottom][index][help] */
 268            unsigned flags)
 269 {
 270         return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0));
 271 }
 272 
 273 
 274 static void raw_close(struct sock *sk, int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 275 {
 276         sk->inuse = 1;
 277         sk->state = TCP_CLOSE;
 278 
 279         inet_del_protocol((struct inet_protocol *)sk->pair);
 280         kfree_s((void *)sk->pair, sizeof (struct inet_protocol));
 281         sk->pair = NULL;
 282         release_sock(sk);
 283 }
 284 
 285 
 286 static int raw_init(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 287 {
 288         struct inet_protocol *p;
 289 
 290         p = (struct inet_protocol *) kmalloc(sizeof (*p), GFP_KERNEL);
 291         if (p == NULL)
 292                 return(-ENOMEM);
 293 
 294         p->handler = raw_rcv;
 295         p->protocol = sk->protocol;
 296         p->data = (void *)sk;
 297         p->err_handler = raw_err;
 298         p->name="USER";
 299         p->frag_handler = NULL; /* For now */
 300         inet_add_protocol(p);
 301    
 302         /* We need to remember this somewhere. */
 303         sk->pair = (struct sock *)p;
 304 
 305         return(0);
 306 }
 307 
 308 
 309 /*
 310  *      This should be easy, if there is something there
 311  *      we return it, otherwise we block.
 312  */
 313 
 314 int raw_recvfrom(struct sock *sk, unsigned char *to, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 315      int noblock, unsigned flags, struct sockaddr_in *sin,
 316              int *addr_len)
 317 {
 318         int copied=0;
 319         struct sk_buff *skb;
 320         int err;
 321         int truesize;
 322 
 323         if (sk->shutdown & RCV_SHUTDOWN) 
 324                 return(0);
 325 
 326         if (addr_len) 
 327                 *addr_len=sizeof(*sin);
 328 
 329         skb=skb_recv_datagram(sk,flags,noblock,&err);
 330         if(skb==NULL)
 331                 return err;
 332 
 333         truesize=skb->len;
 334         copied = min(len, truesize);
 335   
 336         skb_copy_datagram(skb, 0, to, copied);
 337         sk->stamp=skb->stamp;
 338 
 339         /* Copy the address. */
 340         if (sin) 
 341         {
 342                 sin->sin_family = AF_INET;
 343                 sin->sin_addr.s_addr = skb->daddr;
 344         }
 345         skb_free_datagram(skb);
 346         release_sock(sk);
 347         return (truesize);      /* len not copied. BSD returns the true size of the message so you know a bit fell off! */
 348 }
 349 
 350 
 351 int raw_read (struct sock *sk, unsigned char *buff, int len, int noblock,unsigned flags)
     /* [previous][next][first][last][top][bottom][index][help] */
 352 {
 353         return(raw_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
 354 }
 355 
 356 
 357 struct proto raw_prot = {
 358         sock_wmalloc,
 359         sock_rmalloc,
 360         sock_wfree,
 361         sock_rfree,
 362         sock_rspace,
 363         sock_wspace,
 364         raw_close,
 365         raw_read,
 366         raw_write,
 367         raw_sendto,
 368         raw_recvfrom,
 369         ip_build_header,
 370         udp_connect,
 371         NULL,
 372         ip_queue_xmit,
 373         ip_retransmit,
 374         NULL,
 375         NULL,
 376         raw_rcv,
 377         datagram_select,
 378         NULL,
 379         raw_init,
 380         NULL,
 381         ip_setsockopt,
 382         ip_getsockopt,
 383         128,
 384         0,
 385         {NULL,},
 386         "RAW"
 387 };

/* [previous][next][first][last][top][bottom][index][help] */