aboutsummaryrefslogtreecommitdiffstats
path: root/net/llc/af_llc.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/llc/af_llc.c')
-rw-r--r--net/llc/af_llc.c74
1 files changed, 65 insertions, 9 deletions
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 7aa4fd170104..2db6a9f75913 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -25,6 +25,7 @@
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/rtnetlink.h> 26#include <linux/rtnetlink.h>
27#include <linux/init.h> 27#include <linux/init.h>
28#include <linux/slab.h>
28#include <net/llc.h> 29#include <net/llc.h>
29#include <net/llc_sap.h> 30#include <net/llc_sap.h>
30#include <net/llc_pdu.h> 31#include <net/llc_pdu.h>
@@ -47,6 +48,10 @@ static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout);
47#define dprintk(args...) 48#define dprintk(args...)
48#endif 49#endif
49 50
51/* Maybe we'll add some more in the future. */
52#define LLC_CMSG_PKTINFO 1
53
54
50/** 55/**
51 * llc_ui_next_link_no - return the next unused link number for a sap 56 * llc_ui_next_link_no - return the next unused link number for a sap
52 * @sap: Address of sap to get link number from. 57 * @sap: Address of sap to get link number from.
@@ -136,18 +141,22 @@ static struct proto llc_proto = {
136 .name = "LLC", 141 .name = "LLC",
137 .owner = THIS_MODULE, 142 .owner = THIS_MODULE,
138 .obj_size = sizeof(struct llc_sock), 143 .obj_size = sizeof(struct llc_sock),
144 .slab_flags = SLAB_DESTROY_BY_RCU,
139}; 145};
140 146
141/** 147/**
142 * llc_ui_create - alloc and init a new llc_ui socket 148 * llc_ui_create - alloc and init a new llc_ui socket
149 * @net: network namespace (must be default network)
143 * @sock: Socket to initialize and attach allocated sk to. 150 * @sock: Socket to initialize and attach allocated sk to.
144 * @protocol: Unused. 151 * @protocol: Unused.
152 * @kern: on behalf of kernel or userspace
145 * 153 *
146 * Allocate and initialize a new llc_ui socket, validate the user wants a 154 * Allocate and initialize a new llc_ui socket, validate the user wants a
147 * socket type we have available. 155 * socket type we have available.
148 * Returns 0 upon success, negative upon failure. 156 * Returns 0 upon success, negative upon failure.
149 */ 157 */
150static int llc_ui_create(struct net *net, struct socket *sock, int protocol) 158static int llc_ui_create(struct net *net, struct socket *sock, int protocol,
159 int kern)
151{ 160{
152 struct sock *sk; 161 struct sock *sk;
153 int rc = -ESOCKTNOSUPPORT; 162 int rc = -ESOCKTNOSUPPORT;
@@ -155,7 +164,7 @@ static int llc_ui_create(struct net *net, struct socket *sock, int protocol)
155 if (!capable(CAP_NET_RAW)) 164 if (!capable(CAP_NET_RAW))
156 return -EPERM; 165 return -EPERM;
157 166
158 if (net != &init_net) 167 if (!net_eq(net, &init_net))
159 return -EAFNOSUPPORT; 168 return -EAFNOSUPPORT;
160 169
161 if (likely(sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM)) { 170 if (likely(sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM)) {
@@ -189,10 +198,8 @@ static int llc_ui_release(struct socket *sock)
189 llc->laddr.lsap, llc->daddr.lsap); 198 llc->laddr.lsap, llc->daddr.lsap);
190 if (!llc_send_disc(sk)) 199 if (!llc_send_disc(sk))
191 llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); 200 llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo);
192 if (!sock_flag(sk, SOCK_ZAPPED)) { 201 if (!sock_flag(sk, SOCK_ZAPPED))
193 llc_sap_put(llc->sap);
194 llc_sap_remove_socket(llc->sap, sk); 202 llc_sap_remove_socket(llc->sap, sk);
195 }
196 release_sock(sk); 203 release_sock(sk);
197 if (llc->dev) 204 if (llc->dev)
198 dev_put(llc->dev); 205 dev_put(llc->dev);
@@ -252,7 +259,14 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
252 if (!sock_flag(sk, SOCK_ZAPPED)) 259 if (!sock_flag(sk, SOCK_ZAPPED))
253 goto out; 260 goto out;
254 rc = -ENODEV; 261 rc = -ENODEV;
255 llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd); 262 if (sk->sk_bound_dev_if) {
263 llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if);
264 if (llc->dev && addr->sllc_arphrd != llc->dev->type) {
265 dev_put(llc->dev);
266 llc->dev = NULL;
267 }
268 } else
269 llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd);
256 if (!llc->dev) 270 if (!llc->dev)
257 goto out; 271 goto out;
258 rc = -EUSERS; 272 rc = -EUSERS;
@@ -303,7 +317,25 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
303 goto out; 317 goto out;
304 rc = -ENODEV; 318 rc = -ENODEV;
305 rtnl_lock(); 319 rtnl_lock();
306 llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd, addr->sllc_mac); 320 if (sk->sk_bound_dev_if) {
321 llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if);
322 if (llc->dev) {
323 if (!addr->sllc_arphrd)
324 addr->sllc_arphrd = llc->dev->type;
325 if (llc_mac_null(addr->sllc_mac))
326 memcpy(addr->sllc_mac, llc->dev->dev_addr,
327 IFHWADDRLEN);
328 if (addr->sllc_arphrd != llc->dev->type ||
329 !llc_mac_match(addr->sllc_mac,
330 llc->dev->dev_addr)) {
331 rc = -EINVAL;
332 dev_put(llc->dev);
333 llc->dev = NULL;
334 }
335 }
336 } else
337 llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd,
338 addr->sllc_mac);
307 rtnl_unlock(); 339 rtnl_unlock();
308 if (!llc->dev) 340 if (!llc->dev)
309 goto out; 341 goto out;
@@ -319,7 +351,6 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
319 rc = -EBUSY; /* some other network layer is using the sap */ 351 rc = -EBUSY; /* some other network layer is using the sap */
320 if (!sap) 352 if (!sap)
321 goto out; 353 goto out;
322 llc_sap_hold(sap);
323 } else { 354 } else {
324 struct llc_addr laddr, daddr; 355 struct llc_addr laddr, daddr;
325 struct sock *ask; 356 struct sock *ask;
@@ -588,6 +619,20 @@ static int llc_wait_data(struct sock *sk, long timeo)
588 return rc; 619 return rc;
589} 620}
590 621
622static void llc_cmsg_rcv(struct msghdr *msg, struct sk_buff *skb)
623{
624 struct llc_sock *llc = llc_sk(skb->sk);
625
626 if (llc->cmsg_flags & LLC_CMSG_PKTINFO) {
627 struct llc_pktinfo info;
628
629 info.lpi_ifindex = llc_sk(skb->sk)->dev->ifindex;
630 llc_pdu_decode_dsap(skb, &info.lpi_sap);
631 llc_pdu_decode_da(skb, info.lpi_mac);
632 put_cmsg(msg, SOL_LLC, LLC_OPT_PKTINFO, sizeof(info), &info);
633 }
634}
635
591/** 636/**
592 * llc_ui_accept - accept a new incoming connection. 637 * llc_ui_accept - accept a new incoming connection.
593 * @sock: Socket which connections arrive on. 638 * @sock: Socket which connections arrive on.
@@ -809,6 +854,8 @@ copy_uaddr:
809 memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); 854 memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr));
810 msg->msg_namelen = sizeof(*uaddr); 855 msg->msg_namelen = sizeof(*uaddr);
811 } 856 }
857 if (llc_sk(sk)->cmsg_flags)
858 llc_cmsg_rcv(msg, skb);
812 goto out; 859 goto out;
813} 860}
814 861
@@ -1027,6 +1074,12 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname,
1027 goto out; 1074 goto out;
1028 llc->rw = opt; 1075 llc->rw = opt;
1029 break; 1076 break;
1077 case LLC_OPT_PKTINFO:
1078 if (opt)
1079 llc->cmsg_flags |= LLC_CMSG_PKTINFO;
1080 else
1081 llc->cmsg_flags &= ~LLC_CMSG_PKTINFO;
1082 break;
1030 default: 1083 default:
1031 rc = -ENOPROTOOPT; 1084 rc = -ENOPROTOOPT;
1032 goto out; 1085 goto out;
@@ -1080,6 +1133,9 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname,
1080 val = llc->k; break; 1133 val = llc->k; break;
1081 case LLC_OPT_RX_WIN: 1134 case LLC_OPT_RX_WIN:
1082 val = llc->rw; break; 1135 val = llc->rw; break;
1136 case LLC_OPT_PKTINFO:
1137 val = (llc->cmsg_flags & LLC_CMSG_PKTINFO) != 0;
1138 break;
1083 default: 1139 default:
1084 rc = -ENOPROTOOPT; 1140 rc = -ENOPROTOOPT;
1085 goto out; 1141 goto out;
@@ -1092,7 +1148,7 @@ out:
1092 return rc; 1148 return rc;
1093} 1149}
1094 1150
1095static struct net_proto_family llc_ui_family_ops = { 1151static const struct net_proto_family llc_ui_family_ops = {
1096 .family = PF_LLC, 1152 .family = PF_LLC,
1097 .create = llc_ui_create, 1153 .create = llc_ui_create,
1098 .owner = THIS_MODULE, 1154 .owner = THIS_MODULE,