addr.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /* net/atm/addr.c - Local ATM address registry */
  2. /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
  3. #include <linux/atm.h>
  4. #include <linux/atmdev.h>
  5. #include <linux/sched.h>
  6. #include <asm/uaccess.h>
  7. #include "signaling.h"
  8. #include "addr.h"
  9. static int check_addr(struct sockaddr_atmsvc *addr)
  10. {
  11. int i;
  12. if (addr->sas_family != AF_ATMSVC)
  13. return -EAFNOSUPPORT;
  14. if (!*addr->sas_addr.pub)
  15. return *addr->sas_addr.prv ? 0 : -EINVAL;
  16. for (i = 1; i < ATM_E164_LEN + 1; i++) /* make sure it's \0-terminated */
  17. if (!addr->sas_addr.pub[i])
  18. return 0;
  19. return -EINVAL;
  20. }
  21. static int identical(struct sockaddr_atmsvc *a, struct sockaddr_atmsvc *b)
  22. {
  23. if (*a->sas_addr.prv)
  24. if (memcmp(a->sas_addr.prv, b->sas_addr.prv, ATM_ESA_LEN))
  25. return 0;
  26. if (!*a->sas_addr.pub)
  27. return !*b->sas_addr.pub;
  28. if (!*b->sas_addr.pub)
  29. return 0;
  30. return !strcmp(a->sas_addr.pub, b->sas_addr.pub);
  31. }
  32. static void notify_sigd(struct atm_dev *dev)
  33. {
  34. struct sockaddr_atmpvc pvc;
  35. pvc.sap_addr.itf = dev->number;
  36. sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL);
  37. }
  38. void atm_reset_addr(struct atm_dev *dev)
  39. {
  40. unsigned long flags;
  41. struct atm_dev_addr *this, *p;
  42. spin_lock_irqsave(&dev->lock, flags);
  43. list_for_each_entry_safe(this, p, &dev->local, entry) {
  44. list_del(&this->entry);
  45. kfree(this);
  46. }
  47. spin_unlock_irqrestore(&dev->lock, flags);
  48. notify_sigd(dev);
  49. }
  50. int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr)
  51. {
  52. unsigned long flags;
  53. struct atm_dev_addr *this;
  54. int error;
  55. error = check_addr(addr);
  56. if (error)
  57. return error;
  58. spin_lock_irqsave(&dev->lock, flags);
  59. list_for_each_entry(this, &dev->local, entry) {
  60. if (identical(&this->addr, addr)) {
  61. spin_unlock_irqrestore(&dev->lock, flags);
  62. return -EEXIST;
  63. }
  64. }
  65. this = kmalloc(sizeof(struct atm_dev_addr), GFP_ATOMIC);
  66. if (!this) {
  67. spin_unlock_irqrestore(&dev->lock, flags);
  68. return -ENOMEM;
  69. }
  70. this->addr = *addr;
  71. list_add(&this->entry, &dev->local);
  72. spin_unlock_irqrestore(&dev->lock, flags);
  73. notify_sigd(dev);
  74. return 0;
  75. }
  76. int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr)
  77. {
  78. unsigned long flags;
  79. struct atm_dev_addr *this;
  80. int error;
  81. error = check_addr(addr);
  82. if (error)
  83. return error;
  84. spin_lock_irqsave(&dev->lock, flags);
  85. list_for_each_entry(this, &dev->local, entry) {
  86. if (identical(&this->addr, addr)) {
  87. list_del(&this->entry);
  88. spin_unlock_irqrestore(&dev->lock, flags);
  89. kfree(this);
  90. notify_sigd(dev);
  91. return 0;
  92. }
  93. }
  94. spin_unlock_irqrestore(&dev->lock, flags);
  95. return -ENOENT;
  96. }
  97. int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf,
  98. size_t size)
  99. {
  100. unsigned long flags;
  101. struct atm_dev_addr *this;
  102. int total = 0, error;
  103. struct sockaddr_atmsvc *tmp_buf, *tmp_bufp;
  104. spin_lock_irqsave(&dev->lock, flags);
  105. list_for_each_entry(this, &dev->local, entry)
  106. total += sizeof(struct sockaddr_atmsvc);
  107. tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC);
  108. if (!tmp_buf) {
  109. spin_unlock_irqrestore(&dev->lock, flags);
  110. return -ENOMEM;
  111. }
  112. list_for_each_entry(this, &dev->local, entry)
  113. memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc));
  114. spin_unlock_irqrestore(&dev->lock, flags);
  115. error = total > size ? -E2BIG : total;
  116. if (copy_to_user(buf, tmp_buf, total < size ? total : size))
  117. error = -EFAULT;
  118. kfree(tmp_buf);
  119. return error;
  120. }