15
#include <sys/socket.h>
16
#include <netinet/in.h>
19
#include <embox/net/pack.h>
21
#include <net/l3/ipv4/ip.h>
22
#include <net/l4/udp.h>
23
#include <net/lib/udp.h>
25
#include <net/socket/inet_sock.h>
27
#include <lib/libds/dlist.h>
31
static const struct sock_proto_ops udp_sock_ops_struct;
32
const struct sock_proto_ops *const udp_sock_ops = &udp_sock_ops_struct;
34
EMBOX_NET_SOCK(AF_INET, SOCK_DGRAM, IPPROTO_UDP, 1,
37
static int iov_msg_len(struct iovec *iov, int iovlen) {
40
for (int i = 0; i < iovlen; i++) {
41
len += iov[i].iov_len;
47
int iov_stream_make_queue(size_t len, size_t hdr_size, struct sk_buff_head *queue,
48
struct sock *sk, const struct sockaddr *sockaddr) {
51
skb_queue_init(queue);
53
while (to_alloc > 0) {
54
struct sk_buff *skb = NULL;
55
size_t actual_len = to_alloc + hdr_size;
57
int ret = sk->o_ops->make_pack(sk, sockaddr, &actual_len, &skb);
59
skb_queue_purge(queue);
62
skb_queue_push(queue, skb);
63
to_alloc -= actual_len - hdr_size;
69
int iov_dgram_make_queue(size_t len, size_t hdr_size, struct sk_buff_head *queue,
70
struct sock *sk, const struct sockaddr *sockaddr) {
72
skb_queue_init(queue);
74
struct sk_buff *skb = NULL;
75
size_t actual_len = len + hdr_size;
77
int ret = sk->o_ops->make_pack(sk, sockaddr, &actual_len, &skb);
82
skb_queue_push(queue, skb);
83
return actual_len - hdr_size;
86
static int skb_queue_iov(struct sk_buff_head *queue, const struct iovec *iov, int iovlen, size_t header_len) {
87
struct sk_buff *skb = skb_queue_front(queue);
89
int skb_pos = 0, iov_pos = 0;
92
while (!skb_queue_end(skb, queue) && (i_iov < iovlen)) {
93
const int to_copy = min(skb->len - skb_pos, iov[i_iov].iov_len - iov_pos);
94
memcpy(skb->mac.raw + header_len + skb_pos, iov[i_iov].iov_base + iov_pos, to_copy);
100
if (skb->len == skb_pos) {
101
skb = skb_queue_next(skb);
105
if (iov[i_iov].iov_len == iov_pos) {
114
static int udp_get_udp_offset(struct sk_buff *skb) {
115
return (unsigned char *) (skb->h.uh) - skb->mac.raw;
118
static int udp_sendmsg(struct sock *sk, struct msghdr *msg, int flags) {
119
const in_port_t sk_src = sock_inet_get_src_port(sk);
120
const struct sockaddr_in *const addr_to = (const struct sockaddr_in *)
121
(msg->msg_name ? msg->msg_name : &to_inet_sock(sk)->dst_in);
122
struct sk_buff_head queue;
125
const size_t iov_data_len = iov_msg_len(msg->msg_iov, msg->msg_iovlen);
128
const struct sockaddr *sockaddr = (const struct sockaddr *)msg->msg_name;
130
const int out_data_len = iov_dgram_make_queue(iov_data_len, UDP_HEADER_SIZE, &queue, sk, sockaddr);
131
if (out_data_len < 0) {
136
const int skb_udp_offset = udp_get_udp_offset(queue.next);
138
const int bytes_copied = skb_queue_iov(&queue, msg->msg_iov, msg->msg_iovlen, skb_udp_offset + UDP_HEADER_SIZE);
139
if (bytes_copied != out_data_len) {
144
for (struct sk_buff *skb = skb_queue_pop(&queue); skb; skb = skb_queue_pop(&queue)) {
145
udp_build(skb->h.uh, sk_src, addr_to->sin_port, skb->len - skb_udp_offset);
146
udp4_set_check_field(skb->h.uh, skb->nh.iph);
147
err = sk->o_ops->snd_pack(skb);
154
skb_queue_purge(&queue);
158
assert(skb_queue_front(&queue) == NULL);
163
static DLIST_DEFINE(udp_sock_list);
165
static int udp_fillmsg(struct sock *sk, struct msghdr *msg,
166
struct sk_buff *skb) {
167
struct sockaddr_in *inaddr;
169
inaddr = (struct sockaddr_in *)msg->msg_name;
171
inaddr->sin_family = AF_INET;
172
memcpy(&inaddr->sin_addr, &ip_hdr(skb)->saddr, sizeof(in_addr_t));
173
inaddr->sin_port = udp_hdr(skb)->source;
178
static const struct sock_proto_ops udp_sock_ops_struct = {
179
.sendmsg = udp_sendmsg,
180
.recvmsg = sock_dgram_recvmsg,
181
.fillmsg = udp_fillmsg,
182
.sock_list = &udp_sock_list