18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* net/atm/addr.c - Local ATM address registry */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/atm.h> 78c2ecf20Sopenharmony_ci#include <linux/atmdev.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "signaling.h" 128c2ecf20Sopenharmony_ci#include "addr.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic int check_addr(const struct sockaddr_atmsvc *addr) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci int i; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci if (addr->sas_family != AF_ATMSVC) 198c2ecf20Sopenharmony_ci return -EAFNOSUPPORT; 208c2ecf20Sopenharmony_ci if (!*addr->sas_addr.pub) 218c2ecf20Sopenharmony_ci return *addr->sas_addr.prv ? 0 : -EINVAL; 228c2ecf20Sopenharmony_ci for (i = 1; i < ATM_E164_LEN + 1; i++) /* make sure it's \0-terminated */ 238c2ecf20Sopenharmony_ci if (!addr->sas_addr.pub[i]) 248c2ecf20Sopenharmony_ci return 0; 258c2ecf20Sopenharmony_ci return -EINVAL; 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic int identical(const struct sockaddr_atmsvc *a, const struct sockaddr_atmsvc *b) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci if (*a->sas_addr.prv) 318c2ecf20Sopenharmony_ci if (memcmp(a->sas_addr.prv, b->sas_addr.prv, ATM_ESA_LEN)) 328c2ecf20Sopenharmony_ci return 0; 338c2ecf20Sopenharmony_ci if (!*a->sas_addr.pub) 348c2ecf20Sopenharmony_ci return !*b->sas_addr.pub; 358c2ecf20Sopenharmony_ci if (!*b->sas_addr.pub) 368c2ecf20Sopenharmony_ci return 0; 378c2ecf20Sopenharmony_ci return !strcmp(a->sas_addr.pub, b->sas_addr.pub); 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic void notify_sigd(const struct atm_dev *dev) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct sockaddr_atmpvc pvc; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci pvc.sap_addr.itf = dev->number; 458c2ecf20Sopenharmony_ci sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_civoid atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t atype) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci unsigned long flags; 518c2ecf20Sopenharmony_ci struct atm_dev_addr *this, *p; 528c2ecf20Sopenharmony_ci struct list_head *head; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 558c2ecf20Sopenharmony_ci if (atype == ATM_ADDR_LECS) 568c2ecf20Sopenharmony_ci head = &dev->lecs; 578c2ecf20Sopenharmony_ci else 588c2ecf20Sopenharmony_ci head = &dev->local; 598c2ecf20Sopenharmony_ci list_for_each_entry_safe(this, p, head, entry) { 608c2ecf20Sopenharmony_ci list_del(&this->entry); 618c2ecf20Sopenharmony_ci kfree(this); 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 648c2ecf20Sopenharmony_ci if (head == &dev->local) 658c2ecf20Sopenharmony_ci notify_sigd(dev); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ciint atm_add_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr, 698c2ecf20Sopenharmony_ci enum atm_addr_type_t atype) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci unsigned long flags; 728c2ecf20Sopenharmony_ci struct atm_dev_addr *this; 738c2ecf20Sopenharmony_ci struct list_head *head; 748c2ecf20Sopenharmony_ci int error; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci error = check_addr(addr); 778c2ecf20Sopenharmony_ci if (error) 788c2ecf20Sopenharmony_ci return error; 798c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 808c2ecf20Sopenharmony_ci if (atype == ATM_ADDR_LECS) 818c2ecf20Sopenharmony_ci head = &dev->lecs; 828c2ecf20Sopenharmony_ci else 838c2ecf20Sopenharmony_ci head = &dev->local; 848c2ecf20Sopenharmony_ci list_for_each_entry(this, head, entry) { 858c2ecf20Sopenharmony_ci if (identical(&this->addr, addr)) { 868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 878c2ecf20Sopenharmony_ci return -EEXIST; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci this = kmalloc(sizeof(struct atm_dev_addr), GFP_ATOMIC); 918c2ecf20Sopenharmony_ci if (!this) { 928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 938c2ecf20Sopenharmony_ci return -ENOMEM; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci this->addr = *addr; 968c2ecf20Sopenharmony_ci list_add(&this->entry, head); 978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 988c2ecf20Sopenharmony_ci if (head == &dev->local) 998c2ecf20Sopenharmony_ci notify_sigd(dev); 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ciint atm_del_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr, 1048c2ecf20Sopenharmony_ci enum atm_addr_type_t atype) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci unsigned long flags; 1078c2ecf20Sopenharmony_ci struct atm_dev_addr *this; 1088c2ecf20Sopenharmony_ci struct list_head *head; 1098c2ecf20Sopenharmony_ci int error; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci error = check_addr(addr); 1128c2ecf20Sopenharmony_ci if (error) 1138c2ecf20Sopenharmony_ci return error; 1148c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 1158c2ecf20Sopenharmony_ci if (atype == ATM_ADDR_LECS) 1168c2ecf20Sopenharmony_ci head = &dev->lecs; 1178c2ecf20Sopenharmony_ci else 1188c2ecf20Sopenharmony_ci head = &dev->local; 1198c2ecf20Sopenharmony_ci list_for_each_entry(this, head, entry) { 1208c2ecf20Sopenharmony_ci if (identical(&this->addr, addr)) { 1218c2ecf20Sopenharmony_ci list_del(&this->entry); 1228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 1238c2ecf20Sopenharmony_ci kfree(this); 1248c2ecf20Sopenharmony_ci if (head == &dev->local) 1258c2ecf20Sopenharmony_ci notify_sigd(dev); 1268c2ecf20Sopenharmony_ci return 0; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 1308c2ecf20Sopenharmony_ci return -ENOENT; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ciint atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf, 1348c2ecf20Sopenharmony_ci size_t size, enum atm_addr_type_t atype) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci unsigned long flags; 1378c2ecf20Sopenharmony_ci struct atm_dev_addr *this; 1388c2ecf20Sopenharmony_ci struct list_head *head; 1398c2ecf20Sopenharmony_ci int total = 0, error; 1408c2ecf20Sopenharmony_ci struct sockaddr_atmsvc *tmp_buf, *tmp_bufp; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 1438c2ecf20Sopenharmony_ci if (atype == ATM_ADDR_LECS) 1448c2ecf20Sopenharmony_ci head = &dev->lecs; 1458c2ecf20Sopenharmony_ci else 1468c2ecf20Sopenharmony_ci head = &dev->local; 1478c2ecf20Sopenharmony_ci list_for_each_entry(this, head, entry) 1488c2ecf20Sopenharmony_ci total += sizeof(struct sockaddr_atmsvc); 1498c2ecf20Sopenharmony_ci tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC); 1508c2ecf20Sopenharmony_ci if (!tmp_buf) { 1518c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 1528c2ecf20Sopenharmony_ci return -ENOMEM; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci list_for_each_entry(this, head, entry) 1558c2ecf20Sopenharmony_ci memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc)); 1568c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 1578c2ecf20Sopenharmony_ci error = total > size ? -E2BIG : total; 1588c2ecf20Sopenharmony_ci if (copy_to_user(buf, tmp_buf, total < size ? total : size)) 1598c2ecf20Sopenharmony_ci error = -EFAULT; 1608c2ecf20Sopenharmony_ci kfree(tmp_buf); 1618c2ecf20Sopenharmony_ci return error; 1628c2ecf20Sopenharmony_ci} 163