| 1 | |
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
| 7 |
|
| 8 | #include <linux/module.h>
|
| 9 | #include <linux/kmod.h>
|
| 10 | #include <linux/net.h>
|
| 11 | #include <linux/atm.h>
|
| 12 | #include <linux/atmdev.h>
|
| 13 | #include <linux/socket.h>
|
| 14 | #include <linux/errno.h>
|
| 15 | #include <linux/capability.h>
|
| 16 | #include <linux/mm.h>
|
| 17 | #include <linux/sched/signal.h>
|
| 18 | #include <linux/time64.h>
|
| 19 | #include <linux/skbuff.h>
|
| 20 | #include <linux/bitops.h>
|
| 21 | #include <linux/init.h>
|
| 22 | #include <linux/slab.h>
|
| 23 | #include <net/sock.h>
|
| 24 | #include <linux/uaccess.h>
|
| 25 | #include <linux/poll.h>
|
| 26 | #include <linux/uio.h>
|
| 27 |
|
| 28 | #include <linux/atomic.h>
|
| 29 |
|
| 30 | #include "resources.h"
|
| 31 | #include "common.h"
|
| 32 | #include "protocols.h"
|
| 33 |
|
| 34 | struct hlist_head vcc_hash[VCC_HTABLE_SIZE];
|
| 35 | EXPORT_SYMBOL(vcc_hash);
|
| 36 |
|
| 37 | DEFINE_RWLOCK(vcc_sklist_lock);
|
| 38 | EXPORT_SYMBOL(vcc_sklist_lock);
|
| 39 |
|
| 40 | static ATOMIC_NOTIFIER_HEAD(atm_dev_notify_chain);
|
| 41 |
|
| 42 | static void __vcc_insert_socket(struct sock *sk)
|
| 43 | {
|
| 44 | struct atm_vcc *vcc = atm_sk(sk);
|
| 45 | struct hlist_head *head = &vcc_hash[vcc->vci & (VCC_HTABLE_SIZE - 1)];
|
| 46 | sk->sk_hash = vcc->vci & (VCC_HTABLE_SIZE - 1);
|
| 47 | sk_add_node(sk, head);
|
| 48 | }
|
| 49 |
|
| 50 | void vcc_insert_socket(struct sock *sk)
|
| 51 | {
|
| 52 | write_lock_irq(&vcc_sklist_lock);
|
| 53 | __vcc_insert_socket(sk);
|
| 54 | write_unlock_irq(&vcc_sklist_lock);
|
| 55 | }
|
| 56 | EXPORT_SYMBOL(vcc_insert_socket);
|
| 57 |
|
| 58 | static void vcc_remove_socket(struct sock *sk)
|
| 59 | {
|
| 60 | write_lock_irq(&vcc_sklist_lock);
|
| 61 | sk_del_node_init(sk);
|
| 62 | write_unlock_irq(&vcc_sklist_lock);
|
| 63 | }
|
| 64 |
|
| 65 | static bool vcc_tx_ready(struct atm_vcc *vcc, unsigned int size)
|
| 66 | {
|
| 67 | struct sock *sk = sk_atm(vcc);
|
| 68 |
|
| 69 | if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) {
|
| 70 | pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
|
| 71 | sk_wmem_alloc_get(sk), size, sk->sk_sndbuf);
|
| 72 | return false;
|
| 73 | }
|
| 74 | return true;
|
| 75 | }
|
| 76 |
|
| 77 | static void vcc_sock_destruct(struct sock *sk)
|
| 78 | {
|
| 79 | if (atomic_read(&sk->sk_rmem_alloc))
|
| 80 | printk(KERN_DEBUG "%s: rmem leakage (%d bytes) detected.\n",
|
| 81 | __func__, atomic_read(&sk->sk_rmem_alloc));
|
| 82 |
|
| 83 | if (refcount_read(&sk->sk_wmem_alloc))
|
| 84 | printk(KERN_DEBUG "%s: wmem leakage (%d bytes) detected.\n",
|
| 85 | __func__, refcount_read(&sk->sk_wmem_alloc));
|
| 86 | }
|
| 87 |
|
| 88 | static void vcc_def_wakeup(struct sock *sk)
|
| 89 | {
|
| 90 | struct socket_wq *wq;
|
| 91 |
|
| 92 | rcu_read_lock();
|
| 93 | wq = rcu_dereference(sk->sk_wq);
|
| 94 | if (skwq_has_sleeper(wq))
|
| 95 | wake_up(&wq->wait);
|
| 96 | rcu_read_unlock();
|
| 97 | }
|
| 98 |
|
| 99 | static inline int vcc_writable(struct sock *sk)
|
| 100 | {
|
| 101 | struct atm_vcc *vcc = atm_sk(sk);
|
| 102 |
|
| 103 | return (vcc->qos.txtp.max_sdu +
|
| 104 | refcount_read(&sk->sk_wmem_alloc)) <= sk->sk_sndbuf;
|
| 105 | }
|
| 106 |
|
| 107 | static void vcc_write_space(struct sock *sk)
|
| 108 | {
|
| 109 | struct socket_wq *wq;
|
| 110 |
|
| 111 | rcu_read_lock();
|
| 112 |
|
| 113 | if (vcc_writable(sk)) {
|
| 114 | wq = rcu_dereference(sk->sk_wq);
|
| 115 | if (skwq_has_sleeper(wq))
|
| 116 | wake_up_interruptible(&wq->wait);
|
| 117 |
|
| 118 | sk_wake_async_rcu(sk, SOCK_WAKE_SPACE, POLL_OUT);
|
| 119 | }
|
| 120 |
|
| 121 | rcu_read_unlock();
|
| 122 | }
|
| 123 |
|
| 124 | static void vcc_release_cb(struct sock *sk)
|
| 125 | {
|
| 126 | struct atm_vcc *vcc = atm_sk(sk);
|
| 127 |
|
| 128 | if (vcc->release_cb)
|
| 129 | vcc->release_cb(vcc);
|
| 130 | }
|
| 131 |
|
| 132 | static struct proto vcc_proto = {
|
| 133 | .name = "VCC",
|
| 134 | .owner = THIS_MODULE,
|
| 135 | .obj_size = sizeof(struct atm_vcc),
|
| 136 | .release_cb = vcc_release_cb,
|
| 137 | };
|
| 138 |
|
| 139 | int vcc_create(struct net *net, struct socket *sock, int protocol, int family, int kern)
|
| 140 | {
|
| 141 | struct sock *sk;
|
| 142 | struct atm_vcc *vcc;
|
| 143 |
|
| 144 | sock->sk = NULL;
|
| 145 | if (sock->type == SOCK_STREAM)
|
| 146 | return -EINVAL;
|
| 147 | sk = sk_alloc(net, family, GFP_KERNEL, &vcc_proto, kern);
|
| 148 | if (!sk)
|
| 149 | return -ENOMEM;
|
| 150 | sock_init_data(sock, sk);
|
| 151 | sk->sk_state_change = vcc_def_wakeup;
|
| 152 | sk->sk_write_space = vcc_write_space;
|
| 153 |
|
| 154 | vcc = atm_sk(sk);
|
| 155 | vcc->dev = NULL;
|
| 156 | vcc->qos.txtp.max_sdu = 1 << 16;
|
| 157 | refcount_set(&sk->sk_wmem_alloc, SK_WMEM_ALLOC_BIAS);
|
| 158 | atomic_set(&sk->sk_rmem_alloc, 0);
|
| 159 | vcc->push = NULL;
|
| 160 | vcc->pop = NULL;
|
| 161 | vcc->owner = NULL;
|
| 162 | vcc->release_cb = NULL;
|
| 163 | vcc->vpi = vcc->vci = 0;
|
| 164 | vcc->atm_options = vcc->aal_options = 0;
|
| 165 | sk->sk_destruct = vcc_sock_destruct;
|
| 166 | return 0;
|
| 167 | }
|
| 168 |
|
| 169 | static void vcc_destroy_socket(struct sock *sk)
|
| 170 | {
|
| 171 | struct atm_vcc *vcc = atm_sk(sk);
|
| 172 | struct sk_buff *skb;
|
| 173 |
|
| 174 | set_bit(ATM_VF_CLOSE, &vcc->flags);
|
| 175 | clear_bit(ATM_VF_READY, &vcc->flags);
|
| 176 | if (vcc->dev && vcc->dev->ops->close)
|
| 177 | vcc->dev->ops->close(vcc);
|
| 178 | if (vcc->push)
|
| 179 | vcc->push(vcc, NULL);
|
| 180 | module_put(vcc->owner);
|
| 181 |
|
| 182 | while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
|
| 183 | atm_return(vcc, skb->truesize);
|
| 184 | kfree_skb(skb);
|
| 185 | }
|
| 186 |
|
| 187 | if (vcc->dev && vcc->dev->ops->owner) {
|
| 188 | module_put(vcc->dev->ops->owner);
|
| 189 | atm_dev_put(vcc->dev);
|
| 190 | }
|
| 191 |
|
| 192 | vcc_remove_socket(sk);
|
| 193 | }
|
| 194 |
|
| 195 | int vcc_release(struct socket *sock)
|
| 196 | {
|
| 197 | struct sock *sk = sock->sk;
|
| 198 |
|
| 199 | if (sk) {
|
| 200 | lock_sock(sk);
|
| 201 | vcc_destroy_socket(sock->sk);
|
| 202 | release_sock(sk);
|
| 203 | sock_put(sk);
|
| 204 | }
|
| 205 |
|
| 206 | return 0;
|
| 207 | }
|
| 208 |
|
| 209 | void vcc_release_async(struct atm_vcc *vcc, int reply)
|
| 210 | {
|
| 211 | struct sock *sk = sk_atm(vcc);
|
| 212 |
|
| 213 | set_bit(ATM_VF_CLOSE, &vcc->flags);
|
| 214 | sk->sk_shutdown |= RCV_SHUTDOWN;
|
| 215 | sk->sk_err = -reply;
|
| 216 | sk->sk_state_change(sk);
|
| 217 | }
|
| 218 | EXPORT_SYMBOL(vcc_release_async);
|
| 219 |
|
| 220 | void vcc_process_recv_queue(struct atm_vcc *vcc)
|
| 221 | {
|
| 222 | struct sk_buff_head queue, *rq;
|
| 223 | struct sk_buff *skb, *tmp;
|
| 224 | unsigned long flags;
|
| 225 |
|
| 226 | __skb_queue_head_init(&queue);
|
| 227 | rq = &sk_atm(vcc)->sk_receive_queue;
|
| 228 |
|
| 229 | spin_lock_irqsave(&rq->lock, flags);
|
| 230 | skb_queue_splice_init(rq, &queue);
|
| 231 | spin_unlock_irqrestore(&rq->lock, flags);
|
| 232 |
|
| 233 | skb_queue_walk_safe(&queue, skb, tmp) {
|
| 234 | __skb_unlink(skb, &queue);
|
| 235 | vcc->push(vcc, skb);
|
| 236 | }
|
| 237 | }
|
| 238 | EXPORT_SYMBOL(vcc_process_recv_queue);
|
| 239 |
|
| 240 | void atm_dev_signal_change(struct atm_dev *dev, char signal)
|
| 241 | {
|
| 242 | pr_debug("%s signal=%d dev=%p number=%d dev->signal=%d\n",
|
| 243 | __func__, signal, dev, dev->number, dev->signal);
|
| 244 |
|
| 245 |
|
| 246 | WARN_ON(signal < ATM_PHY_SIG_LOST || signal > ATM_PHY_SIG_FOUND);
|
| 247 |
|
| 248 | if (dev->signal == signal)
|
| 249 | return;
|
| 250 |
|
| 251 | dev->signal = signal;
|
| 252 |
|
| 253 | atomic_notifier_call_chain(&atm_dev_notify_chain, signal, dev);
|
| 254 | }
|
| 255 | EXPORT_SYMBOL(atm_dev_signal_change);
|
| 256 |
|
| 257 | void atm_dev_release_vccs(struct atm_dev *dev)
|
| 258 | {
|
| 259 | int i;
|
| 260 |
|
| 261 | write_lock_irq(&vcc_sklist_lock);
|
| 262 | for (i = 0; i < VCC_HTABLE_SIZE; i++) {
|
| 263 | struct hlist_head *head = &vcc_hash[i];
|
| 264 | struct hlist_node *tmp;
|
| 265 | struct sock *s;
|
| 266 | struct atm_vcc *vcc;
|
| 267 |
|
| 268 | sk_for_each_safe(s, tmp, head) {
|
| 269 | vcc = atm_sk(s);
|
| 270 | if (vcc->dev == dev) {
|
| 271 | vcc_release_async(vcc, -EPIPE);
|
| 272 | sk_del_node_init(s);
|
| 273 | }
|
| 274 | }
|
| 275 | }
|
| 276 | write_unlock_irq(&vcc_sklist_lock);
|
| 277 | }
|
| 278 | EXPORT_SYMBOL(atm_dev_release_vccs);
|
| 279 |
|
| 280 | static int adjust_tp(struct atm_trafprm *tp, unsigned char aal)
|
| 281 | {
|
| 282 | int max_sdu;
|
| 283 |
|
| 284 | if (!tp->traffic_class)
|
| 285 | return 0;
|
| 286 | switch (aal) {
|
| 287 | case ATM_AAL0:
|
| 288 | max_sdu = ATM_CELL_SIZE-1;
|
| 289 | break;
|
| 290 | default:
|
| 291 | pr_warn("AAL problems ... (%d)\n", aal);
|
| 292 | fallthrough;
|
| 293 | case ATM_AAL5:
|
| 294 | max_sdu = ATM_MAX_AAL5_PDU;
|
| 295 | }
|
| 296 | if (!tp->max_sdu)
|
| 297 | tp->max_sdu = max_sdu;
|
| 298 | else if (tp->max_sdu > max_sdu)
|
| 299 | return -EINVAL;
|
| 300 | if (!tp->max_cdv)
|
| 301 | tp->max_cdv = ATM_MAX_CDV;
|
| 302 | return 0;
|
| 303 | }
|
| 304 |
|
| 305 | static int check_ci(const struct atm_vcc *vcc, short vpi, int vci)
|
| 306 | {
|
| 307 | struct hlist_head *head = &vcc_hash[vci & (VCC_HTABLE_SIZE - 1)];
|
| 308 | struct sock *s;
|
| 309 | struct atm_vcc *walk;
|
| 310 |
|
| 311 | sk_for_each(s, head) {
|
| 312 | walk = atm_sk(s);
|
| 313 | if (walk->dev != vcc->dev)
|
| 314 | continue;
|
| 315 | if (test_bit(ATM_VF_ADDR, &walk->flags) && walk->vpi == vpi &&
|
| 316 | walk->vci == vci && ((walk->qos.txtp.traffic_class !=
|
| 317 | ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
|
| 318 | (walk->qos.rxtp.traffic_class != ATM_NONE &&
|
| 319 | vcc->qos.rxtp.traffic_class != ATM_NONE)))
|
| 320 | return -EADDRINUSE;
|
| 321 | }
|
| 322 |
|
| 323 | |
| 324 | TX/RX (but we may refuse such sharing for other reasons,
|
| 325 | e.g. if protocol requires to have both channels)
|
| 326 |
|
| 327 | return 0;
|
| 328 | }
|
| 329 |
|
| 330 | static int find_ci(const struct atm_vcc *vcc, short *vpi, int *vci)
|
| 331 | {
|
| 332 | static short p;
|
| 333 | static int c;
|
| 334 | short old_p;
|
| 335 | int old_c;
|
| 336 | int err;
|
| 337 |
|
| 338 | if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) {
|
| 339 | err = check_ci(vcc, *vpi, *vci);
|
| 340 | return err;
|
| 341 | }
|
| 342 |
|
| 343 | if (*vpi != ATM_VPI_ANY)
|
| 344 | p = *vpi;
|
| 345 | else if (p >= 1 << vcc->dev->ci_range.vpi_bits)
|
| 346 | p = 0;
|
| 347 | if (*vci != ATM_VCI_ANY)
|
| 348 | c = *vci;
|
| 349 | else if (c < ATM_NOT_RSV_VCI || c >= 1 << vcc->dev->ci_range.vci_bits)
|
| 350 | c = ATM_NOT_RSV_VCI;
|
| 351 | old_p = p;
|
| 352 | old_c = c;
|
| 353 | do {
|
| 354 | if (!check_ci(vcc, p, c)) {
|
| 355 | *vpi = p;
|
| 356 | *vci = c;
|
| 357 | return 0;
|
| 358 | }
|
| 359 | if (*vci == ATM_VCI_ANY) {
|
| 360 | c++;
|
| 361 | if (c >= 1 << vcc->dev->ci_range.vci_bits)
|
| 362 | c = ATM_NOT_RSV_VCI;
|
| 363 | }
|
| 364 | if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) &&
|
| 365 | *vpi == ATM_VPI_ANY) {
|
| 366 | p++;
|
| 367 | if (p >= 1 << vcc->dev->ci_range.vpi_bits)
|
| 368 | p = 0;
|
| 369 | }
|
| 370 | } while (old_p != p || old_c != c);
|
| 371 | return -EADDRINUSE;
|
| 372 | }
|
| 373 |
|
| 374 | static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi,
|
| 375 | int vci)
|
| 376 | {
|
| 377 | struct sock *sk = sk_atm(vcc);
|
| 378 | int error;
|
| 379 |
|
| 380 | if ((vpi != ATM_VPI_UNSPEC && vpi != ATM_VPI_ANY &&
|
| 381 | vpi >> dev->ci_range.vpi_bits) || (vci != ATM_VCI_UNSPEC &&
|
| 382 | vci != ATM_VCI_ANY && vci >> dev->ci_range.vci_bits))
|
| 383 | return -EINVAL;
|
| 384 | if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
|
| 385 | return -EPERM;
|
| 386 | error = -ENODEV;
|
| 387 | if (!try_module_get(dev->ops->owner))
|
| 388 | return error;
|
| 389 | vcc->dev = dev;
|
| 390 | write_lock_irq(&vcc_sklist_lock);
|
| 391 | if (test_bit(ATM_DF_REMOVED, &dev->flags) ||
|
| 392 | (error = find_ci(vcc, &vpi, &vci))) {
|
| 393 | write_unlock_irq(&vcc_sklist_lock);
|
| 394 | goto fail_module_put;
|
| 395 | }
|
| 396 | vcc->vpi = vpi;
|
| 397 | vcc->vci = vci;
|
| 398 | __vcc_insert_socket(sk);
|
| 399 | write_unlock_irq(&vcc_sklist_lock);
|
| 400 | switch (vcc->qos.aal) {
|
| 401 | case ATM_AAL0:
|
| 402 | error = atm_init_aal0(vcc);
|
| 403 | vcc->stats = &dev->stats.aal0;
|
| 404 | break;
|
| 405 | case ATM_NO_AAL:
|
| 406 |
|
| 407 | vcc->qos.aal = ATM_AAL5;
|
| 408 | fallthrough;
|
| 409 | case ATM_AAL5:
|
| 410 | error = atm_init_aal5(vcc);
|
| 411 | vcc->stats = &dev->stats.aal5;
|
| 412 | break;
|
| 413 | default:
|
| 414 | error = -EPROTOTYPE;
|
| 415 | }
|
| 416 | if (!error)
|
| 417 | error = adjust_tp(&vcc->qos.txtp, vcc->qos.aal);
|
| 418 | if (!error)
|
| 419 | error = adjust_tp(&vcc->qos.rxtp, vcc->qos.aal);
|
| 420 | if (error)
|
| 421 | goto fail;
|
| 422 | pr_debug("VCC %d.%d, AAL %d\n", vpi, vci, vcc->qos.aal);
|
| 423 | pr_debug(" TX: %d, PCR %d..%d, SDU %d\n",
|
| 424 | vcc->qos.txtp.traffic_class,
|
| 425 | vcc->qos.txtp.min_pcr,
|
| 426 | vcc->qos.txtp.max_pcr,
|
| 427 | vcc->qos.txtp.max_sdu);
|
| 428 | pr_debug(" RX: %d, PCR %d..%d, SDU %d\n",
|
| 429 | vcc->qos.rxtp.traffic_class,
|
| 430 | vcc->qos.rxtp.min_pcr,
|
| 431 | vcc->qos.rxtp.max_pcr,
|
| 432 | vcc->qos.rxtp.max_sdu);
|
| 433 |
|
| 434 | if (dev->ops->open) {
|
| 435 | error = dev->ops->open(vcc);
|
| 436 | if (error)
|
| 437 | goto fail;
|
| 438 | }
|
| 439 | return 0;
|
| 440 |
|
| 441 | fail:
|
| 442 | vcc_remove_socket(sk);
|
| 443 | fail_module_put:
|
| 444 | module_put(dev->ops->owner);
|
| 445 |
|
| 446 | vcc->dev = NULL;
|
| 447 | return error;
|
| 448 | }
|
| 449 |
|
| 450 | int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
|
| 451 | {
|
| 452 | struct atm_dev *dev;
|
| 453 | struct atm_vcc *vcc = ATM_SD(sock);
|
| 454 | int error;
|
| 455 |
|
| 456 | pr_debug("(vpi %d, vci %d)\n", vpi, vci);
|
| 457 | if (sock->state == SS_CONNECTED)
|
| 458 | return -EISCONN;
|
| 459 | if (sock->state != SS_UNCONNECTED)
|
| 460 | return -EINVAL;
|
| 461 | if (!(vpi || vci))
|
| 462 | return -EINVAL;
|
| 463 |
|
| 464 | if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC)
|
| 465 | clear_bit(ATM_VF_PARTIAL, &vcc->flags);
|
| 466 | else
|
| 467 | if (test_bit(ATM_VF_PARTIAL, &vcc->flags))
|
| 468 | return -EINVAL;
|
| 469 | pr_debug("(TX: cl %d,bw %d-%d,sdu %d; "
|
| 470 | "RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n",
|
| 471 | vcc->qos.txtp.traffic_class, vcc->qos.txtp.min_pcr,
|
| 472 | vcc->qos.txtp.max_pcr, vcc->qos.txtp.max_sdu,
|
| 473 | vcc->qos.rxtp.traffic_class, vcc->qos.rxtp.min_pcr,
|
| 474 | vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_sdu,
|
| 475 | vcc->qos.aal == ATM_AAL5 ? "" :
|
| 476 | vcc->qos.aal == ATM_AAL0 ? "" : " ??? code ",
|
| 477 | vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal);
|
| 478 | if (!test_bit(ATM_VF_HASQOS, &vcc->flags))
|
| 479 | return -EBADFD;
|
| 480 | if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
|
| 481 | vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
|
| 482 | return -EINVAL;
|
| 483 | if (likely(itf != ATM_ITF_ANY)) {
|
| 484 | dev = try_then_request_module(atm_dev_lookup(itf),
|
| 485 | "atm-device-%d", itf);
|
| 486 | } else {
|
| 487 | dev = NULL;
|
| 488 | mutex_lock(&atm_dev_mutex);
|
| 489 | if (!list_empty(&atm_devs)) {
|
| 490 | dev = list_entry(atm_devs.next,
|
| 491 | struct atm_dev, dev_list);
|
| 492 | atm_dev_hold(dev);
|
| 493 | }
|
| 494 | mutex_unlock(&atm_dev_mutex);
|
| 495 | }
|
| 496 | if (!dev)
|
| 497 | return -ENODEV;
|
| 498 | error = __vcc_connect(vcc, dev, vpi, vci);
|
| 499 | if (error) {
|
| 500 | atm_dev_put(dev);
|
| 501 | return error;
|
| 502 | }
|
| 503 | if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
|
| 504 | set_bit(ATM_VF_PARTIAL, &vcc->flags);
|
| 505 | if (test_bit(ATM_VF_READY, &ATM_SD(sock)->flags))
|
| 506 | sock->state = SS_CONNECTED;
|
| 507 | return 0;
|
| 508 | }
|
| 509 |
|
| 510 | int vcc_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
|
| 511 | int flags)
|
| 512 | {
|
| 513 | struct sock *sk = sock->sk;
|
| 514 | struct atm_vcc *vcc;
|
| 515 | struct sk_buff *skb;
|
| 516 | int copied, error = -EINVAL;
|
| 517 |
|
| 518 | if (sock->state != SS_CONNECTED)
|
| 519 | return -ENOTCONN;
|
| 520 |
|
| 521 |
|
| 522 | if (flags & ~(MSG_DONTWAIT | MSG_PEEK))
|
| 523 | return -EOPNOTSUPP;
|
| 524 |
|
| 525 | vcc = ATM_SD(sock);
|
| 526 | if (test_bit(ATM_VF_CLOSE, &vcc->flags) ||
|
| 527 | !test_bit(ATM_VF_READY, &vcc->flags))
|
| 528 | return 0;
|
| 529 |
|
| 530 | skb = skb_recv_datagram(sk, flags, &error);
|
| 531 | if (!skb)
|
| 532 | return error;
|
| 533 |
|
| 534 | copied = skb->len;
|
| 535 | if (copied > size) {
|
| 536 | copied = size;
|
| 537 | msg->msg_flags |= MSG_TRUNC;
|
| 538 | }
|
| 539 |
|
| 540 | error = skb_copy_datagram_msg(skb, 0, msg, copied);
|
| 541 | if (error)
|
| 542 | return error;
|
| 543 | sock_recv_cmsgs(msg, sk, skb);
|
| 544 |
|
| 545 | if (!(flags & MSG_PEEK)) {
|
| 546 | pr_debug("%d -= %d\n", atomic_read(&sk->sk_rmem_alloc),
|
| 547 | skb->truesize);
|
| 548 | atm_return(vcc, skb->truesize);
|
| 549 | }
|
| 550 |
|
| 551 | skb_free_datagram(sk, skb);
|
| 552 | return copied;
|
| 553 | }
|
| 554 |
|
| 555 | int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size)
|
| 556 | {
|
| 557 | struct sock *sk = sock->sk;
|
| 558 | DEFINE_WAIT(wait);
|
| 559 | struct atm_vcc *vcc;
|
| 560 | struct sk_buff *skb;
|
| 561 | int eff, error;
|
| 562 |
|
| 563 | lock_sock(sk);
|
| 564 | if (sock->state != SS_CONNECTED) {
|
| 565 | error = -ENOTCONN;
|
| 566 | goto out;
|
| 567 | }
|
| 568 | if (m->msg_name) {
|
| 569 | error = -EISCONN;
|
| 570 | goto out;
|
| 571 | }
|
| 572 | vcc = ATM_SD(sock);
|
| 573 | if (test_bit(ATM_VF_CLOSE, &vcc->flags) ||
|
| 574 | !test_bit(ATM_VF_READY, &vcc->flags)) {
|
| 575 | error = -EPIPE;
|
| 576 | send_sig(SIGPIPE, current, 0);
|
| 577 | goto out;
|
| 578 | }
|
| 579 | if (!size) {
|
| 580 | error = 0;
|
| 581 | goto out;
|
| 582 | }
|
| 583 | if (size > vcc->qos.txtp.max_sdu) {
|
| 584 | error = -EMSGSIZE;
|
| 585 | goto out;
|
| 586 | }
|
| 587 |
|
| 588 | eff = (size+3) & ~3;
|
| 589 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
|
| 590 | error = 0;
|
| 591 | while (!vcc_tx_ready(vcc, eff)) {
|
| 592 | if (m->msg_flags & MSG_DONTWAIT) {
|
| 593 | error = -EAGAIN;
|
| 594 | break;
|
| 595 | }
|
| 596 | schedule();
|
| 597 | if (signal_pending(current)) {
|
| 598 | error = -ERESTARTSYS;
|
| 599 | break;
|
| 600 | }
|
| 601 | if (test_bit(ATM_VF_CLOSE, &vcc->flags) ||
|
| 602 | !test_bit(ATM_VF_READY, &vcc->flags)) {
|
| 603 | error = -EPIPE;
|
| 604 | send_sig(SIGPIPE, current, 0);
|
| 605 | break;
|
| 606 | }
|
| 607 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
|
| 608 | }
|
| 609 | finish_wait(sk_sleep(sk), &wait);
|
| 610 | if (error)
|
| 611 | goto out;
|
| 612 |
|
| 613 | skb = alloc_skb(eff, GFP_KERNEL);
|
| 614 | if (!skb) {
|
| 615 | error = -ENOMEM;
|
| 616 | goto out;
|
| 617 | }
|
| 618 | pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize);
|
| 619 | atm_account_tx(vcc, skb);
|
| 620 |
|
| 621 | skb->dev = NULL;
|
| 622 | if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) {
|
| 623 | error = -EFAULT;
|
| 624 | goto free_skb;
|
| 625 | }
|
| 626 | if (eff != size)
|
| 627 | memset(skb->data + size, 0, eff-size);
|
| 628 |
|
| 629 | error = vcc->dev->ops->send(vcc, skb);
|
| 630 | error = error ? error : size;
|
| 631 | out:
|
| 632 | release_sock(sk);
|
| 633 | return error;
|
| 634 | free_skb:
|
| 635 | atm_return_tx(vcc, skb);
|
| 636 | kfree_skb(skb);
|
| 637 | goto out;
|
| 638 | }
|
| 639 |
|
| 640 | __poll_t vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
|
| 641 | {
|
| 642 | struct sock *sk = sock->sk;
|
| 643 | struct atm_vcc *vcc;
|
| 644 | __poll_t mask;
|
| 645 |
|
| 646 | sock_poll_wait(file, sock, wait);
|
| 647 | mask = 0;
|
| 648 |
|
| 649 | vcc = ATM_SD(sock);
|
| 650 |
|
| 651 |
|
| 652 | if (sk->sk_err)
|
| 653 | mask = EPOLLERR;
|
| 654 |
|
| 655 | if (test_bit(ATM_VF_CLOSE, &vcc->flags))
|
| 656 | mask |= EPOLLHUP;
|
| 657 |
|
| 658 |
|
| 659 | if (!skb_queue_empty_lockless(&sk->sk_receive_queue))
|
| 660 | mask |= EPOLLIN | EPOLLRDNORM;
|
| 661 |
|
| 662 |
|
| 663 | if (vcc->qos.txtp.traffic_class != ATM_NONE &&
|
| 664 | vcc_writable(sk))
|
| 665 | mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
|
| 666 |
|
| 667 | return mask;
|
| 668 | }
|
| 669 |
|
| 670 | static int check_tp(const struct atm_trafprm *tp)
|
| 671 | {
|
| 672 |
|
| 673 | if (tp->traffic_class > ATM_ANYCLASS)
|
| 674 | return -EINVAL;
|
| 675 | if (!tp->traffic_class || tp->traffic_class == ATM_ANYCLASS)
|
| 676 | return 0;
|
| 677 | if (tp->traffic_class != ATM_UBR && !tp->min_pcr && !tp->pcr &&
|
| 678 | !tp->max_pcr)
|
| 679 | return -EINVAL;
|
| 680 | if (tp->min_pcr == ATM_MAX_PCR)
|
| 681 | return -EINVAL;
|
| 682 | if (tp->min_pcr && tp->max_pcr && tp->max_pcr != ATM_MAX_PCR &&
|
| 683 | tp->min_pcr > tp->max_pcr)
|
| 684 | return -EINVAL;
|
| 685 | |
| 686 | * We allow pcr to be outside [min_pcr,max_pcr], because later
|
| 687 | * adjustment may still push it in the valid range.
|
| 688 |
|
| 689 | return 0;
|
| 690 | }
|
| 691 |
|
| 692 | static int check_qos(const struct atm_qos *qos)
|
| 693 | {
|
| 694 | int error;
|
| 695 |
|
| 696 | if (!qos->txtp.traffic_class && !qos->rxtp.traffic_class)
|
| 697 | return -EINVAL;
|
| 698 | if (qos->txtp.traffic_class != qos->rxtp.traffic_class &&
|
| 699 | qos->txtp.traffic_class && qos->rxtp.traffic_class &&
|
| 700 | qos->txtp.traffic_class != ATM_ANYCLASS &&
|
| 701 | qos->rxtp.traffic_class != ATM_ANYCLASS)
|
| 702 | return -EINVAL;
|
| 703 | error = check_tp(&qos->txtp);
|
| 704 | if (error)
|
| 705 | return error;
|
| 706 | return check_tp(&qos->rxtp);
|
| 707 | }
|
| 708 |
|
| 709 | int vcc_setsockopt(struct socket *sock, int level, int optname,
|
| 710 | sockptr_t optval, unsigned int optlen)
|
| 711 | {
|
| 712 | struct atm_vcc *vcc;
|
| 713 | int value;
|
| 714 | int error;
|
| 715 |
|
| 716 | if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
|
| 717 | return -EINVAL;
|
| 718 |
|
| 719 | vcc = ATM_SD(sock);
|
| 720 | switch (optname) {
|
| 721 | case SO_ATMQOS:
|
| 722 | {
|
| 723 | struct atm_qos qos;
|
| 724 |
|
| 725 | error = copy_safe_from_sockptr(&qos, sizeof(qos), optval,
|
| 726 | optlen);
|
| 727 | if (error)
|
| 728 | return error;
|
| 729 | error = check_qos(&qos);
|
| 730 | if (error)
|
| 731 | return error;
|
| 732 |
|
| 733 | if (sock->state == SS_CONNECTED)
|
| 734 | return -EOPNOTSUPP;
|
| 735 | if (sock->state != SS_UNCONNECTED)
|
| 736 | return -EBADFD;
|
| 737 | vcc->qos = qos;
|
| 738 | set_bit(ATM_VF_HASQOS, &vcc->flags);
|
| 739 | return 0;
|
| 740 | }
|
| 741 | case SO_SETCLP:
|
| 742 | error = copy_safe_from_sockptr(&value, sizeof(value), optval,
|
| 743 | optlen);
|
| 744 | if (error)
|
| 745 | return error;
|
| 746 | if (value)
|
| 747 | vcc->atm_options |= ATM_ATMOPT_CLP;
|
| 748 | else
|
| 749 | vcc->atm_options &= ~ATM_ATMOPT_CLP;
|
| 750 | return 0;
|
| 751 | default:
|
| 752 | return -EINVAL;
|
| 753 | }
|
| 754 | }
|
| 755 |
|
| 756 | int vcc_getsockopt(struct socket *sock, int level, int optname,
|
| 757 | sockopt_t *opt)
|
| 758 | {
|
| 759 | struct atm_vcc *vcc;
|
| 760 | int val;
|
| 761 | int len;
|
| 762 |
|
| 763 | len = opt->optlen;
|
| 764 | if (__SO_LEVEL_MATCH(optname, level) && len != __SO_SIZE(optname))
|
| 765 | return -EINVAL;
|
| 766 |
|
| 767 | vcc = ATM_SD(sock);
|
| 768 | switch (optname) {
|
| 769 | case SO_ATMQOS:
|
| 770 | if (!test_bit(ATM_VF_HASQOS, &vcc->flags))
|
| 771 | return -EINVAL;
|
| 772 | return copy_to_iter(&vcc->qos, sizeof(vcc->qos),
|
| 773 | &opt->iter_out) != sizeof(vcc->qos)
|
| 774 | ? -EFAULT : 0;
|
| 775 | case SO_SETCLP:
|
| 776 | val = vcc->atm_options & ATM_ATMOPT_CLP ? 1 : 0;
|
| 777 | return copy_to_iter(&val, sizeof(val), &opt->iter_out) !=
|
| 778 | sizeof(val) ? -EFAULT : 0;
|
| 779 | case SO_ATMPVC:
|
| 780 | {
|
| 781 | struct sockaddr_atmpvc pvc;
|
| 782 |
|
| 783 | if (!vcc->dev || !test_bit(ATM_VF_ADDR, &vcc->flags))
|
| 784 | return -ENOTCONN;
|
| 785 | memset(&pvc, 0, sizeof(pvc));
|
| 786 | pvc.sap_family = AF_ATMPVC;
|
| 787 | pvc.sap_addr.itf = vcc->dev->number;
|
| 788 | pvc.sap_addr.vpi = vcc->vpi;
|
| 789 | pvc.sap_addr.vci = vcc->vci;
|
| 790 | return copy_to_iter(&pvc, sizeof(pvc), &opt->iter_out) !=
|
| 791 | sizeof(pvc) ? -EFAULT : 0;
|
| 792 | }
|
| 793 | default:
|
| 794 | return -EINVAL;
|
| 795 | }
|
| 796 | }
|
| 797 |
|
| 798 | int register_atmdevice_notifier(struct notifier_block *nb)
|
| 799 | {
|
| 800 | return atomic_notifier_chain_register(&atm_dev_notify_chain, nb);
|
| 801 | }
|
| 802 | EXPORT_SYMBOL_GPL(register_atmdevice_notifier);
|
| 803 |
|
| 804 | void unregister_atmdevice_notifier(struct notifier_block *nb)
|
| 805 | {
|
| 806 | atomic_notifier_chain_unregister(&atm_dev_notify_chain, nb);
|
| 807 | }
|
| 808 | EXPORT_SYMBOL_GPL(unregister_atmdevice_notifier);
|
| 809 |
|
| 810 | static int __init atm_init(void)
|
| 811 | {
|
| 812 | int error;
|
| 813 |
|
| 814 | error = proto_register(&vcc_proto, 0);
|
| 815 | if (error < 0)
|
| 816 | goto out;
|
| 817 | error = atmpvc_init();
|
| 818 | if (error < 0) {
|
| 819 | pr_err("atmpvc_init() failed with %d\n", error);
|
| 820 | goto out_unregister_vcc_proto;
|
| 821 | }
|
| 822 | error = atm_proc_init();
|
| 823 | if (error < 0) {
|
| 824 | pr_err("atm_proc_init() failed with %d\n", error);
|
| 825 | goto out_atmpvc_exit;
|
| 826 | }
|
| 827 | error = atm_sysfs_init();
|
| 828 | if (error < 0) {
|
| 829 | pr_err("atm_sysfs_init() failed with %d\n", error);
|
| 830 | goto out_atmproc_exit;
|
| 831 | }
|
| 832 | out:
|
| 833 | return error;
|
| 834 | out_atmproc_exit:
|
| 835 | atm_proc_exit();
|
| 836 | out_atmpvc_exit:
|
| 837 | atmpvc_exit();
|
| 838 | out_unregister_vcc_proto:
|
| 839 | proto_unregister(&vcc_proto);
|
| 840 | goto out;
|
| 841 | }
|
| 842 |
|
| 843 | static void __exit atm_exit(void)
|
| 844 | {
|
| 845 | atm_proc_exit();
|
| 846 | atm_sysfs_exit();
|
| 847 | atmpvc_exit();
|
| 848 | proto_unregister(&vcc_proto);
|
| 849 | }
|
| 850 |
|
| 851 | subsys_initcall(atm_init);
|
| 852 |
|
| 853 | module_exit(atm_exit);
|
| 854 |
|
| 855 | MODULE_DESCRIPTION("Asynchronous Transfer Mode (ATM) networking core");
|
| 856 | MODULE_LICENSE("GPL");
|
| 857 | MODULE_ALIAS_NETPROTO(PF_ATMPVC);
|