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  *
  27  *              This program is free software; you can redistribute it and/or
  28  *              modify it under the terms of the GNU General Public License
  29  *              as published by the Free Software Foundation; either version
  30  *              2 of the License, or (at your option) any later version.
  31  */
  32 #include <asm/system.h>
  33 #include <asm/segment.h>
  34 #include <linux/types.h>
  35 #include <linux/sched.h>
  36 #include <linux/errno.h>
  37 #include <linux/timer.h>
  38 #include <linux/mm.h>
  39 #include <linux/kernel.h>
  40 #include <linux/fcntl.h>
  41 #include <linux/socket.h>
  42 #include <linux/in.h>
  43 #include "inet.h"
  44 #include "dev.h"
  45 #include "ip.h"
  46 #include "protocol.h"
  47 #include "tcp.h"
  48 #include "skbuff.h"
  49 #include "sock.h"
  50 #include "icmp.h"
  51 #include "udp.h"
  52 
  53 
  54 static unsigned long
  55 min(unsigned long a, unsigned long b)
     /* [previous][next][first][last][top][bottom][index][help] */
  56 {
  57   if (a < b) return(a);
  58   return(b);
  59 }
  60 
  61 
  62 /* raw_err gets called by the icmp module. */
  63 void
  64 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   DPRINTF((DBG_RAW, "raw_err(err=%d, hdr=%X, daddr=%X, saddr=%X, protocl=%X)\n",
  70                 err, header, daddr, saddr, protocol));
  71 
  72   if (protocol == NULL) return;
  73   sk = (struct sock *) protocol->data;
  74   if (sk == NULL) return;
  75 
  76   /* This is meaningless in raw sockets. */
  77   if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8)) {
  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 int
  94 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   DPRINTF((DBG_RAW, "raw_rcv(skb=%X, dev=%X, opt=%X, daddr=%X,\n"
 101            "         len=%d, saddr=%X, redo=%d, protocol=%X)\n",
 102            skb, dev, opt, daddr, len, saddr, redo, protocol));
 103 
 104   if (skb == NULL) return(0);
 105   if (protocol == NULL) {
 106         kfree_skb(skb, FREE_READ);
 107         return(0);
 108   }
 109   sk = (struct sock *) protocol->data;
 110   if (sk == NULL) {
 111         kfree_skb(skb, FREE_READ);
 112         return(0);
 113   }
 114 
 115   /* Now we need to copy this into memory. */
 116   skb->sk = sk;
 117   skb->len = len + skb->ip_hdr->ihl*sizeof(long);
 118   skb->h.raw = skb->ip_hdr;
 119   skb->dev = dev;
 120   skb->saddr = daddr;
 121   skb->daddr = saddr;
 122 
 123   /* Charge it too the socket. */
 124   if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) {
 125         skb->sk = NULL;
 126         kfree_skb(skb, FREE_READ);
 127         return(0);
 128   }
 129   sk->rmem_alloc += skb->mem_len;
 130   skb_queue_tail(&sk->rqueue,skb);
 131   sk->data_ready(sk,skb->len);
 132   release_sock(sk);
 133   return(0);
 134 }
 135 
 136 
 137 /* This will do terrible things if len + ipheader + devheader > dev->mtu */
 138 static int
 139 raw_sendto(struct sock *sk, unsigned char *from, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 140            int noblock,
 141            unsigned flags, struct sockaddr_in *usin, int addr_len)
 142 {
 143   struct sk_buff *skb;
 144   struct device *dev=NULL;
 145   struct sockaddr_in sin;
 146   int tmp;
 147   int err;
 148 
 149   DPRINTF((DBG_RAW, "raw_sendto(sk=%X, from=%X, len=%d, noblock=%d, flags=%X,\n"
 150            "            usin=%X, addr_len = %d)\n", sk, from, len, noblock,
 151            flags, usin, addr_len));
 152 
 153   /* Check the flags. */
 154   if (flags) return(-EINVAL);
 155   if (len < 0) return(-EINVAL);
 156 
 157   err=verify_area(VERIFY_READ,from,len);
 158   if(err)
 159         return err;
 160   /* Get and verify the address. */
 161   if (usin) {
 162         if (addr_len < sizeof(sin)) return(-EINVAL);
 163         err=verify_area (VERIFY_READ, usin, sizeof (sin));
 164         if(err)
 165                 return err;
 166         memcpy_fromfs(&sin, usin, sizeof(sin));
 167         if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL);
 168   } else {
 169         if (sk->state != TCP_ESTABLISHED) return(-EINVAL);
 170         sin.sin_family = AF_INET;
 171         sin.sin_port = sk->protocol;
 172         sin.sin_addr.s_addr = sk->daddr;
 173   }
 174   if (sin.sin_port == 0) sin.sin_port = sk->protocol;
 175   
 176   if (sk->broadcast == 0 && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
 177         return -EACCES;
 178 
 179   sk->inuse = 1;
 180   skb = NULL;
 181   while (skb == NULL) {
 182         if(sk->err!=0)
 183         {
 184                 err= -sk->err;
 185                 sk->err=0;
 186                 release_sock(sk);
 187                 return(err);
 188         }
 189         
 190         skb = sk->prot->wmalloc(sk,
 191                         len+sizeof(*skb) + sk->prot->max_header,
 192                         0, GFP_KERNEL);
 193         if (skb == NULL) {
 194                 int tmp;
 195 
 196                 DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n"));
 197                 if (noblock) 
 198                         return(-EAGAIN);
 199                 tmp = sk->wmem_alloc;
 200                 release_sock(sk);
 201                 cli();
 202                 if (tmp <= sk->wmem_alloc) {
 203                         interruptible_sleep_on(sk->sleep);
 204                         if (current->signal & ~current->blocked) {
 205                                 sti();
 206                                 return(-ERESTARTSYS);
 207                         }
 208                 }
 209                 sk->inuse = 1;
 210                 sti();
 211         }
 212   }
 213   skb->mem_addr = skb;
 214   skb->mem_len = len + sizeof(*skb) +sk->prot->max_header;
 215   skb->sk = sk;
 216 
 217   skb->free = 1; /* these two should be unecessary. */
 218   skb->arp = 0;
 219 
 220   tmp = sk->prot->build_header(skb, sk->saddr, 
 221                                sin.sin_addr.s_addr, &dev,
 222                                sk->protocol, sk->opt, skb->mem_len, sk->ip_tos,sk->ip_ttl);
 223   if (tmp < 0) {
 224         DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n"));
 225         kfree_skb(skb,FREE_WRITE);
 226         release_sock(sk);
 227         return(tmp);
 228   }
 229 
 230   /* verify_area(VERIFY_WRITE, from, len);*/
 231   memcpy_fromfs(skb->data + tmp, from, len);
 232 
 233   /* If we are using IPPROTO_RAW, we need to fill in the source address in
 234      the IP header */
 235 
 236   if(sk->protocol==IPPROTO_RAW) {
 237     unsigned char *buff;
 238     struct iphdr *iph;
 239 
 240     buff = skb->data;
 241     buff += tmp;
 242     iph = (struct iphdr *)buff;
 243     iph->saddr = sk->saddr;
 244   }
 245 
 246   skb->len = tmp + len;
 247   
 248   if(dev!=NULL && skb->len > 4095)
 249   {
 250         kfree_skb(skb, FREE_WRITE);
 251         release_sock(sk);
 252         return(-EMSGSIZE);
 253   }
 254   
 255   sk->prot->queue_xmit(sk, dev, skb, 1);
 256   release_sock(sk);
 257   return(len);
 258 }
 259 
 260 
 261 static int
 262 raw_write(struct sock *sk, unsigned char *buff, int len, int noblock,
     /* [previous][next][first][last][top][bottom][index][help] */
 263            unsigned flags)
 264 {
 265   return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0));
 266 }
 267 
 268 
 269 static void
 270 raw_close(struct sock *sk, int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 271 {
 272   sk->inuse = 1;
 273   sk->state = TCP_CLOSE;
 274 
 275   DPRINTF((DBG_RAW, "raw_close: deleting protocol %d\n",
 276            ((struct inet_protocol *)sk->pair)->protocol));
 277 
 278   if (inet_del_protocol((struct inet_protocol *)sk->pair) < 0)
 279                 DPRINTF((DBG_RAW, "raw_close: del_protocol failed.\n"));
 280   kfree_s((void *)sk->pair, sizeof (struct inet_protocol));
 281   sk->pair = NULL;
 282   release_sock(sk);
 283 }
 284 
 285 
 286 static int
 287 raw_init(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 288 {
 289   struct inet_protocol *p;
 290 
 291   p = (struct inet_protocol *) kmalloc(sizeof (*p), GFP_KERNEL);
 292   if (p == NULL) 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   DPRINTF((DBG_RAW, "raw init added protocol %d\n", sk->protocol));
 306 
 307   return(0);
 308 }
 309 
 310 
 311 /*
 312  * This should be easy, if there is something there
 313  * we return it, otherwise we block.
 314  */
 315 int
 316 raw_recvfrom(struct sock *sk, unsigned char *to, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 317              int noblock, unsigned flags, struct sockaddr_in *sin,
 318              int *addr_len)
 319 {
 320   int copied=0;
 321   struct sk_buff *skb;
 322   int err;
 323 
 324   DPRINTF((DBG_RAW, "raw_recvfrom (sk=%X, to=%X, len=%d, noblock=%d, flags=%X,\n"
 325            "              sin=%X, addr_len=%X)\n",
 326                 sk, to, len, noblock, flags, sin, addr_len));
 327 
 328   if (len == 0) return(0);
 329   if (len < 0) return(-EINVAL);
 330 
 331   if (sk->shutdown & RCV_SHUTDOWN) return(0);
 332   if (addr_len) {
 333         err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
 334         if(err)
 335                 return err;
 336         put_fs_long(sizeof(*sin), addr_len);
 337   }
 338   if(sin)
 339   {
 340         err=verify_area(VERIFY_WRITE, sin, sizeof(*sin));
 341         if(err)
 342                 return err;
 343   }
 344   
 345   err=verify_area(VERIFY_WRITE,to,len);
 346   if(err)
 347         return err;
 348 
 349   skb=skb_recv_datagram(sk,flags,noblock,&err);
 350   if(skb==NULL)
 351         return err;
 352 
 353   copied = min(len, skb->len);
 354   
 355   skb_copy_datagram(skb, 0, to, copied);
 356 
 357   /* Copy the address. */
 358   if (sin) {
 359         struct sockaddr_in addr;
 360 
 361         addr.sin_family = AF_INET;
 362         addr.sin_addr.s_addr = skb->daddr;
 363         memcpy_tofs(sin, &addr, sizeof(*sin));
 364   }
 365 
 366   skb_free_datagram(skb);
 367   release_sock(sk);
 368   return (copied);
 369 }
 370 
 371 
 372 int
 373 raw_read (struct sock *sk, unsigned char *buff, int len, int noblock,
     /* [previous][next][first][last][top][bottom][index][help] */
 374           unsigned flags)
 375 {
 376   return(raw_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
 377 }
 378 
 379 
 380 struct proto raw_prot = {
 381   sock_wmalloc,
 382   sock_rmalloc,
 383   sock_wfree,
 384   sock_rfree,
 385   sock_rspace,
 386   sock_wspace,
 387   raw_close,
 388   raw_read,
 389   raw_write,
 390   raw_sendto,
 391   raw_recvfrom,
 392   ip_build_header,
 393   udp_connect,
 394   NULL,
 395   ip_queue_xmit,
 396   ip_retransmit,
 397   NULL,
 398   NULL,
 399   raw_rcv,
 400   datagram_select,
 401   NULL,
 402   raw_init,
 403   NULL,
 404   ip_setsockopt,
 405   ip_getsockopt,
 406   128,
 407   0,
 408   {NULL,},
 409   "RAW"
 410 };

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