⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 packet.c

📁 An implementation of the TCP/IP protocol suite for the LINUX operating system. INET is implemented u
💻 C
字号:
  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  *              PACKET - implements raw packet sockets.
  7  *
  8  * Version:     @(#)packet.c    1.0.6   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() now used correctly
 15  *              Alan Cox        :       new skbuff lists, look ma no backlogs!
 16  *              Alan Cox        :       tidied skbuff lists.
 17  *              Alan Cox        :       Now uses generic datagram routines I
 18  *                                      added. Also fixed the peek/read crash
 19  *                                      from all old Linux datagram code.
 20  *              Alan Cox        :       Uses the improved datagram code.
 21  *              Alan Cox        :       Added NULL's for socket options.
 22  *
 23  *
 24  *              This program is free software; you can redistribute it and/or
 25  *              modify it under the terms of the GNU General Public License
 26  *              as published by the Free Software Foundation; either version
 27  *              2 of the License, or (at your option) any later version.
 28  */
 29 #include <linux/types.h>
 30 #include <linux/sched.h>
 31 #include <linux/fcntl.h>
 32 #include <linux/socket.h>
 33 #include <linux/in.h>
 34 #include "inet.h"
 35 #include "dev.h"
 36 #include "ip.h"
 37 #include "protocol.h"
 38 #include "tcp.h"
 39 #include "skbuff.h"
 40 #include "sock.h"
 41 #include <linux/errno.h>
 42 #include <linux/timer.h>
 43 #include <asm/system.h>
 44 #include <asm/segment.h>
 45 #include "udp.h"
 46 #include "raw.h"
 47 
 48 
 49 static unsigned long
 50 min(unsigned long a, unsigned long b)
 51 {
 52   if (a < b) return(a);
 53   return(b);
 54 }
 55 
 56 
 57 /* This should be the easiest of all, all we do is copy it into a buffer. */
 58 int
 59 packet_rcv(struct sk_buff *skb, struct device *dev,  struct packet_type *pt)
 60 {
 61   struct sock *sk;
 62 
 63   sk = (struct sock *) pt->data;
 64   skb->dev = dev;
 65   skb->len += dev->hard_header_len;
 66 
 67   skb->sk = sk;
 68 
 69   /* Charge it too the socket. */
 70   if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) {
 71         skb->sk = NULL;
 72         kfree_skb(skb, FREE_READ);
 73         return(0);
 74   }
 75   sk->rmem_alloc += skb->mem_len;
 76   skb_queue_tail(&sk->rqueue,skb);
 77   wake_up_interruptible(sk->sleep);
 78   release_sock(sk);
 79   return(0);
 80 }
 81 
 82 
 83 /* This will do terrible things if len + ipheader + devheader > dev->mtu */
 84 static int
 85 packet_sendto(struct sock *sk, unsigned char *from, int len,
 86               int noblock, unsigned flags, struct sockaddr_in *usin,
 87               int addr_len)
 88 {
 89   struct sk_buff *skb;
 90   struct device *dev;
 91   struct sockaddr saddr;
 92   int err;
 93 
 94   /* Check the flags. */
 95   if (flags) return(-EINVAL);
 96   if (len < 0) return(-EINVAL);
 97 
 98   /* Get and verify the address. */
 99   if (usin) {
100         if (addr_len < sizeof(saddr)) return(-EINVAL);
101         err=verify_area(VERIFY_READ, usin, sizeof(saddr));
102         if(err)
103                 return err;
104         memcpy_fromfs(&saddr, usin, sizeof(saddr));
105   } else
106         return(-EINVAL);
107         
108   err=verify_area(VERIFY_READ,from,len);
109   if(err)
110         return(err);
111 /* Find the device first to size check it */
112 
113   saddr.sa_data[13] = 0;
114   dev = dev_get(saddr.sa_data);
115   if (dev == NULL) {
116         return(-ENXIO);
117   }
118   if(len>dev->mtu)
119         return -EMSGSIZE;
120 
121 /* Now allocate the buffer, knowing 4K pagelimits wont break this line */  
122   skb = sk->prot->wmalloc(sk, len+sizeof(*skb), 0, GFP_KERNEL);
123 
124   /* This shouldn't happen, but it could. */
125   if (skb == NULL) {
126         DPRINTF((DBG_PKT, "packet_sendto: write buffer full?\n"));
127         return(-ENOMEM);
128   }
129   /* Fill it in */
130   skb->mem_addr = skb;
131   skb->mem_len = len + sizeof(*skb);
132   skb->sk = sk;
133   skb->free = 1;
134   memcpy_fromfs(skb->data, from, len);
135   skb->len = len;
136   skb->next = NULL;
137   skb->arp = 1;
138   if (dev->flags & IFF_UP) dev->queue_xmit(skb, dev, sk->priority);
139     else kfree_skb(skb, FREE_WRITE);
140   return(len);
141 }
142 
143 
144 static int
145 packet_write(struct sock *sk, unsigned char *buff, 
146              int len, int noblock,  unsigned flags)
147 {
148   return(packet_sendto(sk, buff, len, noblock, flags, NULL, 0));
149 }
150 
151 
152 static void
153 packet_close(struct sock *sk, int timeout)
154 {
155   sk->inuse = 1;
156   sk->state = TCP_CLOSE;
157   dev_remove_pack((struct packet_type *)sk->pair);
158   kfree_s((void *)sk->pair, sizeof(struct packet_type));
159   sk->pair = NULL;
160   release_sock(sk);
161 }
162 
163 
164 static int
165 packet_init(struct sock *sk)
166 {
167   struct packet_type *p;
168 
169   p = (struct packet_type *) kmalloc(sizeof(*p), GFP_KERNEL);
170   if (p == NULL) return(-ENOMEM);
171 
172   p->func = packet_rcv;
173   p->type = sk->num;
174   p->data = (void *)sk;
175   dev_add_pack(p);
176    
177   /* We need to remember this somewhere. */
178   sk->pair = (struct sock *)p;
179 
180   return(0);
181 }
182 
183 
184 /*
185  * This should be easy, if there is something there
186  * we return it, otherwise we block.
187  */
188 int
189 packet_recvfrom(struct sock *sk, unsigned char *to, int len,
190                 int noblock, unsigned flags, struct sockaddr_in *sin,
191                 int *addr_len)
192 {
193   int copied=0;
194   struct sk_buff *skb;
195   struct sockaddr *saddr;
196   int err;
197 
198   saddr = (struct sockaddr *)sin;
199   if (len == 0) return(0);
200   if (len < 0) return(-EINVAL);
201 
202   if (sk->shutdown & RCV_SHUTDOWN) return(0);
203   if (addr_len) {
204           err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
205           if(err)
206                 return err;
207           put_fs_long(sizeof(*saddr), addr_len);
208   }
209   
210   err=verify_area(VERIFY_WRITE,to,len);
211   if(err)
212         return err;
213   skb=skb_recv_datagram(sk,flags,noblock,&err);
214   if(skb==NULL)
215         return err;
216   copied = min(len, skb->len);
217 
218   memcpy_tofs(to, skb->data, copied);   /* Don't use skb_copy_datagram here: We can't get frag chains */
219 
220   /* Copy the address. */
221   if (saddr) {
222         struct sockaddr addr;
223 
224         addr.sa_family = skb->dev->type;
225         memcpy(addr.sa_data,skb->dev->name, 14);
226         verify_area(VERIFY_WRITE, saddr, sizeof(*saddr));
227         memcpy_tofs(saddr, &addr, sizeof(*saddr));
228   }
229 
230   skb_free_datagram(skb);               /* Its either been used up, or its a peek_copy anyway */
231 
232   release_sock(sk);
233   return(copied);
234 }
235 
236 
237 int
238 packet_read(struct sock *sk, unsigned char *buff,
239             int len, int noblock, unsigned flags)
240 {
241   return(packet_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
242 }
243 
244 
245 struct proto packet_prot = {
246   sock_wmalloc,
247   sock_rmalloc,
248   sock_wfree,
249   sock_rfree,
250   sock_rspace,
251   sock_wspace,
252   packet_close,
253   packet_read,
254   packet_write,
255   packet_sendto,
256   packet_recvfrom,
257   ip_build_header,
258   udp_connect,
259   NULL,
260   ip_queue_xmit,
261   ip_retransmit,
262   NULL,
263   NULL,
264   NULL, 
265   datagram_select,
266   NULL,
267   packet_init,
268   NULL,
269   NULL, /* No set/get socket options */
270   NULL,
271   128,
272   0,
273   {NULL,},
274   "PACKET"
275 };
276 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -