Import 2.1.15
[davej-history.git] / net / ipv4 / raw.c
blobff7d3c3c4a822183423080433fc50ec0ca61d014
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.
6 * RAW - implementation of IP "raw" sockets.
8 * Version: @(#)raw.c 1.0.4 05/25/93
10 * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
11 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
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 * Alan Cox : Beginnings of mrouted support.
31 * Alan Cox : Added IP_HDRINCL option.
32 * Alan Cox : Skip broadcast check if BSDism set.
34 * This program is free software; you can redistribute it and/or
35 * modify it under the terms of the GNU General Public License
36 * as published by the Free Software Foundation; either version
37 * 2 of the License, or (at your option) any later version.
40 #include <linux/config.h>
41 #include <asm/system.h>
42 #include <asm/uaccess.h>
43 #include <linux/types.h>
44 #include <linux/sched.h>
45 #include <linux/errno.h>
46 #include <linux/timer.h>
47 #include <linux/mm.h>
48 #include <linux/kernel.h>
49 #include <linux/fcntl.h>
50 #include <linux/socket.h>
51 #include <linux/in.h>
52 #include <linux/inet.h>
53 #include <linux/netdevice.h>
54 #include <linux/mroute.h>
55 #include <net/ip.h>
56 #include <net/protocol.h>
57 #include <linux/skbuff.h>
58 #include <net/sock.h>
59 #include <net/icmp.h>
60 #include <net/udp.h>
61 #include <net/checksum.h>
63 #ifdef CONFIG_IP_MROUTE
64 struct sock *mroute_socket=NULL;
65 #endif
68 * Raw_err does not currently get called by the icmp module - FIXME:
71 voidraw_err(struct sock *sk,struct sk_buff *skb)
73 int type = skb->h.icmph->type;
74 int code = skb->h.icmph->code;
76 if(sk->ip_recverr && !sk->users) {
77 struct sk_buff *skb2 =skb_clone(skb, GFP_ATOMIC);
78 if(skb2 &&sock_queue_err_skb(sk, skb2))
79 kfree_skb(skb, FREE_READ);
82 if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
83 if(sk->ip_pmtudisc != IP_PMTUDISC_DONT) {
84 sk->err = EMSGSIZE;
85 sk->error_report(sk);
90 static intraw_rcv_skb(struct sock * sk,struct sk_buff * skb)
92 /* Charge it to the socket. */
94 if(__sock_queue_rcv_skb(sk,skb)<0)
96 ip_statistics.IpInDiscards++;
97 kfree_skb(skb, FREE_READ);
98 return-1;
101 ip_statistics.IpInDelivers++;
102 return0;
106 * This should be the easiest of all, all we do is
107 * copy it into a buffer. All demultiplexing is done
108 * in ip.c
111 intraw_rcv(struct sock *sk,struct sk_buff *skb)
113 /* Now we need to copy this into memory. */
114 skb_trim(skb,ntohs(skb->nh.iph->tot_len));
116 skb->h.raw = skb->nh.raw;
118 if(sk->users) {
119 __skb_queue_tail(&sk->back_log, skb);
120 return0;
122 raw_rcv_skb(sk, skb);
123 return0;
126 struct rawfakehdr
128 const char*from;
129 u32 saddr;
133 * Send a RAW IP packet.
137 * Callback support is trivial for SOCK_RAW
140 static intraw_getfrag(const void*p,char*to,unsigned int offset,unsigned int fraglen)
142 struct rawfakehdr *rfh = (struct rawfakehdr*)p;
143 returncopy_from_user(to, (const unsigned char*)rfh->from+offset, fraglen);
147 * IPPROTO_RAW needs extra work.
150 static intraw_getrawfrag(const void*p,char*to,unsigned int offset,unsigned int fraglen)
152 struct rawfakehdr *rfh = (struct rawfakehdr*)p;
153 int err;
154 err =copy_from_user(to, (const unsigned char*)p+offset, fraglen);
155 if(err)
156 return err;
157 if(offset==0) {
158 struct iphdr *iph = (struct iphdr *)to;
159 if(!iph->saddr)
160 iph->saddr = rfh->saddr;
161 iph->check=0;
162 iph->tot_len=htons(fraglen);/* This is right as you can't frag
163 RAW packets */
165 * Deliberate breach of modularity to keep
166 * ip_build_xmit clean (well less messy).
168 if(!iph->id)
169 iph->id =htons(ip_id_count++);
170 iph->check=ip_fast_csum((unsigned char*)iph, iph->ihl);
172 return0;
175 static intraw_sendto(struct sock *sk,const unsigned char*from,
176 int len,struct msghdr *msg)
178 struct device *dev = NULL;
179 struct ipcm_cookie ipc;
180 struct rawfakehdr rfh;
181 struct rtable *rt;
182 int free =0;
183 u32 daddr;
184 u8 tos;
185 int err;
187 if(len>65535)
188 return-EMSGSIZE;
191 * Check the flags.
194 if(msg->msg_flags & MSG_OOB)/* Mirror BSD error message compatibility */
195 return-EOPNOTSUPP;
197 if(msg->msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT))
198 return(-EINVAL);
201 * Get and verify the address.
204 if(msg->msg_namelen) {
205 struct sockaddr_in *usin = (struct sockaddr_in*)msg->msg_name;
206 if(msg->msg_namelen <sizeof(*usin))
207 return(-EINVAL);
208 if(usin->sin_family != AF_INET) {
209 static int complained;
210 if(!complained++)
211 printk("%s forgot to set AF_INET in raw sendmsg. Fix it!\n", current->comm);
212 if(usin->sin_family)
213 return-EINVAL;
215 daddr = usin->sin_addr.s_addr;
216 /* ANK: I did not forget to get protocol from port field.
217 * I just do not know, who uses this weirdness.
218 * IP_HDRINCL is much more convenient.
220 }else{
221 if(sk->state != TCP_ESTABLISHED)
222 return(-EINVAL);
223 daddr = sk->daddr;
226 ipc.addr = sk->saddr;
227 ipc.opt = NULL;
229 if(msg->msg_controllen) {
230 int tmp =ip_cmsg_send(msg, &ipc, &dev);
231 if(tmp)
232 return tmp;
233 if(ipc.opt && sk->ip_hdrincl) {
234 kfree(ipc.opt);
235 return-EINVAL;
237 if(ipc.opt)
238 free=1;
241 rfh.saddr = ipc.addr;
242 ipc.addr = daddr;
244 if(!ipc.opt)
245 ipc.opt = sk->opt;
246 if(ipc.opt && ipc.opt->srr) {
247 if(!daddr)
248 return-EINVAL;
249 daddr = ipc.opt->faddr;
251 tos =RT_TOS(sk->ip_tos) | (sk->localroute || (msg->msg_flags&MSG_DONTROUTE));
253 if(MULTICAST(daddr) && sk->ip_mc_name[0] && dev==NULL)
254 err =ip_route_output_dev(&rt, daddr, rfh.saddr, tos, sk->ip_mc_name);
255 else
256 err =ip_route_output(&rt, daddr, rfh.saddr, tos, dev);
258 if(err) {
259 if(free)kfree(ipc.opt);
260 return err;
263 if(rt->rt_flags&RTF_BROADCAST && !sk->broadcast) {
264 if(free)kfree(ipc.opt);
265 ip_rt_put(rt);
266 return-EACCES;
269 rfh.from = from;
270 rfh.saddr = rt->rt_src;
271 if(!ipc.addr)
272 ipc.addr = rt->rt_dst;
273 if(sk->ip_hdrincl)
274 err=ip_build_xmit(sk, raw_getrawfrag, &rfh, len, &ipc, rt, msg->msg_flags);
275 else{
276 if(len>65535-sizeof(struct iphdr))
277 err = -EMSGSIZE;
278 else
279 err=ip_build_xmit(sk, raw_getfrag, &rfh, len, &ipc, rt, msg->msg_flags);
282 if(free)
283 kfree(ipc.opt);
284 ip_rt_put(rt);
286 return err<0? err : len;
290 * Temporary
293 static intraw_sendmsg(struct sock *sk,struct msghdr *msg,int len)
295 if(msg->msg_iovlen==1)
296 returnraw_sendto(sk, msg->msg_iov[0].iov_base,len, msg);
297 else{
299 * For awkward cases we linearise the buffer first. In theory this is only frames
300 * whose iovec's don't split on 4 byte boundaries, and soon encrypted stuff (to keep
301 * skip happy). We are a bit more general about it.
304 unsigned char*buf;
305 int err;
306 if(len>65515)
307 return-EMSGSIZE;
308 buf=kmalloc(len, GFP_KERNEL);
309 if(buf==NULL)
310 return-ENOBUFS;
311 err =memcpy_fromiovec(buf, msg->msg_iov, len);
312 if(!err)
314 unsigned short fs;
315 fs=get_fs();
316 set_fs(get_ds());
317 err=raw_sendto(sk,buf,len, msg);
318 set_fs(fs);
320 else
321 err = -EFAULT;
323 kfree_s(buf,len);
324 return err;
328 static voidraw_close(struct sock *sk,unsigned long timeout)
330 sk->state = TCP_CLOSE;
331 #ifdef CONFIG_IP_MROUTE
332 if(sk==mroute_socket)
334 ipv4_config.multicast_route =0;
335 mroute_close(sk);
336 mroute_socket=NULL;
338 #endif
339 sk->dead=1;
340 destroy_sock(sk);
344 static intraw_init(struct sock *sk)
346 return(0);
351 * This should be easy, if there is something there
352 * we return it, otherwise we block.
355 intraw_recvmsg(struct sock *sk,struct msghdr *msg,int len,
356 int noblock,int flags,int*addr_len)
358 int copied=0;
359 struct sk_buff *skb;
360 int err;
361 struct sockaddr_in *sin=(struct sockaddr_in *)msg->msg_name;
363 if(flags & MSG_OOB)
364 return-EOPNOTSUPP;
366 if(sk->shutdown & RCV_SHUTDOWN)
367 return(0);
369 if(addr_len)
370 *addr_len=sizeof(*sin);
372 if(sk->ip_recverr && (skb =skb_dequeue(&sk->error_queue)) != NULL) {
373 err =sock_error(sk);
374 if(msg->msg_controllen ==0) {
375 skb_free_datagram(sk, skb);
376 return err;
378 put_cmsg(msg, SOL_IP, IP_RECVERR, skb->len, skb->data);
379 skb_free_datagram(sk, skb);
380 return0;
383 skb=skb_recv_datagram(sk,flags,noblock,&err);
384 if(skb==NULL)
385 return err;
387 copied = skb->len;
388 if(len < copied)
390 msg->msg_flags |= MSG_TRUNC;
391 copied = len;
394 err =skb_copy_datagram_iovec(skb,0, msg->msg_iov, copied);
395 sk->stamp=skb->stamp;
397 /* Copy the address. */
398 if(sin) {
399 sin->sin_family = AF_INET;
400 sin->sin_addr.s_addr = skb->nh.iph->saddr;
402 if(sk->ip_cmsg_flags)
403 ip_cmsg_recv(msg, skb);
404 skb_free_datagram(sk, skb);
405 return err ? err : (copied);
409 struct proto raw_prot = {
410 raw_close,
411 udp_connect,
412 NULL,
413 NULL,
414 NULL,
415 NULL,
416 datagram_select,
417 #ifdef CONFIG_IP_MROUTE
418 ipmr_ioctl,
419 #else
420 NULL,
421 #endif
422 raw_init,
423 NULL,
424 NULL,
425 ip_setsockopt,
426 ip_getsockopt,
427 raw_sendmsg,
428 raw_recvmsg,
429 NULL,/* No special bind */
430 raw_rcv_skb,
431 128,
433 "RAW",
434 0,0,
435 NULL
close