Skip to content

Commit 314001f

Browse files
Rao Shoaibdavem330
Rao Shoaib
authored andcommitted
af_unix: Add OOB support
This patch adds OOB support for AF_UNIX sockets. The semantics is same as TCP. The last byte of a message with the OOB flag is treated as the OOB byte. The byte is separated into a skb and a pointer to the skb is stored in unix_sock. The pointer is used to enforce OOB semantics. Signed-off-by: Rao Shoaib <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 7e89350 commit 314001f

File tree

6 files changed

+602
-2
lines changed

6 files changed

+602
-2
lines changed

include/net/af_unix.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ struct unix_sock {
7070
struct socket_wq peer_wq;
7171
wait_queue_entry_t peer_wake;
7272
struct scm_stat scm_stat;
73+
#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
74+
struct sk_buff *oob_skb;
75+
#endif
7376
};
7477

7578
static inline struct unix_sock *unix_sk(const struct sock *sk)

net/unix/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ config UNIX_SCM
2525
depends on UNIX
2626
default y
2727

28+
config AF_UNIX_OOB
29+
bool
30+
depends on UNIX
31+
default y
32+
2833
config UNIX_DIAG
2934
tristate "UNIX: socket monitoring interface"
3035
depends on UNIX

net/unix/af_unix.c

Lines changed: 151 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,12 @@ static void unix_sock_destructor(struct sock *sk)
503503

504504
skb_queue_purge(&sk->sk_receive_queue);
505505

506+
#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
507+
if (u->oob_skb) {
508+
kfree_skb(u->oob_skb);
509+
u->oob_skb = NULL;
510+
}
511+
#endif
506512
WARN_ON(refcount_read(&sk->sk_wmem_alloc));
507513
WARN_ON(!sk_unhashed(sk));
508514
WARN_ON(sk->sk_socket);
@@ -1889,6 +1895,46 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
18891895
*/
18901896
#define UNIX_SKB_FRAGS_SZ (PAGE_SIZE << get_order(32768))
18911897

1898+
#if (IS_ENABLED(CONFIG_AF_UNIX_OOB))
1899+
static int queue_oob(struct socket *sock, struct msghdr *msg, struct sock *other)
1900+
{
1901+
struct unix_sock *ousk = unix_sk(other);
1902+
struct sk_buff *skb;
1903+
int err = 0;
1904+
1905+
skb = sock_alloc_send_skb(sock->sk, 1, msg->msg_flags & MSG_DONTWAIT, &err);
1906+
1907+
if (!skb)
1908+
return err;
1909+
1910+
skb_put(skb, 1);
1911+
skb->len = 1;
1912+
err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, 1);
1913+
1914+
if (err) {
1915+
kfree_skb(skb);
1916+
return err;
1917+
}
1918+
1919+
unix_state_lock(other);
1920+
maybe_add_creds(skb, sock, other);
1921+
skb_get(skb);
1922+
1923+
if (ousk->oob_skb)
1924+
kfree_skb(ousk->oob_skb);
1925+
1926+
ousk->oob_skb = skb;
1927+
1928+
scm_stat_add(other, skb);
1929+
skb_queue_tail(&other->sk_receive_queue, skb);
1930+
sk_send_sigurg(other);
1931+
unix_state_unlock(other);
1932+
other->sk_data_ready(other);
1933+
1934+
return err;
1935+
}
1936+
#endif
1937+
18921938
static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
18931939
size_t len)
18941940
{
@@ -1907,8 +1953,14 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
19071953
return err;
19081954

19091955
err = -EOPNOTSUPP;
1910-
if (msg->msg_flags&MSG_OOB)
1911-
goto out_err;
1956+
if (msg->msg_flags & MSG_OOB) {
1957+
#if (IS_ENABLED(CONFIG_AF_UNIX_OOB))
1958+
if (len)
1959+
len--;
1960+
else
1961+
#endif
1962+
goto out_err;
1963+
}
19121964

19131965
if (msg->msg_namelen) {
19141966
err = sk->sk_state == TCP_ESTABLISHED ? -EISCONN : -EOPNOTSUPP;
@@ -1973,6 +2025,15 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
19732025
sent += size;
19742026
}
19752027

2028+
#if (IS_ENABLED(CONFIG_AF_UNIX_OOB))
2029+
if (msg->msg_flags & MSG_OOB) {
2030+
err = queue_oob(sock, msg, other);
2031+
if (err)
2032+
goto out_err;
2033+
sent++;
2034+
}
2035+
#endif
2036+
19762037
scm_destroy(&scm);
19772038

19782039
return sent;
@@ -2358,6 +2419,59 @@ struct unix_stream_read_state {
23582419
unsigned int splice_flags;
23592420
};
23602421

2422+
#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
2423+
static int unix_stream_recv_urg(struct unix_stream_read_state *state)
2424+
{
2425+
struct socket *sock = state->socket;
2426+
struct sock *sk = sock->sk;
2427+
struct unix_sock *u = unix_sk(sk);
2428+
int chunk = 1;
2429+
2430+
if (sock_flag(sk, SOCK_URGINLINE) || !u->oob_skb)
2431+
return -EINVAL;
2432+
2433+
chunk = state->recv_actor(u->oob_skb, 0, chunk, state);
2434+
if (chunk < 0)
2435+
return -EFAULT;
2436+
2437+
if (!(state->flags & MSG_PEEK)) {
2438+
UNIXCB(u->oob_skb).consumed += 1;
2439+
kfree_skb(u->oob_skb);
2440+
u->oob_skb = NULL;
2441+
}
2442+
state->msg->msg_flags |= MSG_OOB;
2443+
return 1;
2444+
}
2445+
2446+
static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,
2447+
int flags, int copied)
2448+
{
2449+
struct unix_sock *u = unix_sk(sk);
2450+
2451+
if (!unix_skb_len(skb) && !(flags & MSG_PEEK)) {
2452+
skb_unlink(skb, &sk->sk_receive_queue);
2453+
consume_skb(skb);
2454+
skb = NULL;
2455+
} else {
2456+
if (skb == u->oob_skb) {
2457+
if (copied) {
2458+
skb = NULL;
2459+
} else if (sock_flag(sk, SOCK_URGINLINE)) {
2460+
if (!(flags & MSG_PEEK)) {
2461+
u->oob_skb = NULL;
2462+
consume_skb(skb);
2463+
}
2464+
} else if (!(flags & MSG_PEEK)) {
2465+
skb_unlink(skb, &sk->sk_receive_queue);
2466+
consume_skb(skb);
2467+
skb = skb_peek(&sk->sk_receive_queue);
2468+
}
2469+
}
2470+
}
2471+
return skb;
2472+
}
2473+
#endif
2474+
23612475
static int unix_stream_read_generic(struct unix_stream_read_state *state,
23622476
bool freezable)
23632477
{
@@ -2383,6 +2497,15 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state,
23832497

23842498
if (unlikely(flags & MSG_OOB)) {
23852499
err = -EOPNOTSUPP;
2500+
#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
2501+
mutex_lock(&u->iolock);
2502+
unix_state_lock(sk);
2503+
2504+
err = unix_stream_recv_urg(state);
2505+
2506+
unix_state_unlock(sk);
2507+
mutex_unlock(&u->iolock);
2508+
#endif
23862509
goto out;
23872510
}
23882511

@@ -2411,6 +2534,18 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state,
24112534
}
24122535
last = skb = skb_peek(&sk->sk_receive_queue);
24132536
last_len = last ? last->len : 0;
2537+
2538+
#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
2539+
if (skb) {
2540+
skb = manage_oob(skb, sk, flags, copied);
2541+
if (!skb) {
2542+
unix_state_unlock(sk);
2543+
if (copied)
2544+
break;
2545+
goto redo;
2546+
}
2547+
}
2548+
#endif
24142549
again:
24152550
if (skb == NULL) {
24162551
if (copied >= target)
@@ -2746,6 +2881,20 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
27462881
case SIOCUNIXFILE:
27472882
err = unix_open_file(sk);
27482883
break;
2884+
#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
2885+
case SIOCATMARK:
2886+
{
2887+
struct sk_buff *skb;
2888+
struct unix_sock *u = unix_sk(sk);
2889+
int answ = 0;
2890+
2891+
skb = skb_peek(&sk->sk_receive_queue);
2892+
if (skb && skb == u->oob_skb)
2893+
answ = 1;
2894+
err = put_user(answ, (int __user *)arg);
2895+
}
2896+
break;
2897+
#endif
27492898
default:
27502899
err = -ENOIOCTLCMD;
27512900
break;

tools/testing/selftests/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ TARGETS += mount_setattr
3838
TARGETS += mqueue
3939
TARGETS += nci
4040
TARGETS += net
41+
TARGETS += net/af_unix
4142
TARGETS += net/forwarding
4243
TARGETS += net/mptcp
4344
TARGETS += netfilter
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
##TEST_GEN_FILES := test_unix_oob
2+
TEST_PROGS := test_unix_oob
3+
include ../../lib.mk
4+
5+
all: $(TEST_PROGS)

0 commit comments

Comments
 (0)