addr.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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/slab.h>
  6. #include <linux/uaccess.h>
  7. #include "signaling.h"
  8. #include "addr.h"
  9. static int check_addr(const 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(const struct sockaddr_atmsvc *a, const 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(const 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, enum atm_addr_type_t atype)
  39. {
  40. unsigned long flags;
  41. struct atm_dev_addr *this, *p;
  42. struct list_head *head;
  43. spin_lock_irqsave(&dev->lock, flags);
  44. if (atype == ATM_ADDR_LECS)
  45. head = &dev->lecs;
  46. else
  47. head = &dev->local;
  48. list_for_each_entry_safe(this, p, head, entry) {
  49. list_del(&this->entry);
  50. kfree(this);
  51. }
  52. spin_unlock_irqrestore(&dev->lock, flags);
  53. if (head == &dev->local)
  54. notify_sigd(dev);
  55. }
  56. int atm_add_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
  57. enum atm_addr_type_t atype)
  58. {
  59. unsigned long flags;
  60. struct atm_dev_addr *this;
  61. struct list_head *head;
  62. int error;
  63. error = check_addr(addr);
  64. if (error)
  65. return error;
  66. spin_lock_irqsave(&dev->lock, flags);
  67. if (atype == ATM_ADDR_LECS)
  68. head = &dev->lecs;
  69. else
  70. head = &dev->local;
  71. list_for_each_entry(this, head, entry) {
  72. if (identical(&this->addr, addr)) {
  73. spin_unlock_irqrestore(&dev->lock, flags);
  74. return -EEXIST;
  75. }
  76. }
  77. this = kmalloc(sizeof(struct atm_dev_addr), GFP_ATOMIC);
  78. if (!this) {
  79. spin_unlock_irqrestore(&dev->lock, flags);
  80. return -ENOMEM;
  81. }
  82. this->addr = *addr;
  83. list_add(&this->entry, head);
  84. spin_unlock_irqrestore(&dev->lock, flags);
  85. if (head == &dev->local)
  86. notify_sigd(dev);
  87. return 0;
  88. }
  89. int atm_del_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
  90. enum atm_addr_type_t atype)
  91. {
  92. unsigned long flags;
  93. struct atm_dev_addr *this;
  94. struct list_head *head;
  95. int error;
  96. error = check_addr(addr);
  97. if (error)
  98. return error;
  99. spin_lock_irqsave(&dev->lock, flags);
  100. if (atype == ATM_ADDR_LECS)
  101. head = &dev->lecs;
  102. else
  103. head = &dev->local;
  104. list_for_each_entry(this, head, entry) {
  105. if (identical(&this->addr, addr)) {
  106. list_del(&this->entry);
  107. spin_unlock_irqrestore(&dev->lock, flags);
  108. kfree(this);
  109. if (head == &dev->local)
  110. notify_sigd(dev);
  111. return 0;
  112. }
  113. }
  114. spin_unlock_irqrestore(&dev->lock, flags);
  115. return -ENOENT;
  116. }
  117. int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf,
  118. size_t size, enum atm_addr_type_t atype)
  119. {
  120. unsigned long flags;
  121. struct atm_dev_addr *this;
  122. struct list_head *head;
  123. int total = 0, error;
  124. struct sockaddr_atmsvc *tmp_buf, *tmp_bufp;
  125. spin_lock_irqsave(&dev->lock, flags);
  126. if (atype == ATM_ADDR_LECS)
  127. head = &dev->lecs;
  128. else
  129. head = &dev->local;
  130. list_for_each_entry(this, head, entry)
  131. total += sizeof(struct sockaddr_atmsvc);
  132. tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC);
  133. if (!tmp_buf) {
  134. spin_unlock_irqrestore(&dev->lock, flags);
  135. return -ENOMEM;
  136. }
  137. list_for_each_entry(this, head, entry)
  138. memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc));
  139. spin_unlock_irqrestore(&dev->lock, flags);
  140. error = total > size ? -E2BIG : total;
  141. if (copy_to_user(buf, tmp_buf, total < size ? total : size))
  142. error = -EFAULT;
  143. kfree(tmp_buf);
  144. return error;
  145. }