3 * Linux INET6 implementation
6 * Pedro Roque <roque@di.fc.ul.pt>
8 * Adapted from linux/net/ipv4/raw.c
10 * $Id: raw.c,v 1.24 1999/04/22 10:07:45 davem Exp $
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
18 #include <linux/errno.h>
19 #include <linux/types.h>
20 #include <linux/socket.h>
21 #include <linux/sockios.h>
22 #include <linux/sched.h>
23 #include <linux/net.h>
24 #include <linux/in6.h>
25 #include <linux/netdevice.h>
26 #include <linux/if_arp.h>
27 #include <linux/icmpv6.h>
28 #include <asm/uaccess.h>
34 #include <net/ndisc.h>
35 #include <net/protocol.h>
36 #include <net/ip6_route.h>
37 #include <net/addrconf.h>
38 #include <net/transp_v6.h>
40 #include <net/rawv6.h>
42 #include <asm/uaccess.h>
44 struct sock
*raw_v6_htable
[RAWV6_HTABLE_SIZE
];
46 static void raw_v6_hash(struct sock
*sk
)
51 num
&= (RAWV6_HTABLE_SIZE
- 1);
52 skp
= &raw_v6_htable
[num
];
53 SOCKHASH_LOCK_WRITE();
57 SOCKHASH_UNLOCK_WRITE();
60 static void raw_v6_unhash(struct sock
*sk
)
65 num
&= (RAWV6_HTABLE_SIZE
- 1);
66 skp
= &raw_v6_htable
[num
];
68 SOCKHASH_LOCK_WRITE();
74 skp
= &((*skp
)->next
);
76 SOCKHASH_UNLOCK_WRITE();
79 static void raw_v6_rehash(struct sock
*sk
)
83 int oldnum
= sk
->hashent
;
85 num
&= (RAWV6_HTABLE_SIZE
- 1);
86 skp
= &raw_v6_htable
[oldnum
];
88 SOCKHASH_LOCK_WRITE();
94 skp
= &((*skp
)->next
);
96 sk
->next
= raw_v6_htable
[num
];
97 raw_v6_htable
[num
] = sk
;
99 SOCKHASH_UNLOCK_WRITE();
102 static __inline__
int inet6_mc_check(struct sock
*sk
, struct in6_addr
*addr
)
104 struct ipv6_mc_socklist
*mc
;
106 for (mc
= sk
->net_pinfo
.af_inet6
.ipv6_mc_list
; mc
; mc
=mc
->next
) {
107 if (ipv6_addr_cmp(&mc
->addr
, addr
) == 0)
114 /* Grumble... icmp and ip_input want to get at this... */
115 struct sock
*raw_v6_lookup(struct sock
*sk
, unsigned short num
,
116 struct in6_addr
*loc_addr
, struct in6_addr
*rmt_addr
)
119 int addr_type
= ipv6_addr_type(loc_addr
);
121 for(s
= sk
; s
; s
= s
->next
) {
122 if((s
->num
== num
) &&
123 !(s
->dead
&& (s
->state
== TCP_CLOSE
))) {
124 struct ipv6_pinfo
*np
= &s
->net_pinfo
.af_inet6
;
126 if (!ipv6_addr_any(&np
->daddr
) &&
127 ipv6_addr_cmp(&np
->daddr
, rmt_addr
))
130 if (!ipv6_addr_any(&np
->rcv_saddr
)) {
131 if (ipv6_addr_cmp(&np
->rcv_saddr
, loc_addr
) == 0)
133 if ((addr_type
& IPV6_ADDR_MULTICAST
) &&
134 inet6_mc_check(s
, loc_addr
))
144 /* This cleans up af_inet6 a bit. -DaveM */
145 static int rawv6_bind(struct sock
*sk
, struct sockaddr
*uaddr
, int addr_len
)
147 struct sockaddr_in6
*addr
= (struct sockaddr_in6
*) uaddr
;
151 /* Check these errors. */
152 if (sk
->state
!= TCP_CLOSE
|| (addr_len
< sizeof(struct sockaddr_in6
)))
155 addr_type
= ipv6_addr_type(&addr
->sin6_addr
);
157 /* Check if the address belongs to the host. */
158 if (addr_type
== IPV6_ADDR_MAPPED
) {
159 /* Raw sockets are IPv6 only */
160 return(-EADDRNOTAVAIL
);
162 if (addr_type
!= IPV6_ADDR_ANY
) {
163 /* ipv4 addr of the socket is invalid. Only the
164 * unpecified and mapped address have a v4 equivalent.
166 v4addr
= LOOPBACK4_IPV6
;
167 if (!(addr_type
& IPV6_ADDR_MULTICAST
)) {
168 if (ipv6_chk_addr(&addr
->sin6_addr
, NULL
, 0) == NULL
)
169 return(-EADDRNOTAVAIL
);
174 sk
->rcv_saddr
= v4addr
;
176 memcpy(&sk
->net_pinfo
.af_inet6
.rcv_saddr
, &addr
->sin6_addr
,
177 sizeof(struct in6_addr
));
178 if (!(addr_type
& IPV6_ADDR_MULTICAST
))
179 memcpy(&sk
->net_pinfo
.af_inet6
.saddr
, &addr
->sin6_addr
,
180 sizeof(struct in6_addr
));
184 void rawv6_err(struct sock
*sk
, struct sk_buff
*skb
, struct ipv6hdr
*hdr
,
185 struct inet6_skb_parm
*opt
,
186 int type
, int code
, unsigned char *buff
, u32 info
)
191 if (buff
> skb
->tail
)
194 /* Report error on raw socket, if:
195 1. User requested recverr.
196 2. Socket is connected (otherwise the error indication
197 is useless without recverr and error is hard.
199 if (!sk
->net_pinfo
.af_inet6
.recverr
&& sk
->state
!= TCP_ESTABLISHED
)
202 harderr
= icmpv6_err_convert(type
, code
, &err
);
203 if (type
== ICMPV6_PKT_TOOBIG
)
204 harderr
= (sk
->net_pinfo
.af_inet6
.pmtudisc
== IPV6_PMTUDISC_DO
);
206 if (sk
->net_pinfo
.af_inet6
.recverr
)
207 ipv6_icmp_error(sk
, skb
, err
, 0, ntohl(info
), buff
);
209 if (sk
->net_pinfo
.af_inet6
.recverr
|| harderr
) {
211 sk
->error_report(sk
);
215 static inline int rawv6_rcv_skb(struct sock
* sk
, struct sk_buff
* skb
)
217 /* Charge it to the socket. */
218 if (sock_queue_rcv_skb(sk
,skb
)<0) {
219 ipv6_statistics
.Ip6InDiscards
++;
224 ipv6_statistics
.Ip6InDelivers
++;
229 * This is next to useless...
230 * if we demultiplex in network layer we don't need the extra call
231 * just to queue the skb...
232 * maybe we could have the network decide uppon a hint if it
233 * should call raw_rcv for demultiplexing
235 int rawv6_rcv(struct sock
*sk
, struct sk_buff
*skb
, unsigned long len
)
238 skb
->h
.raw
= skb
->nh
.raw
;
240 rawv6_rcv_skb(sk
, skb
);
246 * This should be easy, if there is something there
247 * we return it, otherwise we block.
250 int rawv6_recvmsg(struct sock
*sk
, struct msghdr
*msg
, int len
,
251 int noblock
, int flags
, int *addr_len
)
253 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)msg
->msg_name
;
261 *addr_len
=sizeof(*sin6
);
263 if (flags
& MSG_ERRQUEUE
)
264 return ipv6_recv_error(sk
, msg
, len
);
266 skb
= skb_recv_datagram(sk
, flags
, noblock
, &err
);
270 copied
= skb
->tail
- skb
->h
.raw
;
273 msg
->msg_flags
|= MSG_TRUNC
;
276 err
= skb_copy_datagram_iovec(skb
, 0, msg
->msg_iov
, copied
);
277 sk
->stamp
=skb
->stamp
;
281 /* Copy the address. */
283 sin6
->sin6_family
= AF_INET6
;
284 memcpy(&sin6
->sin6_addr
, &skb
->nh
.ipv6h
->saddr
,
285 sizeof(struct in6_addr
));
286 sin6
->sin6_flowinfo
= 0;
289 if (sk
->net_pinfo
.af_inet6
.rxopt
.all
)
290 datagram_recv_ctl(sk
, msg
, skb
);
294 skb_free_datagram(sk
, skb
);
303 struct rawv6_fakehdr
{
309 struct in6_addr
*daddr
;
312 static int rawv6_getfrag(const void *data
, struct in6_addr
*saddr
,
313 char *buff
, unsigned int offset
, unsigned int len
)
315 struct iovec
*iov
= (struct iovec
*) data
;
317 return memcpy_fromiovecend(buff
, iov
, offset
, len
);
320 static int rawv6_frag_cksum(const void *data
, struct in6_addr
*addr
,
321 char *buff
, unsigned int offset
,
324 struct rawv6_fakehdr
*hdr
= (struct rawv6_fakehdr
*) data
;
326 if (csum_partial_copy_fromiovecend(buff
, hdr
->iov
, offset
,
332 struct raw6_opt
*opt
;
333 struct in6_addr
*daddr
;
336 opt
= &sk
->tp_pinfo
.tp_raw
;
343 hdr
->cksum
= csum_ipv6_magic(addr
, daddr
, hdr
->len
,
344 hdr
->proto
, hdr
->cksum
);
346 if (opt
->offset
< len
) {
349 csum
= (__u16
*) (buff
+ opt
->offset
);
353 printk(KERN_DEBUG
"icmp: cksum offset too big\n");
361 static int rawv6_sendmsg(struct sock
*sk
, struct msghdr
*msg
, int len
)
363 struct ipv6_txoptions opt_space
;
364 struct sockaddr_in6
* sin6
= (struct sockaddr_in6
*) msg
->msg_name
;
365 struct ipv6_pinfo
*np
= &sk
->net_pinfo
.af_inet6
;
366 struct ipv6_txoptions
*opt
= NULL
;
367 struct ip6_flowlabel
*flowlabel
= NULL
;
369 int addr_len
= msg
->msg_namelen
;
370 struct in6_addr
*daddr
;
371 struct raw6_opt
*raw_opt
;
376 /* Rough check on arithmetic overflow,
377 better check is made in ip6_build_xmit
382 /* Mirror BSD error message compatibility */
383 if (msg
->msg_flags
& MSG_OOB
)
386 if (msg
->msg_flags
& ~(MSG_DONTROUTE
|MSG_DONTWAIT
))
389 * Get and verify the address.
392 fl
.fl6_flowlabel
= 0;
395 if (addr_len
< sizeof(struct sockaddr_in6
))
398 if (sin6
->sin6_family
&& sin6
->sin6_family
!= AF_INET6
)
401 /* port is the proto value [0..255] carried in nexthdr */
402 proto
= ntohs(sin6
->sin6_port
);
410 daddr
= &sin6
->sin6_addr
;
412 fl
.fl6_flowlabel
= sin6
->sin6_flowinfo
&IPV6_FLOWINFO_MASK
;
413 if (fl
.fl6_flowlabel
&IPV6_FLOWLABEL_MASK
) {
414 flowlabel
= fl6_sock_lookup(sk
, fl
.fl6_flowlabel
);
415 if (flowlabel
== NULL
)
417 daddr
= &flowlabel
->dst
;
422 /* Otherwise it will be difficult to maintain sk->dst_cache. */
423 if (sk
->state
== TCP_ESTABLISHED
&&
424 !ipv6_addr_cmp(daddr
, &sk
->net_pinfo
.af_inet6
.daddr
))
425 daddr
= &sk
->net_pinfo
.af_inet6
.daddr
;
427 if (sk
->state
!= TCP_ESTABLISHED
)
431 daddr
= &(sk
->net_pinfo
.af_inet6
.daddr
);
432 fl
.fl6_flowlabel
= np
->flow_label
;
435 if (ipv6_addr_any(daddr
)) {
437 * unspecfied destination address
438 * treated as error... is this correct ?
443 fl
.oif
= sk
->bound_dev_if
;
446 if (msg
->msg_controllen
) {
448 memset(opt
, 0, sizeof(struct ipv6_txoptions
));
450 err
= datagram_send_ctl(msg
, &fl
, opt
, &hlimit
);
452 fl6_sock_release(flowlabel
);
455 if ((fl
.fl6_flowlabel
&IPV6_FLOWLABEL_MASK
) && !flowlabel
) {
456 flowlabel
= fl6_sock_lookup(sk
, fl
.fl6_flowlabel
);
457 if (flowlabel
== NULL
)
460 if (!(opt
->opt_nflen
|opt
->opt_flen
))
466 opt
= fl6_merge_options(&opt_space
, flowlabel
, opt
);
468 raw_opt
= &sk
->tp_pinfo
.tp_raw
;
472 fl
.uli_u
.icmpt
.type
= 0;
473 fl
.uli_u
.icmpt
.code
= 0;
475 if (raw_opt
->checksum
) {
476 struct rawv6_fakehdr hdr
;
478 hdr
.iov
= msg
->msg_iov
;
484 if (opt
&& opt
->srcrt
)
489 err
= ip6_build_xmit(sk
, rawv6_frag_cksum
, &hdr
, &fl
, len
,
490 opt
, hlimit
, msg
->msg_flags
);
492 err
= ip6_build_xmit(sk
, rawv6_getfrag
, msg
->msg_iov
, &fl
, len
,
493 opt
, hlimit
, msg
->msg_flags
);
496 fl6_sock_release(flowlabel
);
498 return err
<0?err
:len
;
501 static int rawv6_seticmpfilter(struct sock
*sk
, int level
, int optname
,
502 char *optval
, int optlen
)
506 if (optlen
> sizeof(struct icmp6_filter
))
507 optlen
= sizeof(struct icmp6_filter
);
508 if (copy_from_user(&sk
->tp_pinfo
.tp_raw
.filter
, optval
, optlen
))
518 static int rawv6_geticmpfilter(struct sock
*sk
, int level
, int optname
,
519 char *optval
, int *optlen
)
525 if (get_user(len
, optlen
))
527 if (len
> sizeof(struct icmp6_filter
))
528 len
= sizeof(struct icmp6_filter
);
529 if (put_user(len
, optlen
))
531 if (copy_to_user(optval
, &sk
->tp_pinfo
.tp_raw
.filter
, len
))
542 static int rawv6_setsockopt(struct sock
*sk
, int level
, int optname
,
543 char *optval
, int optlen
)
545 struct raw6_opt
*opt
= &sk
->tp_pinfo
.tp_raw
;
553 if (sk
->num
!= IPPROTO_ICMPV6
)
555 return rawv6_seticmpfilter(sk
, level
, optname
, optval
,
558 if (optname
== IPV6_CHECKSUM
)
561 return ipv6_setsockopt(sk
, level
, optname
, optval
,
565 if (get_user(val
, (int *)optval
))
581 return(-ENOPROTOOPT
);
585 static int rawv6_getsockopt(struct sock
*sk
, int level
, int optname
,
586 char *optval
, int *optlen
)
588 struct raw6_opt
*opt
= &sk
->tp_pinfo
.tp_raw
;
596 if (sk
->num
!= IPPROTO_ICMPV6
)
598 return rawv6_geticmpfilter(sk
, level
, optname
, optval
,
601 if (optname
== IPV6_CHECKSUM
)
604 return ipv6_getsockopt(sk
, level
, optname
, optval
,
608 if (get_user(len
,optlen
))
613 if (opt
->checksum
== 0)
622 len
=min(sizeof(int),len
);
624 if (put_user(len
, optlen
))
626 if (copy_to_user(optval
,&val
,len
))
632 static void rawv6_close(struct sock
*sk
, long timeout
)
636 /* See for explanation: raw_close in ipv4/raw.c */
637 sk
->state
= TCP_CLOSE
;
639 if (sk
->num
== IPPROTO_RAW
)
640 ip6_ra_control(sk
, -1, NULL
);
645 static int rawv6_init_sk(struct sock
*sk
)
650 struct proto rawv6_prot
= {
651 (struct sock
*)&rawv6_prot
, /* sklist_next */
652 (struct sock
*)&rawv6_prot
, /* sklist_prev */
653 rawv6_close
, /* close */
654 udpv6_connect
, /* connect */
656 NULL
, /* retransmit */
657 NULL
, /* write_wakeup */
658 NULL
, /* read_wakeup */
659 datagram_poll
, /* poll */
661 rawv6_init_sk
, /* init */
662 inet6_destroy_sock
, /* destroy */
664 rawv6_setsockopt
, /* setsockopt */
665 rawv6_getsockopt
, /* getsockopt */
666 rawv6_sendmsg
, /* sendmsg */
667 rawv6_recvmsg
, /* recvmsg */
668 rawv6_bind
, /* bind */
669 rawv6_rcv_skb
, /* backlog_rcv */
670 raw_v6_hash
, /* hash */
671 raw_v6_unhash
, /* unhash */
672 raw_v6_rehash
, /* rehash */
673 NULL
, /* good_socknum */
674 NULL
, /* verify_bind */
675 128, /* max_header */