home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / net / inet / raw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-11  |  6.7 KB  |  320 lines

  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)
  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,
  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)
  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, 
  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,
  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)
  226. {
  227.     sk->state = TCP_CLOSE;
  228. }
  229.  
  230.  
  231. static int raw_init(struct sock *sk)
  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,
  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)
  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. };
  320.