3
* @brief Implements raw socket function.
6
* @author Anton Bondarev
13
#include <sys/socket.h>
15
#include <netinet/in.h>
17
#include <net/l3/ipv4/ip.h>
18
#include <net/l3/icmpv4.h>
19
#include <net/skbuff.h>
21
#include <net/socket/inet_sock.h>
22
#include <net/socket/raw.h>
23
#include <net/netdevice.h>
25
#include <lib/libds/dlist.h>
28
#include <embox/net/pack.h>
30
static const struct sock_proto_ops raw_sock_ops_struct;
31
const struct sock_proto_ops *const raw_sock_ops
32
= &raw_sock_ops_struct;
34
EMBOX_NET_SOCK(AF_INET, SOCK_RAW, IPPROTO_ICMP, 0,
36
EMBOX_NET_SOCK(AF_INET, SOCK_RAW, IPPROTO_UDP, 0,
38
EMBOX_NET_SOCK(AF_INET, SOCK_RAW, IPPROTO_TCP, 0,
40
EMBOX_NET_SOCK(AF_INET, SOCK_RAW, IPPROTO_RAW, 0,
43
static int raw_rcv_tester(const struct sock *sk,
44
const struct sk_buff *skb) {
45
const struct inet_sock *in_sk;
47
in_sk = (const struct inet_sock *)sk;
48
assert(in_sk != NULL);
49
assert(in_sk->src_in.sin_family == AF_INET);
50
assert(in_sk->dst_in.sin_family == AF_INET);
53
assert(skb->nh.iph != NULL);
55
return ((in_sk->src_in.sin_addr.s_addr == skb->nh.iph->daddr)
56
|| (in_sk->src_in.sin_addr.s_addr == INADDR_ANY))
57
&& ((in_sk->dst_in.sin_addr.s_addr == skb->nh.iph->saddr)
58
|| (in_sk->dst_in.sin_addr.s_addr == INADDR_ANY))
59
&& (in_sk->sk.opt.so_protocol == skb->nh.iph->proto)
60
&& ((in_sk->sk.opt.so_bindtodevice == skb->dev)
61
|| (in_sk->sk.opt.so_bindtodevice == NULL));
64
extern uint16_t skb_get_secure_level(const struct sk_buff *skb);
65
extern uint16_t sock_get_secure_level(const struct sock *sk);
67
int raw_rcv(const struct sk_buff *skb) {
69
struct sk_buff *cloned;
72
assert(skb->dev != NULL);
78
sk = sock_lookup(sk, raw_sock_ops, raw_rcv_tester, skb);
82
/* if we have socket with secure label we have to check secure level */
83
if (sock_get_secure_level(sk) > skb_get_secure_level(skb)) {
87
cloned = skb_clone(skb);
92
sock_rcv(sk, cloned, cloned->nh.raw,
93
cloned->len - skb->dev->hdr_len);
99
static int raw_err_tester(const struct sock *sk,
100
const struct sk_buff *skb) {
101
const struct inet_sock *in_sk;
102
const struct iphdr *emb_pack_iphdr;
104
in_sk = (const struct inet_sock *)sk;
105
assert(in_sk != NULL);
106
assert(in_sk->src_in.sin_family == AF_INET);
107
assert(in_sk->dst_in.sin_family == AF_INET);
110
assert(skb->h.raw != NULL);
111
emb_pack_iphdr = (const struct iphdr *)(skb->h.raw
112
+ IP_HEADER_SIZE(skb->nh.iph) + ICMP_MIN_HEADER_SIZE);
114
return (((in_sk->src_in.sin_addr.s_addr == skb->nh.iph->daddr)
115
&& (in_sk->src_in.sin_addr.s_addr == emb_pack_iphdr->saddr))
116
|| (in_sk->src_in.sin_addr.s_addr == INADDR_ANY))
117
&& (((in_sk->dst_in.sin_addr.s_addr == skb->nh.iph->saddr)
118
&& (in_sk->dst_in.sin_addr.s_addr == emb_pack_iphdr->daddr))
119
|| (in_sk->dst_in.sin_addr.s_addr == INADDR_ANY))
120
&& (in_sk->sk.opt.so_protocol == skb->nh.iph->proto)
121
&& ((in_sk->sk.opt.so_bindtodevice == skb->dev)
122
|| (in_sk->sk.opt.so_bindtodevice == NULL));
125
void raw_err(const struct sk_buff *skb, int error_info) {
131
sk = sock_lookup(sk, raw_sock_ops, raw_err_tester, skb);
136
sock_set_so_error(sk, error_info);
140
static int raw_sendmsg(struct sock *sk, struct msghdr *msg, int flags) {
144
const struct sockaddr *sockaddr;
149
assert(msg->msg_iov);
150
assert(msg->msg_iov->iov_base);
152
assert(sk->o_ops->make_pack);
154
data_len = msg->msg_iov->iov_len;
156
sockaddr = (const struct sockaddr *)msg->msg_name;
158
if (sk->opt.so_type == SOCK_RAW) {
159
struct inet_sock *inet = to_inet_sock(sk);
161
if (sk->opt.so_protocol == IPPROTO_RAW) {
162
/* It is Linux specific behaviour. FreeBSD does not set this flag by default
163
* when protocol is IPPROTO_RAW.
164
* See http://sock-raw.org/papers/sock_raw */
165
inet->opt.hdrincl = 1;
168
if (inet->opt.hdrincl) {
174
ret = sk->o_ops->make_pack(sk, sockaddr, &data_len, &skb);
176
size_t actual_data_len;
177
if (data_len < sizeof(struct iphdr)) {
180
actual_data_len = data_len - sizeof(struct iphdr);
181
ret = sk->o_ops->make_pack(sk, sockaddr, &actual_data_len, &skb);
182
data_len = actual_data_len + sizeof(struct iphdr);
189
if (data_len < msg->msg_iov->iov_len) {
198
memcpy(skb->h.raw, msg->msg_iov->iov_base, data_len);
200
/* Rewrite IP header made by sk->o_ops->make_pack above +
201
* write @c actual_data_len payload */
202
memcpy(skb->nh.raw, msg->msg_iov->iov_base, data_len);
205
assert(sk->o_ops->snd_pack != NULL);
206
ret = sk->o_ops->snd_pack(skb);
213
static DLIST_DEFINE(raw_sock_list);
215
static const struct sock_proto_ops raw_sock_ops_struct = {
216
.sendmsg = raw_sendmsg,
217
.recvmsg = sock_dgram_recvmsg,
218
.sock_list = &raw_sock_list