aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'net/llc/af_llc.c')
-rw-r--r--net/llc/af_llc.c59
1 files changed, 41 insertions, 18 deletions
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index d301ac51bbe1..1e20b719fb3c 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -98,8 +98,16 @@ static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr)
98{ 98{
99 u8 rc = LLC_PDU_LEN_U; 99 u8 rc = LLC_PDU_LEN_U;
100 100
101 if (addr->sllc_test || addr->sllc_xid) 101 if (addr->sllc_test)
102 rc = LLC_PDU_LEN_U; 102 rc = LLC_PDU_LEN_U;
103 else if (addr->sllc_xid)
104 /* We need to expand header to sizeof(struct llc_xid_info)
105 * since llc_pdu_init_as_xid_cmd() sets 4,5,6 bytes of LLC header
106 * as XID PDU. In llc_ui_sendmsg() we reserved header size and then
107 * filled all other space with user data. If we won't reserve this
108 * bytes, llc_pdu_init_as_xid_cmd() will overwrite user data
109 */
110 rc = LLC_PDU_LEN_U_XID;
103 else if (sk->sk_type == SOCK_STREAM) 111 else if (sk->sk_type == SOCK_STREAM)
104 rc = LLC_PDU_LEN_I; 112 rc = LLC_PDU_LEN_I;
105 return rc; 113 return rc;
@@ -268,6 +276,7 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
268{ 276{
269 struct sock *sk = sock->sk; 277 struct sock *sk = sock->sk;
270 struct llc_sock *llc = llc_sk(sk); 278 struct llc_sock *llc = llc_sk(sk);
279 struct net_device *dev = NULL;
271 struct llc_sap *sap; 280 struct llc_sap *sap;
272 int rc = -EINVAL; 281 int rc = -EINVAL;
273 282
@@ -279,14 +288,14 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
279 goto out; 288 goto out;
280 rc = -ENODEV; 289 rc = -ENODEV;
281 if (sk->sk_bound_dev_if) { 290 if (sk->sk_bound_dev_if) {
282 llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); 291 dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if);
283 if (llc->dev && addr->sllc_arphrd != llc->dev->type) { 292 if (dev && addr->sllc_arphrd != dev->type) {
284 dev_put(llc->dev); 293 dev_put(dev);
285 llc->dev = NULL; 294 dev = NULL;
286 } 295 }
287 } else 296 } else
288 llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd); 297 dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd);
289 if (!llc->dev) 298 if (!dev)
290 goto out; 299 goto out;
291 rc = -EUSERS; 300 rc = -EUSERS;
292 llc->laddr.lsap = llc_ui_autoport(); 301 llc->laddr.lsap = llc_ui_autoport();
@@ -296,6 +305,11 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
296 sap = llc_sap_open(llc->laddr.lsap, NULL); 305 sap = llc_sap_open(llc->laddr.lsap, NULL);
297 if (!sap) 306 if (!sap)
298 goto out; 307 goto out;
308
309 /* Note: We do not expect errors from this point. */
310 llc->dev = dev;
311 dev = NULL;
312
299 memcpy(llc->laddr.mac, llc->dev->dev_addr, IFHWADDRLEN); 313 memcpy(llc->laddr.mac, llc->dev->dev_addr, IFHWADDRLEN);
300 memcpy(&llc->addr, addr, sizeof(llc->addr)); 314 memcpy(&llc->addr, addr, sizeof(llc->addr));
301 /* assign new connection to its SAP */ 315 /* assign new connection to its SAP */
@@ -303,6 +317,7 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
303 sock_reset_flag(sk, SOCK_ZAPPED); 317 sock_reset_flag(sk, SOCK_ZAPPED);
304 rc = 0; 318 rc = 0;
305out: 319out:
320 dev_put(dev);
306 return rc; 321 return rc;
307} 322}
308 323
@@ -325,6 +340,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
325 struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr; 340 struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr;
326 struct sock *sk = sock->sk; 341 struct sock *sk = sock->sk;
327 struct llc_sock *llc = llc_sk(sk); 342 struct llc_sock *llc = llc_sk(sk);
343 struct net_device *dev = NULL;
328 struct llc_sap *sap; 344 struct llc_sap *sap;
329 int rc = -EINVAL; 345 int rc = -EINVAL;
330 346
@@ -341,25 +357,26 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
341 rc = -ENODEV; 357 rc = -ENODEV;
342 rcu_read_lock(); 358 rcu_read_lock();
343 if (sk->sk_bound_dev_if) { 359 if (sk->sk_bound_dev_if) {
344 llc->dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if); 360 dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if);
345 if (llc->dev) { 361 if (dev) {
346 if (is_zero_ether_addr(addr->sllc_mac)) 362 if (is_zero_ether_addr(addr->sllc_mac))
347 memcpy(addr->sllc_mac, llc->dev->dev_addr, 363 memcpy(addr->sllc_mac, dev->dev_addr,
348 IFHWADDRLEN); 364 IFHWADDRLEN);
349 if (addr->sllc_arphrd != llc->dev->type || 365 if (addr->sllc_arphrd != dev->type ||
350 !ether_addr_equal(addr->sllc_mac, 366 !ether_addr_equal(addr->sllc_mac,
351 llc->dev->dev_addr)) { 367 dev->dev_addr)) {
352 rc = -EINVAL; 368 rc = -EINVAL;
353 llc->dev = NULL; 369 dev = NULL;
354 } 370 }
355 } 371 }
356 } else 372 } else {
357 llc->dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd, 373 dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd,
358 addr->sllc_mac); 374 addr->sllc_mac);
359 if (llc->dev) 375 }
360 dev_hold(llc->dev); 376 if (dev)
377 dev_hold(dev);
361 rcu_read_unlock(); 378 rcu_read_unlock();
362 if (!llc->dev) 379 if (!dev)
363 goto out; 380 goto out;
364 if (!addr->sllc_sap) { 381 if (!addr->sllc_sap) {
365 rc = -EUSERS; 382 rc = -EUSERS;
@@ -392,6 +409,11 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
392 goto out_put; 409 goto out_put;
393 } 410 }
394 } 411 }
412
413 /* Note: We do not expect errors from this point. */
414 llc->dev = dev;
415 dev = NULL;
416
395 llc->laddr.lsap = addr->sllc_sap; 417 llc->laddr.lsap = addr->sllc_sap;
396 memcpy(llc->laddr.mac, addr->sllc_mac, IFHWADDRLEN); 418 memcpy(llc->laddr.mac, addr->sllc_mac, IFHWADDRLEN);
397 memcpy(&llc->addr, addr, sizeof(llc->addr)); 419 memcpy(&llc->addr, addr, sizeof(llc->addr));
@@ -402,6 +424,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
402out_put: 424out_put:
403 llc_sap_put(sap); 425 llc_sap_put(sap);
404out: 426out:
427 dev_put(dev);
405 release_sock(sk); 428 release_sock(sk);
406 return rc; 429 return rc;
407} 430}