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

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