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

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