addr.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:3k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  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) return -EAFNOSUPPORT;
  13. if (!*addr->sas_addr.pub)
  14. return *addr->sas_addr.prv ? 0 : -EINVAL;
  15. for (i = 1; i < ATM_E164_LEN+1; i++) /* make sure it's -terminated */
  16. if (!addr->sas_addr.pub[i]) return 0;
  17. return -EINVAL;
  18. }
  19. static int identical(struct sockaddr_atmsvc *a,struct sockaddr_atmsvc *b)
  20. {
  21. if (*a->sas_addr.prv)
  22. if (memcmp(a->sas_addr.prv,b->sas_addr.prv,ATM_ESA_LEN))
  23. return 0;
  24. if (!*a->sas_addr.pub) return !*b->sas_addr.pub;
  25. if (!*b->sas_addr.pub) return 0;
  26. return !strcmp(a->sas_addr.pub,b->sas_addr.pub);
  27. }
  28. /*
  29.  * Avoid modification of any list of local interfaces while reading it
  30.  * (which may involve page faults and therefore rescheduling)
  31.  */
  32. static DECLARE_MUTEX(local_lock);
  33. extern  spinlock_t atm_dev_lock;
  34. static void notify_sigd(struct atm_dev *dev)
  35. {
  36. struct sockaddr_atmpvc pvc;
  37. pvc.sap_addr.itf = dev->number;
  38. sigd_enq(NULL,as_itf_notify,NULL,&pvc,NULL);
  39. }
  40. /*
  41.  * This is called from atm_ioctl only. You must hold the lock as a caller
  42.  */
  43. void atm_reset_addr(struct atm_dev *dev)
  44. {
  45. struct atm_dev_addr *this;
  46. down(&local_lock);
  47. while (dev->local) {
  48. this = dev->local;
  49. dev->local = this->next;
  50. kfree(this);
  51. }
  52. up(&local_lock);
  53. notify_sigd(dev);
  54. }
  55. int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
  56. {
  57. struct atm_dev_addr **walk;
  58. int error;
  59. error = check_addr(addr);
  60. if (error) return error;
  61. down(&local_lock);
  62. for (walk = &dev->local; *walk; walk = &(*walk)->next)
  63. if (identical(&(*walk)->addr,addr)) {
  64. up(&local_lock);
  65. return -EEXIST;
  66. }
  67. *walk = kmalloc(sizeof(struct atm_dev_addr),GFP_KERNEL);
  68. if (!*walk) {
  69. up(&local_lock);
  70. return -ENOMEM;
  71. }
  72. (*walk)->addr = *addr;
  73. (*walk)->next = NULL;
  74. up(&local_lock);
  75. notify_sigd(dev);
  76. return 0;
  77. }
  78. int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
  79. {
  80. struct atm_dev_addr **walk,*this;
  81. int error;
  82. error = check_addr(addr);
  83. if (error) return error;
  84. down(&local_lock);
  85. for (walk = &dev->local; *walk; walk = &(*walk)->next)
  86. if (identical(&(*walk)->addr,addr)) break;
  87. if (!*walk) {
  88. up(&local_lock);
  89. return -ENOENT;
  90. }
  91. this = *walk;
  92. *walk = this->next;
  93. kfree(this);
  94. up(&local_lock);
  95. notify_sigd(dev);
  96. return 0;
  97. }
  98. int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size)
  99. {
  100. struct atm_dev_addr *walk;
  101. int total;
  102. down(&local_lock);
  103. total = 0;
  104. for (walk = dev->local; walk; walk = walk->next) {
  105. total += sizeof(struct sockaddr_atmsvc);
  106. if (total > size) {
  107. up(&local_lock);
  108. return -E2BIG;
  109. }
  110. if (copy_to_user(u_buf,&walk->addr,
  111.     sizeof(struct sockaddr_atmsvc))) {
  112. up(&local_lock);
  113. return -EFAULT;
  114. }
  115. u_buf++;
  116. }
  117. up(&local_lock);
  118. return total;
  119. }