diff options
Diffstat (limited to 'net/llc/af_llc.c')
-rw-r--r-- | net/llc/af_llc.c | 501 |
1 files changed, 302 insertions, 199 deletions
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 66f55e514b56..59d02cbbeb9e 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c | |||
@@ -21,6 +21,7 @@ | |||
21 | * See the GNU General Public License for more details. | 21 | * See the GNU General Public License for more details. |
22 | */ | 22 | */ |
23 | #include <linux/config.h> | 23 | #include <linux/config.h> |
24 | #include <linux/compiler.h> | ||
24 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
25 | #include <linux/module.h> | 26 | #include <linux/module.h> |
26 | #include <linux/rtnetlink.h> | 27 | #include <linux/rtnetlink.h> |
@@ -37,10 +38,9 @@ static u16 llc_ui_sap_link_no_max[256]; | |||
37 | static struct sockaddr_llc llc_ui_addrnull; | 38 | static struct sockaddr_llc llc_ui_addrnull; |
38 | static struct proto_ops llc_ui_ops; | 39 | static struct proto_ops llc_ui_ops; |
39 | 40 | ||
40 | static int llc_ui_wait_for_conn(struct sock *sk, int timeout); | 41 | static int llc_ui_wait_for_conn(struct sock *sk, long timeout); |
41 | static int llc_ui_wait_for_disc(struct sock *sk, int timeout); | 42 | static int llc_ui_wait_for_disc(struct sock *sk, long timeout); |
42 | static int llc_ui_wait_for_data(struct sock *sk, int timeout); | 43 | static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout); |
43 | static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout); | ||
44 | 44 | ||
45 | #if 0 | 45 | #if 0 |
46 | #define dprintk(args...) printk(KERN_DEBUG args) | 46 | #define dprintk(args...) printk(KERN_DEBUG args) |
@@ -116,12 +116,12 @@ static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb, int noblock) | |||
116 | struct llc_sock* llc = llc_sk(sk); | 116 | struct llc_sock* llc = llc_sk(sk); |
117 | int rc = 0; | 117 | int rc = 0; |
118 | 118 | ||
119 | if (llc_data_accept_state(llc->state) || llc->p_flag) { | 119 | if (unlikely(llc_data_accept_state(llc->state) || llc->p_flag)) { |
120 | int timeout = sock_sndtimeo(sk, noblock); | 120 | long timeout = sock_sndtimeo(sk, noblock); |
121 | 121 | ||
122 | rc = llc_ui_wait_for_busy_core(sk, timeout); | 122 | rc = llc_ui_wait_for_busy_core(sk, timeout); |
123 | } | 123 | } |
124 | if (!rc) | 124 | if (unlikely(!rc)) |
125 | rc = llc_build_and_send_pkt(sk, skb); | 125 | rc = llc_build_and_send_pkt(sk, skb); |
126 | return rc; | 126 | return rc; |
127 | } | 127 | } |
@@ -155,7 +155,7 @@ static int llc_ui_create(struct socket *sock, int protocol) | |||
155 | struct sock *sk; | 155 | struct sock *sk; |
156 | int rc = -ESOCKTNOSUPPORT; | 156 | int rc = -ESOCKTNOSUPPORT; |
157 | 157 | ||
158 | if (sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM) { | 158 | if (likely(sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM)) { |
159 | rc = -ENOMEM; | 159 | rc = -ENOMEM; |
160 | sk = llc_sk_alloc(PF_LLC, GFP_KERNEL, &llc_proto); | 160 | sk = llc_sk_alloc(PF_LLC, GFP_KERNEL, &llc_proto); |
161 | if (sk) { | 161 | if (sk) { |
@@ -177,7 +177,7 @@ static int llc_ui_release(struct socket *sock) | |||
177 | struct sock *sk = sock->sk; | 177 | struct sock *sk = sock->sk; |
178 | struct llc_sock *llc; | 178 | struct llc_sock *llc; |
179 | 179 | ||
180 | if (!sk) | 180 | if (unlikely(sk == NULL)) |
181 | goto out; | 181 | goto out; |
182 | sock_hold(sk); | 182 | sock_hold(sk); |
183 | lock_sock(sk); | 183 | lock_sock(sk); |
@@ -189,10 +189,6 @@ static int llc_ui_release(struct socket *sock) | |||
189 | if (!sock_flag(sk, SOCK_ZAPPED)) | 189 | if (!sock_flag(sk, SOCK_ZAPPED)) |
190 | llc_sap_remove_socket(llc->sap, sk); | 190 | llc_sap_remove_socket(llc->sap, sk); |
191 | release_sock(sk); | 191 | release_sock(sk); |
192 | if (llc->sap && hlist_empty(&llc->sap->sk_list.list)) { | ||
193 | llc_release_sockets(llc->sap); | ||
194 | llc_sap_close(llc->sap); | ||
195 | } | ||
196 | if (llc->dev) | 192 | if (llc->dev) |
197 | dev_put(llc->dev); | 193 | dev_put(llc->dev); |
198 | sock_put(sk); | 194 | sock_put(sk); |
@@ -221,6 +217,7 @@ static int llc_ui_autoport(void) | |||
221 | llc_ui_sap_last_autoport = i + 2; | 217 | llc_ui_sap_last_autoport = i + 2; |
222 | goto out; | 218 | goto out; |
223 | } | 219 | } |
220 | llc_sap_put(sap); | ||
224 | } | 221 | } |
225 | llc_ui_sap_last_autoport = LLC_SAP_DYN_START; | 222 | llc_ui_sap_last_autoport = LLC_SAP_DYN_START; |
226 | tries++; | 223 | tries++; |
@@ -231,20 +228,13 @@ out: | |||
231 | } | 228 | } |
232 | 229 | ||
233 | /** | 230 | /** |
234 | * llc_ui_autobind - Bind a socket to a specific address. | 231 | * llc_ui_autobind - automatically bind a socket to a sap |
235 | * @sk: Socket to bind an address to. | 232 | * @sock: socket to bind |
236 | * @addr: Address the user wants the socket bound to. | 233 | * @addr: address to connect to |
234 | * | ||
235 | * Used by llc_ui_connect and llc_ui_sendmsg when the user hasn't | ||
236 | * specifically used llc_ui_bind to bind to an specific address/sap | ||
237 | * | 237 | * |
238 | * Bind a socket to a specific address. For llc a user is able to bind to | ||
239 | * a specific sap only or mac + sap. If the user only specifies a sap and | ||
240 | * a null dmac (all zeros) the user is attempting to bind to an entire | ||
241 | * sap. This will stop anyone else on the local system from using that | ||
242 | * sap. If someone else has a mac + sap open the bind to null + sap will | ||
243 | * fail. | ||
244 | * If the user desires to bind to a specific mac + sap, it is possible to | ||
245 | * have multiple sap connections via multiple macs. | ||
246 | * Bind and autobind for that matter must enforce the correct sap usage | ||
247 | * otherwise all hell will break loose. | ||
248 | * Returns: 0 upon success, negative otherwise. | 238 | * Returns: 0 upon success, negative otherwise. |
249 | */ | 239 | */ |
250 | static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) | 240 | static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) |
@@ -285,11 +275,7 @@ out: | |||
285 | * @addrlen: Length of the uaddr structure. | 275 | * @addrlen: Length of the uaddr structure. |
286 | * | 276 | * |
287 | * Bind a socket to a specific address. For llc a user is able to bind to | 277 | * Bind a socket to a specific address. For llc a user is able to bind to |
288 | * a specific sap only or mac + sap. If the user only specifies a sap and | 278 | * a specific sap only or mac + sap. |
289 | * a null dmac (all zeros) the user is attempting to bind to an entire | ||
290 | * sap. This will stop anyone else on the local system from using that | ||
291 | * sap. If someone else has a mac + sap open the bind to null + sap will | ||
292 | * fail. | ||
293 | * If the user desires to bind to a specific mac + sap, it is possible to | 279 | * If the user desires to bind to a specific mac + sap, it is possible to |
294 | * have multiple sap connections via multiple macs. | 280 | * have multiple sap connections via multiple macs. |
295 | * Bind and autobind for that matter must enforce the correct sap usage | 281 | * Bind and autobind for that matter must enforce the correct sap usage |
@@ -305,10 +291,16 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) | |||
305 | int rc = -EINVAL; | 291 | int rc = -EINVAL; |
306 | 292 | ||
307 | dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_sap); | 293 | dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_sap); |
308 | if (!sock_flag(sk, SOCK_ZAPPED) || addrlen != sizeof(*addr)) | 294 | if (unlikely(!sock_flag(sk, SOCK_ZAPPED) || addrlen != sizeof(*addr))) |
309 | goto out; | 295 | goto out; |
310 | rc = -EAFNOSUPPORT; | 296 | rc = -EAFNOSUPPORT; |
311 | if (addr->sllc_family != AF_LLC) | 297 | if (unlikely(addr->sllc_family != AF_LLC)) |
298 | goto out; | ||
299 | rc = -ENODEV; | ||
300 | rtnl_lock(); | ||
301 | llc->dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_mac); | ||
302 | rtnl_unlock(); | ||
303 | if (!llc->dev) | ||
312 | goto out; | 304 | goto out; |
313 | if (!addr->sllc_sap) { | 305 | if (!addr->sllc_sap) { |
314 | rc = -EUSERS; | 306 | rc = -EUSERS; |
@@ -322,6 +314,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) | |||
322 | rc = -EBUSY; /* some other network layer is using the sap */ | 314 | rc = -EBUSY; /* some other network layer is using the sap */ |
323 | if (!sap) | 315 | if (!sap) |
324 | goto out; | 316 | goto out; |
317 | llc_sap_hold(sap); | ||
325 | } else { | 318 | } else { |
326 | struct llc_addr laddr, daddr; | 319 | struct llc_addr laddr, daddr; |
327 | struct sock *ask; | 320 | struct sock *ask; |
@@ -338,7 +331,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) | |||
338 | ask = llc_lookup_established(sap, &daddr, &laddr); | 331 | ask = llc_lookup_established(sap, &daddr, &laddr); |
339 | if (ask) { | 332 | if (ask) { |
340 | sock_put(ask); | 333 | sock_put(ask); |
341 | goto out; | 334 | goto out_put; |
342 | } | 335 | } |
343 | } | 336 | } |
344 | llc->laddr.lsap = addr->sllc_sap; | 337 | llc->laddr.lsap = addr->sllc_sap; |
@@ -348,6 +341,8 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) | |||
348 | llc_sap_add_socket(sap, sk); | 341 | llc_sap_add_socket(sap, sk); |
349 | sock_reset_flag(sk, SOCK_ZAPPED); | 342 | sock_reset_flag(sk, SOCK_ZAPPED); |
350 | rc = 0; | 343 | rc = 0; |
344 | out_put: | ||
345 | llc_sap_put(sap); | ||
351 | out: | 346 | out: |
352 | return rc; | 347 | return rc; |
353 | } | 348 | } |
@@ -369,7 +364,7 @@ static int llc_ui_shutdown(struct socket *sock, int how) | |||
369 | int rc = -ENOTCONN; | 364 | int rc = -ENOTCONN; |
370 | 365 | ||
371 | lock_sock(sk); | 366 | lock_sock(sk); |
372 | if (sk->sk_state != TCP_ESTABLISHED) | 367 | if (unlikely(sk->sk_state != TCP_ESTABLISHED)) |
373 | goto out; | 368 | goto out; |
374 | rc = -EINVAL; | 369 | rc = -EINVAL; |
375 | if (how != 2) | 370 | if (how != 2) |
@@ -404,14 +399,18 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr, | |||
404 | struct sock *sk = sock->sk; | 399 | struct sock *sk = sock->sk; |
405 | struct llc_sock *llc = llc_sk(sk); | 400 | struct llc_sock *llc = llc_sk(sk); |
406 | struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr; | 401 | struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr; |
407 | struct net_device *dev; | ||
408 | int rc = -EINVAL; | 402 | int rc = -EINVAL; |
409 | 403 | ||
410 | lock_sock(sk); | 404 | lock_sock(sk); |
411 | if (addrlen != sizeof(*addr)) | 405 | if (unlikely(addrlen != sizeof(*addr))) |
412 | goto out; | 406 | goto out; |
413 | rc = -EAFNOSUPPORT; | 407 | rc = -EAFNOSUPPORT; |
414 | if (addr->sllc_family != AF_LLC) | 408 | if (unlikely(addr->sllc_family != AF_LLC)) |
409 | goto out; | ||
410 | if (unlikely(sk->sk_type != SOCK_STREAM)) | ||
411 | goto out; | ||
412 | rc = -EALREADY; | ||
413 | if (unlikely(sock->state == SS_CONNECTING)) | ||
415 | goto out; | 414 | goto out; |
416 | /* bind connection to sap if user hasn't done it. */ | 415 | /* bind connection to sap if user hasn't done it. */ |
417 | if (sock_flag(sk, SOCK_ZAPPED)) { | 416 | if (sock_flag(sk, SOCK_ZAPPED)) { |
@@ -419,19 +418,13 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr, | |||
419 | rc = llc_ui_autobind(sock, addr); | 418 | rc = llc_ui_autobind(sock, addr); |
420 | if (rc) | 419 | if (rc) |
421 | goto out; | 420 | goto out; |
422 | llc->daddr.lsap = addr->sllc_sap; | ||
423 | memcpy(llc->daddr.mac, addr->sllc_mac, IFHWADDRLEN); | ||
424 | } | 421 | } |
425 | dev = llc->dev; | 422 | llc->daddr.lsap = addr->sllc_sap; |
426 | if (sk->sk_type != SOCK_STREAM) | 423 | memcpy(llc->daddr.mac, addr->sllc_mac, IFHWADDRLEN); |
427 | goto out; | ||
428 | rc = -EALREADY; | ||
429 | if (sock->state == SS_CONNECTING) | ||
430 | goto out; | ||
431 | sock->state = SS_CONNECTING; | 424 | sock->state = SS_CONNECTING; |
432 | sk->sk_state = TCP_SYN_SENT; | 425 | sk->sk_state = TCP_SYN_SENT; |
433 | llc->link = llc_ui_next_link_no(llc->sap->laddr.lsap); | 426 | llc->link = llc_ui_next_link_no(llc->sap->laddr.lsap); |
434 | rc = llc_establish_connection(sk, dev->dev_addr, | 427 | rc = llc_establish_connection(sk, llc->dev->dev_addr, |
435 | addr->sllc_mac, addr->sllc_sap); | 428 | addr->sllc_mac, addr->sllc_sap); |
436 | if (rc) { | 429 | if (rc) { |
437 | dprintk("%s: llc_ui_send_conn failed :-(\n", __FUNCTION__); | 430 | dprintk("%s: llc_ui_send_conn failed :-(\n", __FUNCTION__); |
@@ -439,12 +432,30 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr, | |||
439 | sk->sk_state = TCP_CLOSE; | 432 | sk->sk_state = TCP_CLOSE; |
440 | goto out; | 433 | goto out; |
441 | } | 434 | } |
442 | rc = llc_ui_wait_for_conn(sk, sk->sk_rcvtimeo); | 435 | |
443 | if (rc) | 436 | if (sk->sk_state == TCP_SYN_SENT) { |
444 | dprintk("%s: llc_ui_wait_for_conn failed=%d\n", __FUNCTION__, rc); | 437 | const long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); |
438 | |||
439 | if (!timeo || !llc_ui_wait_for_conn(sk, timeo)) | ||
440 | goto out; | ||
441 | |||
442 | rc = sock_intr_errno(timeo); | ||
443 | if (signal_pending(current)) | ||
444 | goto out; | ||
445 | } | ||
446 | |||
447 | if (sk->sk_state == TCP_CLOSE) | ||
448 | goto sock_error; | ||
449 | |||
450 | sock->state = SS_CONNECTED; | ||
451 | rc = 0; | ||
445 | out: | 452 | out: |
446 | release_sock(sk); | 453 | release_sock(sk); |
447 | return rc; | 454 | return rc; |
455 | sock_error: | ||
456 | rc = sock_error(sk) ? : -ECONNABORTED; | ||
457 | sock->state = SS_UNCONNECTED; | ||
458 | goto out; | ||
448 | } | 459 | } |
449 | 460 | ||
450 | /** | 461 | /** |
@@ -461,10 +472,10 @@ static int llc_ui_listen(struct socket *sock, int backlog) | |||
461 | int rc = -EINVAL; | 472 | int rc = -EINVAL; |
462 | 473 | ||
463 | lock_sock(sk); | 474 | lock_sock(sk); |
464 | if (sock->state != SS_UNCONNECTED) | 475 | if (unlikely(sock->state != SS_UNCONNECTED)) |
465 | goto out; | 476 | goto out; |
466 | rc = -EOPNOTSUPP; | 477 | rc = -EOPNOTSUPP; |
467 | if (sk->sk_type != SOCK_STREAM) | 478 | if (unlikely(sk->sk_type != SOCK_STREAM)) |
468 | goto out; | 479 | goto out; |
469 | rc = -EAGAIN; | 480 | rc = -EAGAIN; |
470 | if (sock_flag(sk, SOCK_ZAPPED)) | 481 | if (sock_flag(sk, SOCK_ZAPPED)) |
@@ -483,20 +494,14 @@ out: | |||
483 | return rc; | 494 | return rc; |
484 | } | 495 | } |
485 | 496 | ||
486 | static int llc_ui_wait_for_disc(struct sock *sk, int timeout) | 497 | static int llc_ui_wait_for_disc(struct sock *sk, long timeout) |
487 | { | 498 | { |
488 | DECLARE_WAITQUEUE(wait, current); | 499 | DEFINE_WAIT(wait); |
489 | int rc; | 500 | int rc = 0; |
490 | 501 | ||
491 | add_wait_queue_exclusive(sk->sk_sleep, &wait); | 502 | while (1) { |
492 | for (;;) { | 503 | prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); |
493 | __set_current_state(TASK_INTERRUPTIBLE); | 504 | if (sk_wait_event(sk, &timeout, sk->sk_state == TCP_CLOSE)) |
494 | rc = 0; | ||
495 | if (sk->sk_state != TCP_CLOSE) { | ||
496 | release_sock(sk); | ||
497 | timeout = schedule_timeout(timeout); | ||
498 | lock_sock(sk); | ||
499 | } else | ||
500 | break; | 505 | break; |
501 | rc = -ERESTARTSYS; | 506 | rc = -ERESTARTSYS; |
502 | if (signal_pending(current)) | 507 | if (signal_pending(current)) |
@@ -504,65 +509,40 @@ static int llc_ui_wait_for_disc(struct sock *sk, int timeout) | |||
504 | rc = -EAGAIN; | 509 | rc = -EAGAIN; |
505 | if (!timeout) | 510 | if (!timeout) |
506 | break; | 511 | break; |
512 | rc = 0; | ||
507 | } | 513 | } |
508 | __set_current_state(TASK_RUNNING); | 514 | finish_wait(sk->sk_sleep, &wait); |
509 | remove_wait_queue(sk->sk_sleep, &wait); | ||
510 | return rc; | 515 | return rc; |
511 | } | 516 | } |
512 | 517 | ||
513 | static int llc_ui_wait_for_conn(struct sock *sk, int timeout) | 518 | static int llc_ui_wait_for_conn(struct sock *sk, long timeout) |
514 | { | 519 | { |
515 | DECLARE_WAITQUEUE(wait, current); | 520 | DEFINE_WAIT(wait); |
516 | int rc; | ||
517 | 521 | ||
518 | add_wait_queue_exclusive(sk->sk_sleep, &wait); | 522 | while (1) { |
519 | for (;;) { | 523 | prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); |
520 | __set_current_state(TASK_INTERRUPTIBLE); | 524 | if (sk_wait_event(sk, &timeout, sk->sk_state != TCP_SYN_SENT)) |
521 | rc = -EAGAIN; | ||
522 | if (sk->sk_state == TCP_CLOSE) | ||
523 | break; | ||
524 | rc = 0; | ||
525 | if (sk->sk_state != TCP_ESTABLISHED) { | ||
526 | release_sock(sk); | ||
527 | timeout = schedule_timeout(timeout); | ||
528 | lock_sock(sk); | ||
529 | } else | ||
530 | break; | 525 | break; |
531 | rc = -ERESTARTSYS; | 526 | if (signal_pending(current) || !timeout) |
532 | if (signal_pending(current)) | ||
533 | break; | ||
534 | rc = -EAGAIN; | ||
535 | if (!timeout) | ||
536 | break; | 527 | break; |
537 | } | 528 | } |
538 | __set_current_state(TASK_RUNNING); | 529 | finish_wait(sk->sk_sleep, &wait); |
539 | remove_wait_queue(sk->sk_sleep, &wait); | 530 | return timeout; |
540 | return rc; | ||
541 | } | 531 | } |
542 | 532 | ||
543 | static int llc_ui_wait_for_data(struct sock *sk, int timeout) | 533 | static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout) |
544 | { | 534 | { |
545 | DECLARE_WAITQUEUE(wait, current); | 535 | DEFINE_WAIT(wait); |
546 | int rc = 0; | 536 | struct llc_sock *llc = llc_sk(sk); |
537 | int rc; | ||
547 | 538 | ||
548 | add_wait_queue_exclusive(sk->sk_sleep, &wait); | 539 | while (1) { |
549 | for (;;) { | 540 | prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); |
550 | __set_current_state(TASK_INTERRUPTIBLE); | ||
551 | if (sk->sk_shutdown & RCV_SHUTDOWN) | ||
552 | break; | ||
553 | /* | ||
554 | * Well, if we have backlog, try to process it now. | ||
555 | */ | ||
556 | if (sk->sk_backlog.tail) { | ||
557 | release_sock(sk); | ||
558 | lock_sock(sk); | ||
559 | } | ||
560 | rc = 0; | 541 | rc = 0; |
561 | if (skb_queue_empty(&sk->sk_receive_queue)) { | 542 | if (sk_wait_event(sk, &timeout, |
562 | release_sock(sk); | 543 | (sk->sk_shutdown & RCV_SHUTDOWN) || |
563 | timeout = schedule_timeout(timeout); | 544 | (!llc_data_accept_state(llc->state) && |
564 | lock_sock(sk); | 545 | !llc->p_flag))) |
565 | } else | ||
566 | break; | 546 | break; |
567 | rc = -ERESTARTSYS; | 547 | rc = -ERESTARTSYS; |
568 | if (signal_pending(current)) | 548 | if (signal_pending(current)) |
@@ -571,40 +551,35 @@ static int llc_ui_wait_for_data(struct sock *sk, int timeout) | |||
571 | if (!timeout) | 551 | if (!timeout) |
572 | break; | 552 | break; |
573 | } | 553 | } |
574 | __set_current_state(TASK_RUNNING); | 554 | finish_wait(sk->sk_sleep, &wait); |
575 | remove_wait_queue(sk->sk_sleep, &wait); | ||
576 | return rc; | 555 | return rc; |
577 | } | 556 | } |
578 | 557 | ||
579 | static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout) | 558 | static int llc_wait_data(struct sock *sk, long timeo) |
580 | { | 559 | { |
581 | DECLARE_WAITQUEUE(wait, current); | ||
582 | struct llc_sock *llc = llc_sk(sk); | ||
583 | int rc; | 560 | int rc; |
584 | 561 | ||
585 | add_wait_queue_exclusive(sk->sk_sleep, &wait); | 562 | while (1) { |
586 | for (;;) { | 563 | /* |
587 | dprintk("%s: looping...\n", __FUNCTION__); | 564 | * POSIX 1003.1g mandates this order. |
588 | __set_current_state(TASK_INTERRUPTIBLE); | 565 | */ |
589 | rc = -ENOTCONN; | 566 | if (sk->sk_err) { |
590 | if (sk->sk_shutdown & RCV_SHUTDOWN) | 567 | rc = sock_error(sk); |
591 | break; | 568 | break; |
569 | } | ||
592 | rc = 0; | 570 | rc = 0; |
593 | if (llc_data_accept_state(llc->state) || llc->p_flag) { | 571 | if (sk->sk_shutdown & RCV_SHUTDOWN) |
594 | release_sock(sk); | ||
595 | timeout = schedule_timeout(timeout); | ||
596 | lock_sock(sk); | ||
597 | } else | ||
598 | break; | 572 | break; |
599 | rc = -ERESTARTSYS; | 573 | rc = -EAGAIN; |
574 | if (!timeo) | ||
575 | break; | ||
576 | rc = sock_intr_errno(timeo); | ||
600 | if (signal_pending(current)) | 577 | if (signal_pending(current)) |
601 | break; | 578 | break; |
602 | rc = -EAGAIN; | 579 | rc = 0; |
603 | if (!timeout) | 580 | if (sk_wait_data(sk, &timeo)) |
604 | break; | 581 | break; |
605 | } | 582 | } |
606 | __set_current_state(TASK_RUNNING); | ||
607 | remove_wait_queue(sk->sk_sleep, &wait); | ||
608 | return rc; | 583 | return rc; |
609 | } | 584 | } |
610 | 585 | ||
@@ -627,15 +602,18 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags) | |||
627 | dprintk("%s: accepting on %02X\n", __FUNCTION__, | 602 | dprintk("%s: accepting on %02X\n", __FUNCTION__, |
628 | llc_sk(sk)->laddr.lsap); | 603 | llc_sk(sk)->laddr.lsap); |
629 | lock_sock(sk); | 604 | lock_sock(sk); |
630 | if (sk->sk_type != SOCK_STREAM) | 605 | if (unlikely(sk->sk_type != SOCK_STREAM)) |
631 | goto out; | 606 | goto out; |
632 | rc = -EINVAL; | 607 | rc = -EINVAL; |
633 | if (sock->state != SS_UNCONNECTED || sk->sk_state != TCP_LISTEN) | 608 | if (unlikely(sock->state != SS_UNCONNECTED || |
609 | sk->sk_state != TCP_LISTEN)) | ||
634 | goto out; | 610 | goto out; |
635 | /* wait for a connection to arrive. */ | 611 | /* wait for a connection to arrive. */ |
636 | rc = llc_ui_wait_for_data(sk, sk->sk_rcvtimeo); | 612 | if (skb_queue_empty(&sk->sk_receive_queue)) { |
637 | if (rc) | 613 | rc = llc_wait_data(sk, sk->sk_rcvtimeo); |
638 | goto out; | 614 | if (rc) |
615 | goto out; | ||
616 | } | ||
639 | dprintk("%s: got a new connection on %02X\n", __FUNCTION__, | 617 | dprintk("%s: got a new connection on %02X\n", __FUNCTION__, |
640 | llc_sk(sk)->laddr.lsap); | 618 | llc_sk(sk)->laddr.lsap); |
641 | skb = skb_dequeue(&sk->sk_receive_queue); | 619 | skb = skb_dequeue(&sk->sk_receive_queue); |
@@ -657,7 +635,6 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags) | |||
657 | /* put original socket back into a clean listen state. */ | 635 | /* put original socket back into a clean listen state. */ |
658 | sk->sk_state = TCP_LISTEN; | 636 | sk->sk_state = TCP_LISTEN; |
659 | sk->sk_ack_backlog--; | 637 | sk->sk_ack_backlog--; |
660 | skb->sk = NULL; | ||
661 | dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__, | 638 | dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__, |
662 | llc_sk(sk)->addr.sllc_sap, newllc->daddr.lsap); | 639 | llc_sk(sk)->addr.sllc_sap, newllc->daddr.lsap); |
663 | frees: | 640 | frees: |
@@ -671,56 +648,167 @@ out: | |||
671 | * llc_ui_recvmsg - copy received data to the socket user. | 648 | * llc_ui_recvmsg - copy received data to the socket user. |
672 | * @sock: Socket to copy data from. | 649 | * @sock: Socket to copy data from. |
673 | * @msg: Various user space related information. | 650 | * @msg: Various user space related information. |
674 | * @size: Size of user buffer. | 651 | * @len: Size of user buffer. |
675 | * @flags: User specified flags. | 652 | * @flags: User specified flags. |
676 | * | 653 | * |
677 | * Copy received data to the socket user. | 654 | * Copy received data to the socket user. |
678 | * Returns non-negative upon success, negative otherwise. | 655 | * Returns non-negative upon success, negative otherwise. |
679 | */ | 656 | */ |
680 | static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, | 657 | static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, |
681 | struct msghdr *msg, size_t size, int flags) | 658 | struct msghdr *msg, size_t len, int flags) |
682 | { | 659 | { |
683 | struct sock *sk = sock->sk; | ||
684 | struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name; | 660 | struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name; |
685 | struct sk_buff *skb; | 661 | const int nonblock = flags & MSG_DONTWAIT; |
662 | struct sk_buff *skb = NULL; | ||
663 | struct sock *sk = sock->sk; | ||
664 | struct llc_sock *llc = llc_sk(sk); | ||
686 | size_t copied = 0; | 665 | size_t copied = 0; |
687 | int rc = -ENOMEM, timeout; | 666 | u32 peek_seq = 0; |
688 | int noblock = flags & MSG_DONTWAIT; | 667 | u32 *seq; |
668 | unsigned long used; | ||
669 | int target; /* Read at least this many bytes */ | ||
670 | long timeo; | ||
689 | 671 | ||
690 | dprintk("%s: receiving in %02X from %02X\n", __FUNCTION__, | ||
691 | llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap); | ||
692 | lock_sock(sk); | 672 | lock_sock(sk); |
693 | timeout = sock_rcvtimeo(sk, noblock); | 673 | copied = -ENOTCONN; |
694 | rc = llc_ui_wait_for_data(sk, timeout); | 674 | if (sk->sk_state == TCP_LISTEN) |
695 | if (rc) { | ||
696 | dprintk("%s: llc_ui_wait_for_data failed recv " | ||
697 | "in %02X from %02X\n", __FUNCTION__, | ||
698 | llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap); | ||
699 | goto out; | 675 | goto out; |
700 | } | 676 | |
701 | skb = skb_dequeue(&sk->sk_receive_queue); | 677 | timeo = sock_rcvtimeo(sk, nonblock); |
702 | if (!skb) /* shutdown */ | 678 | |
703 | goto out; | 679 | seq = &llc->copied_seq; |
704 | copied = skb->len; | 680 | if (flags & MSG_PEEK) { |
705 | if (copied > size) | 681 | peek_seq = llc->copied_seq; |
706 | copied = size; | 682 | seq = &peek_seq; |
707 | rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); | 683 | } |
708 | if (rc) | 684 | |
709 | goto dgram_free; | 685 | target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); |
710 | if (skb->len > copied) { | 686 | copied = 0; |
711 | skb_pull(skb, copied); | 687 | |
712 | skb_queue_head(&sk->sk_receive_queue, skb); | 688 | do { |
713 | } | 689 | u32 offset; |
714 | if (uaddr) | 690 | |
715 | memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); | 691 | /* |
716 | msg->msg_namelen = sizeof(*uaddr); | 692 | * We need to check signals first, to get correct SIGURG |
717 | if (!skb->next) { | 693 | * handling. FIXME: Need to check this doesn't impact 1003.1g |
718 | dgram_free: | 694 | * and move it down to the bottom of the loop |
719 | kfree_skb(skb); | 695 | */ |
720 | } | 696 | if (signal_pending(current)) { |
697 | if (copied) | ||
698 | break; | ||
699 | copied = timeo ? sock_intr_errno(timeo) : -EAGAIN; | ||
700 | break; | ||
701 | } | ||
702 | |||
703 | /* Next get a buffer. */ | ||
704 | |||
705 | skb = skb_peek(&sk->sk_receive_queue); | ||
706 | if (skb) { | ||
707 | offset = *seq; | ||
708 | goto found_ok_skb; | ||
709 | } | ||
710 | /* Well, if we have backlog, try to process it now yet. */ | ||
711 | |||
712 | if (copied >= target && !sk->sk_backlog.tail) | ||
713 | break; | ||
714 | |||
715 | if (copied) { | ||
716 | if (sk->sk_err || | ||
717 | sk->sk_state == TCP_CLOSE || | ||
718 | (sk->sk_shutdown & RCV_SHUTDOWN) || | ||
719 | !timeo || | ||
720 | (flags & MSG_PEEK)) | ||
721 | break; | ||
722 | } else { | ||
723 | if (sock_flag(sk, SOCK_DONE)) | ||
724 | break; | ||
725 | |||
726 | if (sk->sk_err) { | ||
727 | copied = sock_error(sk); | ||
728 | break; | ||
729 | } | ||
730 | if (sk->sk_shutdown & RCV_SHUTDOWN) | ||
731 | break; | ||
732 | |||
733 | if (sk->sk_state == TCP_CLOSE) { | ||
734 | if (!sock_flag(sk, SOCK_DONE)) { | ||
735 | /* | ||
736 | * This occurs when user tries to read | ||
737 | * from never connected socket. | ||
738 | */ | ||
739 | copied = -ENOTCONN; | ||
740 | break; | ||
741 | } | ||
742 | break; | ||
743 | } | ||
744 | if (!timeo) { | ||
745 | copied = -EAGAIN; | ||
746 | break; | ||
747 | } | ||
748 | } | ||
749 | |||
750 | if (copied >= target) { /* Do not sleep, just process backlog. */ | ||
751 | release_sock(sk); | ||
752 | lock_sock(sk); | ||
753 | } else | ||
754 | sk_wait_data(sk, &timeo); | ||
755 | |||
756 | if ((flags & MSG_PEEK) && peek_seq != llc->copied_seq) { | ||
757 | if (net_ratelimit()) | ||
758 | printk(KERN_DEBUG "LLC(%s:%d): Application " | ||
759 | "bug, race in MSG_PEEK.\n", | ||
760 | current->comm, current->pid); | ||
761 | peek_seq = llc->copied_seq; | ||
762 | } | ||
763 | continue; | ||
764 | found_ok_skb: | ||
765 | /* Ok so how much can we use? */ | ||
766 | used = skb->len - offset; | ||
767 | if (len < used) | ||
768 | used = len; | ||
769 | |||
770 | if (!(flags & MSG_TRUNC)) { | ||
771 | int rc = skb_copy_datagram_iovec(skb, offset, | ||
772 | msg->msg_iov, used); | ||
773 | if (rc) { | ||
774 | /* Exception. Bailout! */ | ||
775 | if (!copied) | ||
776 | copied = -EFAULT; | ||
777 | break; | ||
778 | } | ||
779 | } | ||
780 | |||
781 | *seq += used; | ||
782 | copied += used; | ||
783 | len -= used; | ||
784 | |||
785 | if (used + offset < skb->len) | ||
786 | continue; | ||
787 | |||
788 | if (!(flags & MSG_PEEK)) { | ||
789 | sk_eat_skb(sk, skb); | ||
790 | *seq = 0; | ||
791 | } | ||
792 | } while (len > 0); | ||
793 | |||
794 | /* | ||
795 | * According to UNIX98, msg_name/msg_namelen are ignored | ||
796 | * on connected socket. -ANK | ||
797 | * But... af_llc still doesn't have separate sets of methods for | ||
798 | * SOCK_DGRAM and SOCK_STREAM :-( So we have to do this test, will | ||
799 | * eventually fix this tho :-) -acme | ||
800 | */ | ||
801 | if (sk->sk_type == SOCK_DGRAM) | ||
802 | goto copy_uaddr; | ||
721 | out: | 803 | out: |
722 | release_sock(sk); | 804 | release_sock(sk); |
723 | return rc ? : copied; | 805 | return copied; |
806 | copy_uaddr: | ||
807 | if (uaddr != NULL && skb != NULL) { | ||
808 | memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); | ||
809 | msg->msg_namelen = sizeof(*uaddr); | ||
810 | } | ||
811 | goto out; | ||
724 | } | 812 | } |
725 | 813 | ||
726 | /** | 814 | /** |
@@ -740,7 +828,6 @@ static int llc_ui_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
740 | struct sockaddr_llc *addr = (struct sockaddr_llc *)msg->msg_name; | 828 | struct sockaddr_llc *addr = (struct sockaddr_llc *)msg->msg_name; |
741 | int flags = msg->msg_flags; | 829 | int flags = msg->msg_flags; |
742 | int noblock = flags & MSG_DONTWAIT; | 830 | int noblock = flags & MSG_DONTWAIT; |
743 | struct net_device *dev; | ||
744 | struct sk_buff *skb; | 831 | struct sk_buff *skb; |
745 | size_t size = 0; | 832 | size_t size = 0; |
746 | int rc = -EINVAL, copied = 0, hdrlen; | 833 | int rc = -EINVAL, copied = 0, hdrlen; |
@@ -763,19 +850,17 @@ static int llc_ui_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
763 | if (rc) | 850 | if (rc) |
764 | goto release; | 851 | goto release; |
765 | } | 852 | } |
766 | dev = llc->dev; | 853 | hdrlen = llc->dev->hard_header_len + llc_ui_header_len(sk, addr); |
767 | hdrlen = dev->hard_header_len + llc_ui_header_len(sk, addr); | ||
768 | size = hdrlen + len; | 854 | size = hdrlen + len; |
769 | if (size > dev->mtu) | 855 | if (size > llc->dev->mtu) |
770 | size = dev->mtu; | 856 | size = llc->dev->mtu; |
771 | copied = size - hdrlen; | 857 | copied = size - hdrlen; |
772 | release_sock(sk); | 858 | release_sock(sk); |
773 | skb = sock_alloc_send_skb(sk, size, noblock, &rc); | 859 | skb = sock_alloc_send_skb(sk, size, noblock, &rc); |
774 | lock_sock(sk); | 860 | lock_sock(sk); |
775 | if (!skb) | 861 | if (!skb) |
776 | goto release; | 862 | goto release; |
777 | skb->sk = sk; | 863 | skb->dev = llc->dev; |
778 | skb->dev = dev; | ||
779 | skb->protocol = llc_proto_type(addr->sllc_arphrd); | 864 | skb->protocol = llc_proto_type(addr->sllc_arphrd); |
780 | skb_reserve(skb, hdrlen); | 865 | skb_reserve(skb, hdrlen); |
781 | rc = memcpy_fromiovec(skb_put(skb, copied), msg->msg_iov, copied); | 866 | rc = memcpy_fromiovec(skb_put(skb, copied), msg->msg_iov, copied); |
@@ -800,15 +885,13 @@ static int llc_ui_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
800 | if (!(sk->sk_type == SOCK_STREAM && !addr->sllc_ua)) | 885 | if (!(sk->sk_type == SOCK_STREAM && !addr->sllc_ua)) |
801 | goto out; | 886 | goto out; |
802 | rc = llc_ui_send_data(sk, skb, noblock); | 887 | rc = llc_ui_send_data(sk, skb, noblock); |
803 | if (rc) | ||
804 | dprintk("%s: llc_ui_send_data failed: %d\n", __FUNCTION__, rc); | ||
805 | out: | 888 | out: |
806 | if (rc) | 889 | if (rc) { |
807 | kfree_skb(skb); | 890 | kfree_skb(skb); |
808 | release: | 891 | release: |
809 | if (rc) | ||
810 | dprintk("%s: failed sending from %02X to %02X: %d\n", | 892 | dprintk("%s: failed sending from %02X to %02X: %d\n", |
811 | __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap, rc); | 893 | __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap, rc); |
894 | } | ||
812 | release_sock(sk); | 895 | release_sock(sk); |
813 | return rc ? : copied; | 896 | return rc ? : copied; |
814 | } | 897 | } |
@@ -895,7 +978,7 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname, | |||
895 | int rc = -EINVAL, opt; | 978 | int rc = -EINVAL, opt; |
896 | 979 | ||
897 | lock_sock(sk); | 980 | lock_sock(sk); |
898 | if (level != SOL_LLC || optlen != sizeof(int)) | 981 | if (unlikely(level != SOL_LLC || optlen != sizeof(int))) |
899 | goto out; | 982 | goto out; |
900 | rc = get_user(opt, (int __user *)optval); | 983 | rc = get_user(opt, (int __user *)optval); |
901 | if (rc) | 984 | if (rc) |
@@ -915,22 +998,22 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname, | |||
915 | case LLC_OPT_ACK_TMR_EXP: | 998 | case LLC_OPT_ACK_TMR_EXP: |
916 | if (opt > LLC_OPT_MAX_ACK_TMR_EXP) | 999 | if (opt > LLC_OPT_MAX_ACK_TMR_EXP) |
917 | goto out; | 1000 | goto out; |
918 | llc->ack_timer.expire = opt; | 1001 | llc->ack_timer.expire = opt * HZ; |
919 | break; | 1002 | break; |
920 | case LLC_OPT_P_TMR_EXP: | 1003 | case LLC_OPT_P_TMR_EXP: |
921 | if (opt > LLC_OPT_MAX_P_TMR_EXP) | 1004 | if (opt > LLC_OPT_MAX_P_TMR_EXP) |
922 | goto out; | 1005 | goto out; |
923 | llc->pf_cycle_timer.expire = opt; | 1006 | llc->pf_cycle_timer.expire = opt * HZ; |
924 | break; | 1007 | break; |
925 | case LLC_OPT_REJ_TMR_EXP: | 1008 | case LLC_OPT_REJ_TMR_EXP: |
926 | if (opt > LLC_OPT_MAX_REJ_TMR_EXP) | 1009 | if (opt > LLC_OPT_MAX_REJ_TMR_EXP) |
927 | goto out; | 1010 | goto out; |
928 | llc->rej_sent_timer.expire = opt; | 1011 | llc->rej_sent_timer.expire = opt * HZ; |
929 | break; | 1012 | break; |
930 | case LLC_OPT_BUSY_TMR_EXP: | 1013 | case LLC_OPT_BUSY_TMR_EXP: |
931 | if (opt > LLC_OPT_MAX_BUSY_TMR_EXP) | 1014 | if (opt > LLC_OPT_MAX_BUSY_TMR_EXP) |
932 | goto out; | 1015 | goto out; |
933 | llc->busy_state_timer.expire = opt; | 1016 | llc->busy_state_timer.expire = opt * HZ; |
934 | break; | 1017 | break; |
935 | case LLC_OPT_TX_WIN: | 1018 | case LLC_OPT_TX_WIN: |
936 | if (opt > LLC_OPT_MAX_WIN) | 1019 | if (opt > LLC_OPT_MAX_WIN) |
@@ -970,7 +1053,7 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname, | |||
970 | int val = 0, len = 0, rc = -EINVAL; | 1053 | int val = 0, len = 0, rc = -EINVAL; |
971 | 1054 | ||
972 | lock_sock(sk); | 1055 | lock_sock(sk); |
973 | if (level != SOL_LLC) | 1056 | if (unlikely(level != SOL_LLC)) |
974 | goto out; | 1057 | goto out; |
975 | rc = get_user(len, optlen); | 1058 | rc = get_user(len, optlen); |
976 | if (rc) | 1059 | if (rc) |
@@ -980,17 +1063,17 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname, | |||
980 | goto out; | 1063 | goto out; |
981 | switch (optname) { | 1064 | switch (optname) { |
982 | case LLC_OPT_RETRY: | 1065 | case LLC_OPT_RETRY: |
983 | val = llc->n2; break; | 1066 | val = llc->n2; break; |
984 | case LLC_OPT_SIZE: | 1067 | case LLC_OPT_SIZE: |
985 | val = llc->n1; break; | 1068 | val = llc->n1; break; |
986 | case LLC_OPT_ACK_TMR_EXP: | 1069 | case LLC_OPT_ACK_TMR_EXP: |
987 | val = llc->ack_timer.expire; break; | 1070 | val = llc->ack_timer.expire / HZ; break; |
988 | case LLC_OPT_P_TMR_EXP: | 1071 | case LLC_OPT_P_TMR_EXP: |
989 | val = llc->pf_cycle_timer.expire; break; | 1072 | val = llc->pf_cycle_timer.expire / HZ; break; |
990 | case LLC_OPT_REJ_TMR_EXP: | 1073 | case LLC_OPT_REJ_TMR_EXP: |
991 | val = llc->rej_sent_timer.expire; break; | 1074 | val = llc->rej_sent_timer.expire / HZ; break; |
992 | case LLC_OPT_BUSY_TMR_EXP: | 1075 | case LLC_OPT_BUSY_TMR_EXP: |
993 | val = llc->busy_state_timer.expire; break; | 1076 | val = llc->busy_state_timer.expire / HZ; break; |
994 | case LLC_OPT_TX_WIN: | 1077 | case LLC_OPT_TX_WIN: |
995 | val = llc->k; break; | 1078 | val = llc->k; break; |
996 | case LLC_OPT_RX_WIN: | 1079 | case LLC_OPT_RX_WIN: |
@@ -1034,8 +1117,12 @@ static struct proto_ops llc_ui_ops = { | |||
1034 | .sendpage = sock_no_sendpage, | 1117 | .sendpage = sock_no_sendpage, |
1035 | }; | 1118 | }; |
1036 | 1119 | ||
1037 | extern void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb); | 1120 | static char llc_proc_err_msg[] __initdata = |
1038 | extern void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb); | 1121 | KERN_CRIT "LLC: Unable to register the proc_fs entries\n"; |
1122 | static char llc_sysctl_err_msg[] __initdata = | ||
1123 | KERN_CRIT "LLC: Unable to register the sysctl entries\n"; | ||
1124 | static char llc_sock_err_msg[] __initdata = | ||
1125 | KERN_CRIT "LLC: Unable to register the network family\n"; | ||
1039 | 1126 | ||
1040 | static int __init llc2_init(void) | 1127 | static int __init llc2_init(void) |
1041 | { | 1128 | { |
@@ -1048,13 +1135,28 @@ static int __init llc2_init(void) | |||
1048 | llc_station_init(); | 1135 | llc_station_init(); |
1049 | llc_ui_sap_last_autoport = LLC_SAP_DYN_START; | 1136 | llc_ui_sap_last_autoport = LLC_SAP_DYN_START; |
1050 | rc = llc_proc_init(); | 1137 | rc = llc_proc_init(); |
1051 | if (rc != 0) | 1138 | if (rc != 0) { |
1139 | printk(llc_proc_err_msg); | ||
1052 | goto out_unregister_llc_proto; | 1140 | goto out_unregister_llc_proto; |
1053 | sock_register(&llc_ui_family_ops); | 1141 | } |
1142 | rc = llc_sysctl_init(); | ||
1143 | if (rc) { | ||
1144 | printk(llc_sysctl_err_msg); | ||
1145 | goto out_proc; | ||
1146 | } | ||
1147 | rc = sock_register(&llc_ui_family_ops); | ||
1148 | if (rc) { | ||
1149 | printk(llc_sock_err_msg); | ||
1150 | goto out_sysctl; | ||
1151 | } | ||
1054 | llc_add_pack(LLC_DEST_SAP, llc_sap_handler); | 1152 | llc_add_pack(LLC_DEST_SAP, llc_sap_handler); |
1055 | llc_add_pack(LLC_DEST_CONN, llc_conn_handler); | 1153 | llc_add_pack(LLC_DEST_CONN, llc_conn_handler); |
1056 | out: | 1154 | out: |
1057 | return rc; | 1155 | return rc; |
1156 | out_sysctl: | ||
1157 | llc_sysctl_exit(); | ||
1158 | out_proc: | ||
1159 | llc_proc_exit(); | ||
1058 | out_unregister_llc_proto: | 1160 | out_unregister_llc_proto: |
1059 | proto_unregister(&llc_proto); | 1161 | proto_unregister(&llc_proto); |
1060 | goto out; | 1162 | goto out; |
@@ -1067,6 +1169,7 @@ static void __exit llc2_exit(void) | |||
1067 | llc_remove_pack(LLC_DEST_CONN); | 1169 | llc_remove_pack(LLC_DEST_CONN); |
1068 | sock_unregister(PF_LLC); | 1170 | sock_unregister(PF_LLC); |
1069 | llc_proc_exit(); | 1171 | llc_proc_exit(); |
1172 | llc_sysctl_exit(); | ||
1070 | proto_unregister(&llc_proto); | 1173 | proto_unregister(&llc_proto); |
1071 | } | 1174 | } |
1072 | 1175 | ||