diff options
Diffstat (limited to 'net/tipc/socket.c')
-rw-r--r-- | net/tipc/socket.c | 209 |
1 files changed, 182 insertions, 27 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index daf7c4df4531..64bbf9d03629 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * net/tipc/socket.c: TIPC socket API | 2 | * net/tipc/socket.c: TIPC socket API |
3 | * | 3 | * |
4 | * Copyright (c) 2001-2007, 2012-2016, Ericsson AB | 4 | * Copyright (c) 2001-2007, 2012-2017, Ericsson AB |
5 | * Copyright (c) 2004-2008, 2010-2013, Wind River Systems | 5 | * Copyright (c) 2004-2008, 2010-2013, Wind River Systems |
6 | * All rights reserved. | 6 | * All rights reserved. |
7 | * | 7 | * |
@@ -45,6 +45,7 @@ | |||
45 | #include "socket.h" | 45 | #include "socket.h" |
46 | #include "bcast.h" | 46 | #include "bcast.h" |
47 | #include "netlink.h" | 47 | #include "netlink.h" |
48 | #include "group.h" | ||
48 | 49 | ||
49 | #define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ | 50 | #define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ |
50 | #define CONN_PROBING_INTERVAL msecs_to_jiffies(3600000) /* [ms] => 1 h */ | 51 | #define CONN_PROBING_INTERVAL msecs_to_jiffies(3600000) /* [ms] => 1 h */ |
@@ -78,7 +79,7 @@ enum { | |||
78 | * @conn_timeout: the time we can wait for an unresponded setup request | 79 | * @conn_timeout: the time we can wait for an unresponded setup request |
79 | * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue | 80 | * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue |
80 | * @cong_link_cnt: number of congested links | 81 | * @cong_link_cnt: number of congested links |
81 | * @sent_unacked: # messages sent by socket, and not yet acked by peer | 82 | * @snt_unacked: # messages sent by socket, and not yet acked by peer |
82 | * @rcv_unacked: # messages read by user, but not yet acked back to peer | 83 | * @rcv_unacked: # messages read by user, but not yet acked back to peer |
83 | * @peer: 'connected' peer for dgram/rdm | 84 | * @peer: 'connected' peer for dgram/rdm |
84 | * @node: hash table node | 85 | * @node: hash table node |
@@ -109,6 +110,7 @@ struct tipc_sock { | |||
109 | struct rhash_head node; | 110 | struct rhash_head node; |
110 | struct tipc_mc_method mc_method; | 111 | struct tipc_mc_method mc_method; |
111 | struct rcu_head rcu; | 112 | struct rcu_head rcu; |
113 | struct tipc_group *group; | ||
112 | }; | 114 | }; |
113 | 115 | ||
114 | static int tipc_sk_backlog_rcv(struct sock *sk, struct sk_buff *skb); | 116 | static int tipc_sk_backlog_rcv(struct sock *sk, struct sk_buff *skb); |
@@ -123,6 +125,7 @@ static int tipc_sk_publish(struct tipc_sock *tsk, uint scope, | |||
123 | struct tipc_name_seq const *seq); | 125 | struct tipc_name_seq const *seq); |
124 | static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope, | 126 | static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope, |
125 | struct tipc_name_seq const *seq); | 127 | struct tipc_name_seq const *seq); |
128 | static int tipc_sk_leave(struct tipc_sock *tsk); | ||
126 | static struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid); | 129 | static struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid); |
127 | static int tipc_sk_insert(struct tipc_sock *tsk); | 130 | static int tipc_sk_insert(struct tipc_sock *tsk); |
128 | static void tipc_sk_remove(struct tipc_sock *tsk); | 131 | static void tipc_sk_remove(struct tipc_sock *tsk); |
@@ -559,6 +562,7 @@ static int tipc_release(struct socket *sock) | |||
559 | 562 | ||
560 | __tipc_shutdown(sock, TIPC_ERR_NO_PORT); | 563 | __tipc_shutdown(sock, TIPC_ERR_NO_PORT); |
561 | sk->sk_shutdown = SHUTDOWN_MASK; | 564 | sk->sk_shutdown = SHUTDOWN_MASK; |
565 | tipc_sk_leave(tsk); | ||
562 | tipc_sk_withdraw(tsk, 0, NULL); | 566 | tipc_sk_withdraw(tsk, 0, NULL); |
563 | sk_stop_timer(sk, &sk->sk_timer); | 567 | sk_stop_timer(sk, &sk->sk_timer); |
564 | tipc_sk_remove(tsk); | 568 | tipc_sk_remove(tsk); |
@@ -601,7 +605,10 @@ static int tipc_bind(struct socket *sock, struct sockaddr *uaddr, | |||
601 | res = tipc_sk_withdraw(tsk, 0, NULL); | 605 | res = tipc_sk_withdraw(tsk, 0, NULL); |
602 | goto exit; | 606 | goto exit; |
603 | } | 607 | } |
604 | 608 | if (tsk->group) { | |
609 | res = -EACCES; | ||
610 | goto exit; | ||
611 | } | ||
605 | if (uaddr_len < sizeof(struct sockaddr_tipc)) { | 612 | if (uaddr_len < sizeof(struct sockaddr_tipc)) { |
606 | res = -EINVAL; | 613 | res = -EINVAL; |
607 | goto exit; | 614 | goto exit; |
@@ -698,6 +705,7 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, | |||
698 | { | 705 | { |
699 | struct sock *sk = sock->sk; | 706 | struct sock *sk = sock->sk; |
700 | struct tipc_sock *tsk = tipc_sk(sk); | 707 | struct tipc_sock *tsk = tipc_sk(sk); |
708 | struct tipc_group *grp = tsk->group; | ||
701 | u32 mask = 0; | 709 | u32 mask = 0; |
702 | 710 | ||
703 | sock_poll_wait(file, sk_sleep(sk), wait); | 711 | sock_poll_wait(file, sk_sleep(sk), wait); |
@@ -718,8 +726,9 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock, | |||
718 | mask |= (POLLIN | POLLRDNORM); | 726 | mask |= (POLLIN | POLLRDNORM); |
719 | break; | 727 | break; |
720 | case TIPC_OPEN: | 728 | case TIPC_OPEN: |
721 | if (!tsk->cong_link_cnt) | 729 | if (!grp || tipc_group_size(grp)) |
722 | mask |= POLLOUT; | 730 | if (!tsk->cong_link_cnt) |
731 | mask |= POLLOUT; | ||
723 | if (tipc_sk_type_connectionless(sk) && | 732 | if (tipc_sk_type_connectionless(sk) && |
724 | (!skb_queue_empty(&sk->sk_receive_queue))) | 733 | (!skb_queue_empty(&sk->sk_receive_queue))) |
725 | mask |= (POLLIN | POLLRDNORM); | 734 | mask |= (POLLIN | POLLRDNORM); |
@@ -757,6 +766,9 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq, | |||
757 | struct tipc_nlist dsts; | 766 | struct tipc_nlist dsts; |
758 | int rc; | 767 | int rc; |
759 | 768 | ||
769 | if (tsk->group) | ||
770 | return -EACCES; | ||
771 | |||
760 | /* Block or return if any destination link is congested */ | 772 | /* Block or return if any destination link is congested */ |
761 | rc = tipc_wait_for_cond(sock, &timeout, !tsk->cong_link_cnt); | 773 | rc = tipc_wait_for_cond(sock, &timeout, !tsk->cong_link_cnt); |
762 | if (unlikely(rc)) | 774 | if (unlikely(rc)) |
@@ -794,6 +806,64 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq, | |||
794 | } | 806 | } |
795 | 807 | ||
796 | /** | 808 | /** |
809 | * tipc_send_group_bcast - send message to all members in communication group | ||
810 | * @sk: socket structure | ||
811 | * @m: message to send | ||
812 | * @dlen: total length of message data | ||
813 | * @timeout: timeout to wait for wakeup | ||
814 | * | ||
815 | * Called from function tipc_sendmsg(), which has done all sanity checks | ||
816 | * Returns the number of bytes sent on success, or errno | ||
817 | */ | ||
818 | static int tipc_send_group_bcast(struct socket *sock, struct msghdr *m, | ||
819 | int dlen, long timeout) | ||
820 | { | ||
821 | struct sock *sk = sock->sk; | ||
822 | struct net *net = sock_net(sk); | ||
823 | struct tipc_sock *tsk = tipc_sk(sk); | ||
824 | struct tipc_group *grp = tsk->group; | ||
825 | struct tipc_nlist *dsts = tipc_group_dests(grp); | ||
826 | struct tipc_mc_method *method = &tsk->mc_method; | ||
827 | struct tipc_msg *hdr = &tsk->phdr; | ||
828 | int mtu = tipc_bcast_get_mtu(net); | ||
829 | struct sk_buff_head pkts; | ||
830 | int rc = -EHOSTUNREACH; | ||
831 | |||
832 | if (!dsts->local && !dsts->remote) | ||
833 | return -EHOSTUNREACH; | ||
834 | |||
835 | /* Block or return if any destination link is congested */ | ||
836 | rc = tipc_wait_for_cond(sock, &timeout, !tsk->cong_link_cnt); | ||
837 | if (unlikely(rc)) | ||
838 | return rc; | ||
839 | |||
840 | /* Complete message header */ | ||
841 | msg_set_type(hdr, TIPC_GRP_BCAST_MSG); | ||
842 | msg_set_hdr_sz(hdr, MCAST_H_SIZE); | ||
843 | msg_set_destport(hdr, 0); | ||
844 | msg_set_destnode(hdr, 0); | ||
845 | msg_set_nameinst(hdr, 0); | ||
846 | msg_set_grp_bc_seqno(hdr, tipc_group_bc_snd_nxt(grp)); | ||
847 | |||
848 | /* Build message as chain of buffers */ | ||
849 | skb_queue_head_init(&pkts); | ||
850 | rc = tipc_msg_build(hdr, m, 0, dlen, mtu, &pkts); | ||
851 | if (unlikely(rc != dlen)) | ||
852 | return rc; | ||
853 | |||
854 | /* Send message */ | ||
855 | rc = tipc_mcast_xmit(net, &pkts, method, dsts, | ||
856 | &tsk->cong_link_cnt); | ||
857 | if (unlikely(rc)) | ||
858 | return rc; | ||
859 | |||
860 | /* Update broadcast sequence number */ | ||
861 | tipc_group_update_bc_members(tsk->group); | ||
862 | |||
863 | return dlen; | ||
864 | } | ||
865 | |||
866 | /** | ||
797 | * tipc_sk_mcast_rcv - Deliver multicast messages to all destination sockets | 867 | * tipc_sk_mcast_rcv - Deliver multicast messages to all destination sockets |
798 | * @arrvq: queue with arriving messages, to be cloned after destination lookup | 868 | * @arrvq: queue with arriving messages, to be cloned after destination lookup |
799 | * @inputq: queue with cloned messages, delivered to socket after dest lookup | 869 | * @inputq: queue with cloned messages, delivered to socket after dest lookup |
@@ -803,13 +873,15 @@ static int tipc_sendmcast(struct socket *sock, struct tipc_name_seq *seq, | |||
803 | void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq, | 873 | void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq, |
804 | struct sk_buff_head *inputq) | 874 | struct sk_buff_head *inputq) |
805 | { | 875 | { |
806 | struct tipc_msg *msg; | ||
807 | struct list_head dports; | ||
808 | u32 portid; | ||
809 | u32 scope = TIPC_CLUSTER_SCOPE; | 876 | u32 scope = TIPC_CLUSTER_SCOPE; |
810 | struct sk_buff_head tmpq; | 877 | u32 self = tipc_own_addr(net); |
811 | uint hsz; | ||
812 | struct sk_buff *skb, *_skb; | 878 | struct sk_buff *skb, *_skb; |
879 | u32 lower = 0, upper = ~0; | ||
880 | struct sk_buff_head tmpq; | ||
881 | u32 portid, oport, onode; | ||
882 | struct list_head dports; | ||
883 | struct tipc_msg *msg; | ||
884 | int hsz; | ||
813 | 885 | ||
814 | __skb_queue_head_init(&tmpq); | 886 | __skb_queue_head_init(&tmpq); |
815 | INIT_LIST_HEAD(&dports); | 887 | INIT_LIST_HEAD(&dports); |
@@ -818,14 +890,18 @@ void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq, | |||
818 | for (; skb; skb = tipc_skb_peek(arrvq, &inputq->lock)) { | 890 | for (; skb; skb = tipc_skb_peek(arrvq, &inputq->lock)) { |
819 | msg = buf_msg(skb); | 891 | msg = buf_msg(skb); |
820 | hsz = skb_headroom(skb) + msg_hdr_sz(msg); | 892 | hsz = skb_headroom(skb) + msg_hdr_sz(msg); |
821 | 893 | oport = msg_origport(msg); | |
822 | if (in_own_node(net, msg_orignode(msg))) | 894 | onode = msg_orignode(msg); |
895 | if (onode == self) | ||
823 | scope = TIPC_NODE_SCOPE; | 896 | scope = TIPC_NODE_SCOPE; |
824 | 897 | ||
825 | /* Create destination port list and message clones: */ | 898 | /* Create destination port list and message clones: */ |
826 | tipc_nametbl_mc_translate(net, | 899 | if (!msg_in_group(msg)) { |
827 | msg_nametype(msg), msg_namelower(msg), | 900 | lower = msg_namelower(msg); |
828 | msg_nameupper(msg), scope, &dports); | 901 | upper = msg_nameupper(msg); |
902 | } | ||
903 | tipc_nametbl_mc_translate(net, msg_nametype(msg), lower, upper, | ||
904 | scope, &dports); | ||
829 | while (tipc_dest_pop(&dports, NULL, &portid)) { | 905 | while (tipc_dest_pop(&dports, NULL, &portid)) { |
830 | _skb = __pskb_copy(skb, hsz, GFP_ATOMIC); | 906 | _skb = __pskb_copy(skb, hsz, GFP_ATOMIC); |
831 | if (_skb) { | 907 | if (_skb) { |
@@ -895,10 +971,6 @@ exit: | |||
895 | kfree_skb(skb); | 971 | kfree_skb(skb); |
896 | } | 972 | } |
897 | 973 | ||
898 | static void tipc_sk_top_evt(struct tipc_sock *tsk, struct tipc_event *evt) | ||
899 | { | ||
900 | } | ||
901 | |||
902 | /** | 974 | /** |
903 | * tipc_sendmsg - send message in connectionless manner | 975 | * tipc_sendmsg - send message in connectionless manner |
904 | * @sock: socket structure | 976 | * @sock: socket structure |
@@ -934,6 +1006,7 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen) | |||
934 | long timeout = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); | 1006 | long timeout = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); |
935 | struct list_head *clinks = &tsk->cong_links; | 1007 | struct list_head *clinks = &tsk->cong_links; |
936 | bool syn = !tipc_sk_type_connectionless(sk); | 1008 | bool syn = !tipc_sk_type_connectionless(sk); |
1009 | struct tipc_group *grp = tsk->group; | ||
937 | struct tipc_msg *hdr = &tsk->phdr; | 1010 | struct tipc_msg *hdr = &tsk->phdr; |
938 | struct tipc_name_seq *seq; | 1011 | struct tipc_name_seq *seq; |
939 | struct sk_buff_head pkts; | 1012 | struct sk_buff_head pkts; |
@@ -944,6 +1017,9 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen) | |||
944 | if (unlikely(dlen > TIPC_MAX_USER_MSG_SIZE)) | 1017 | if (unlikely(dlen > TIPC_MAX_USER_MSG_SIZE)) |
945 | return -EMSGSIZE; | 1018 | return -EMSGSIZE; |
946 | 1019 | ||
1020 | if (unlikely(grp)) | ||
1021 | return tipc_send_group_bcast(sock, m, dlen, timeout); | ||
1022 | |||
947 | if (unlikely(!dest)) { | 1023 | if (unlikely(!dest)) { |
948 | dest = &tsk->peer; | 1024 | dest = &tsk->peer; |
949 | if (!syn || dest->family != AF_TIPC) | 1025 | if (!syn || dest->family != AF_TIPC) |
@@ -1543,6 +1619,7 @@ static void tipc_sk_proto_rcv(struct sock *sk, | |||
1543 | struct sk_buff *skb = __skb_dequeue(inputq); | 1619 | struct sk_buff *skb = __skb_dequeue(inputq); |
1544 | struct tipc_sock *tsk = tipc_sk(sk); | 1620 | struct tipc_sock *tsk = tipc_sk(sk); |
1545 | struct tipc_msg *hdr = buf_msg(skb); | 1621 | struct tipc_msg *hdr = buf_msg(skb); |
1622 | struct tipc_group *grp = tsk->group; | ||
1546 | 1623 | ||
1547 | switch (msg_user(hdr)) { | 1624 | switch (msg_user(hdr)) { |
1548 | case CONN_MANAGER: | 1625 | case CONN_MANAGER: |
@@ -1553,8 +1630,12 @@ static void tipc_sk_proto_rcv(struct sock *sk, | |||
1553 | tsk->cong_link_cnt--; | 1630 | tsk->cong_link_cnt--; |
1554 | sk->sk_write_space(sk); | 1631 | sk->sk_write_space(sk); |
1555 | break; | 1632 | break; |
1633 | case GROUP_PROTOCOL: | ||
1634 | tipc_group_proto_rcv(grp, hdr, xmitq); | ||
1635 | break; | ||
1556 | case TOP_SRV: | 1636 | case TOP_SRV: |
1557 | tipc_sk_top_evt(tsk, (void *)msg_data(hdr)); | 1637 | tipc_group_member_evt(tsk->group, skb, xmitq); |
1638 | skb = NULL; | ||
1558 | break; | 1639 | break; |
1559 | default: | 1640 | default: |
1560 | break; | 1641 | break; |
@@ -1699,6 +1780,7 @@ static void tipc_sk_filter_rcv(struct sock *sk, struct sk_buff *skb, | |||
1699 | { | 1780 | { |
1700 | bool sk_conn = !tipc_sk_type_connectionless(sk); | 1781 | bool sk_conn = !tipc_sk_type_connectionless(sk); |
1701 | struct tipc_sock *tsk = tipc_sk(sk); | 1782 | struct tipc_sock *tsk = tipc_sk(sk); |
1783 | struct tipc_group *grp = tsk->group; | ||
1702 | struct tipc_msg *hdr = buf_msg(skb); | 1784 | struct tipc_msg *hdr = buf_msg(skb); |
1703 | struct net *net = sock_net(sk); | 1785 | struct net *net = sock_net(sk); |
1704 | struct sk_buff_head inputq; | 1786 | struct sk_buff_head inputq; |
@@ -1710,15 +1792,19 @@ static void tipc_sk_filter_rcv(struct sock *sk, struct sk_buff *skb, | |||
1710 | 1792 | ||
1711 | if (unlikely(!msg_isdata(hdr))) | 1793 | if (unlikely(!msg_isdata(hdr))) |
1712 | tipc_sk_proto_rcv(sk, &inputq, xmitq); | 1794 | tipc_sk_proto_rcv(sk, &inputq, xmitq); |
1713 | else if (unlikely(msg_type(hdr) > TIPC_DIRECT_MSG)) | 1795 | else if (unlikely(msg_type(hdr) > TIPC_GRP_BCAST_MSG)) |
1714 | return kfree_skb(skb); | 1796 | return kfree_skb(skb); |
1715 | 1797 | ||
1798 | if (unlikely(grp)) | ||
1799 | tipc_group_filter_msg(grp, &inputq, xmitq); | ||
1800 | |||
1716 | /* Validate and add to receive buffer if there is space */ | 1801 | /* Validate and add to receive buffer if there is space */ |
1717 | while ((skb = __skb_dequeue(&inputq))) { | 1802 | while ((skb = __skb_dequeue(&inputq))) { |
1718 | hdr = buf_msg(skb); | 1803 | hdr = buf_msg(skb); |
1719 | limit = rcvbuf_limit(sk, skb); | 1804 | limit = rcvbuf_limit(sk, skb); |
1720 | if ((sk_conn && !tipc_sk_filter_connect(tsk, skb)) || | 1805 | if ((sk_conn && !tipc_sk_filter_connect(tsk, skb)) || |
1721 | (!sk_conn && msg_connected(hdr))) | 1806 | (!sk_conn && msg_connected(hdr)) || |
1807 | (!grp && msg_in_group(hdr))) | ||
1722 | err = TIPC_ERR_NO_PORT; | 1808 | err = TIPC_ERR_NO_PORT; |
1723 | else if (sk_rmem_alloc_get(sk) + skb->truesize >= limit) | 1809 | else if (sk_rmem_alloc_get(sk) + skb->truesize >= limit) |
1724 | err = TIPC_ERR_OVERLOAD; | 1810 | err = TIPC_ERR_OVERLOAD; |
@@ -1837,7 +1923,6 @@ void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq) | |||
1837 | sock_put(sk); | 1923 | sock_put(sk); |
1838 | continue; | 1924 | continue; |
1839 | } | 1925 | } |
1840 | |||
1841 | /* No destination socket => dequeue skb if still there */ | 1926 | /* No destination socket => dequeue skb if still there */ |
1842 | skb = tipc_skb_dequeue(inputq, dport); | 1927 | skb = tipc_skb_dequeue(inputq, dport); |
1843 | if (!skb) | 1928 | if (!skb) |
@@ -1905,6 +1990,11 @@ static int tipc_connect(struct socket *sock, struct sockaddr *dest, | |||
1905 | 1990 | ||
1906 | lock_sock(sk); | 1991 | lock_sock(sk); |
1907 | 1992 | ||
1993 | if (tsk->group) { | ||
1994 | res = -EINVAL; | ||
1995 | goto exit; | ||
1996 | } | ||
1997 | |||
1908 | if (dst->family == AF_UNSPEC) { | 1998 | if (dst->family == AF_UNSPEC) { |
1909 | memset(&tsk->peer, 0, sizeof(struct sockaddr_tipc)); | 1999 | memset(&tsk->peer, 0, sizeof(struct sockaddr_tipc)); |
1910 | if (!tipc_sk_type_connectionless(sk)) | 2000 | if (!tipc_sk_type_connectionless(sk)) |
@@ -2341,6 +2431,52 @@ void tipc_sk_rht_destroy(struct net *net) | |||
2341 | rhashtable_destroy(&tn->sk_rht); | 2431 | rhashtable_destroy(&tn->sk_rht); |
2342 | } | 2432 | } |
2343 | 2433 | ||
2434 | static int tipc_sk_join(struct tipc_sock *tsk, struct tipc_group_req *mreq) | ||
2435 | { | ||
2436 | struct net *net = sock_net(&tsk->sk); | ||
2437 | u32 domain = addr_domain(net, mreq->scope); | ||
2438 | struct tipc_group *grp = tsk->group; | ||
2439 | struct tipc_msg *hdr = &tsk->phdr; | ||
2440 | struct tipc_name_seq seq; | ||
2441 | int rc; | ||
2442 | |||
2443 | if (mreq->type < TIPC_RESERVED_TYPES) | ||
2444 | return -EACCES; | ||
2445 | if (grp) | ||
2446 | return -EACCES; | ||
2447 | grp = tipc_group_create(net, tsk->portid, mreq); | ||
2448 | if (!grp) | ||
2449 | return -ENOMEM; | ||
2450 | tsk->group = grp; | ||
2451 | msg_set_lookup_scope(hdr, mreq->scope); | ||
2452 | msg_set_nametype(hdr, mreq->type); | ||
2453 | msg_set_dest_droppable(hdr, true); | ||
2454 | seq.type = mreq->type; | ||
2455 | seq.lower = mreq->instance; | ||
2456 | seq.upper = seq.lower; | ||
2457 | tipc_nametbl_build_group(net, grp, mreq->type, domain); | ||
2458 | rc = tipc_sk_publish(tsk, mreq->scope, &seq); | ||
2459 | if (rc) | ||
2460 | tipc_group_delete(net, grp); | ||
2461 | return rc; | ||
2462 | } | ||
2463 | |||
2464 | static int tipc_sk_leave(struct tipc_sock *tsk) | ||
2465 | { | ||
2466 | struct net *net = sock_net(&tsk->sk); | ||
2467 | struct tipc_group *grp = tsk->group; | ||
2468 | struct tipc_name_seq seq; | ||
2469 | int scope; | ||
2470 | |||
2471 | if (!grp) | ||
2472 | return -EINVAL; | ||
2473 | tipc_group_self(grp, &seq, &scope); | ||
2474 | tipc_group_delete(net, grp); | ||
2475 | tsk->group = NULL; | ||
2476 | tipc_sk_withdraw(tsk, scope, &seq); | ||
2477 | return 0; | ||
2478 | } | ||
2479 | |||
2344 | /** | 2480 | /** |
2345 | * tipc_setsockopt - set socket option | 2481 | * tipc_setsockopt - set socket option |
2346 | * @sock: socket structure | 2482 | * @sock: socket structure |
@@ -2359,6 +2495,7 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt, | |||
2359 | { | 2495 | { |
2360 | struct sock *sk = sock->sk; | 2496 | struct sock *sk = sock->sk; |
2361 | struct tipc_sock *tsk = tipc_sk(sk); | 2497 | struct tipc_sock *tsk = tipc_sk(sk); |
2498 | struct tipc_group_req mreq; | ||
2362 | u32 value = 0; | 2499 | u32 value = 0; |
2363 | int res = 0; | 2500 | int res = 0; |
2364 | 2501 | ||
@@ -2374,9 +2511,14 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt, | |||
2374 | case TIPC_CONN_TIMEOUT: | 2511 | case TIPC_CONN_TIMEOUT: |
2375 | if (ol < sizeof(value)) | 2512 | if (ol < sizeof(value)) |
2376 | return -EINVAL; | 2513 | return -EINVAL; |
2377 | res = get_user(value, (u32 __user *)ov); | 2514 | if (get_user(value, (u32 __user *)ov)) |
2378 | if (res) | 2515 | return -EFAULT; |
2379 | return res; | 2516 | break; |
2517 | case TIPC_GROUP_JOIN: | ||
2518 | if (ol < sizeof(mreq)) | ||
2519 | return -EINVAL; | ||
2520 | if (copy_from_user(&mreq, ov, sizeof(mreq))) | ||
2521 | return -EFAULT; | ||
2380 | break; | 2522 | break; |
2381 | default: | 2523 | default: |
2382 | if (ov || ol) | 2524 | if (ov || ol) |
@@ -2409,6 +2551,12 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt, | |||
2409 | tsk->mc_method.rcast = true; | 2551 | tsk->mc_method.rcast = true; |
2410 | tsk->mc_method.mandatory = true; | 2552 | tsk->mc_method.mandatory = true; |
2411 | break; | 2553 | break; |
2554 | case TIPC_GROUP_JOIN: | ||
2555 | res = tipc_sk_join(tsk, &mreq); | ||
2556 | break; | ||
2557 | case TIPC_GROUP_LEAVE: | ||
2558 | res = tipc_sk_leave(tsk); | ||
2559 | break; | ||
2412 | default: | 2560 | default: |
2413 | res = -EINVAL; | 2561 | res = -EINVAL; |
2414 | } | 2562 | } |
@@ -2436,7 +2584,8 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt, | |||
2436 | { | 2584 | { |
2437 | struct sock *sk = sock->sk; | 2585 | struct sock *sk = sock->sk; |
2438 | struct tipc_sock *tsk = tipc_sk(sk); | 2586 | struct tipc_sock *tsk = tipc_sk(sk); |
2439 | int len; | 2587 | struct tipc_name_seq seq; |
2588 | int len, scope; | ||
2440 | u32 value; | 2589 | u32 value; |
2441 | int res; | 2590 | int res; |
2442 | 2591 | ||
@@ -2470,6 +2619,12 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt, | |||
2470 | case TIPC_SOCK_RECVQ_DEPTH: | 2619 | case TIPC_SOCK_RECVQ_DEPTH: |
2471 | value = skb_queue_len(&sk->sk_receive_queue); | 2620 | value = skb_queue_len(&sk->sk_receive_queue); |
2472 | break; | 2621 | break; |
2622 | case TIPC_GROUP_JOIN: | ||
2623 | seq.type = 0; | ||
2624 | if (tsk->group) | ||
2625 | tipc_group_self(tsk->group, &seq, &scope); | ||
2626 | value = seq.type; | ||
2627 | break; | ||
2473 | default: | 2628 | default: |
2474 | res = -EINVAL; | 2629 | res = -EINVAL; |
2475 | } | 2630 | } |