[funini.com] -> [kei@sodan] -> Kernel Reading

root/net/atm/addr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. check_addr
  2. identical
  3. notify_sigd
  4. atm_reset_addr
  5. atm_add_addr
  6. atm_del_addr
  7. atm_get_addr

/* net/atm/addr.c - Local ATM address registry */

/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */

#include <linux/atm.h>
#include <linux/atmdev.h>
#include <asm/uaccess.h>

#include "signaling.h"
#include "addr.h"

static int check_addr(const struct sockaddr_atmsvc *addr)
{
        int i;

        if (addr->sas_family != AF_ATMSVC)
                return -EAFNOSUPPORT;
        if (!*addr->sas_addr.pub)
                return *addr->sas_addr.prv ? 0 : -EINVAL;
        for (i = 1; i < ATM_E164_LEN + 1; i++)  /* make sure it's \0-terminated */
                if (!addr->sas_addr.pub[i])
                        return 0;
        return -EINVAL;
}

static int identical(const struct sockaddr_atmsvc *a, const struct sockaddr_atmsvc *b)
{
        if (*a->sas_addr.prv)
                if (memcmp(a->sas_addr.prv, b->sas_addr.prv, ATM_ESA_LEN))
                        return 0;
        if (!*a->sas_addr.pub)
                return !*b->sas_addr.pub;
        if (!*b->sas_addr.pub)
                return 0;
        return !strcmp(a->sas_addr.pub, b->sas_addr.pub);
}

static void notify_sigd(const struct atm_dev *dev)
{
        struct sockaddr_atmpvc pvc;

        pvc.sap_addr.itf = dev->number;
        sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL);
}

void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t atype)
{
        unsigned long flags;
        struct atm_dev_addr *this, *p;
        struct list_head *head;

        spin_lock_irqsave(&dev->lock, flags);
        if (atype == ATM_ADDR_LECS)
                head = &dev->lecs;
        else
                head = &dev->local;
        list_for_each_entry_safe(this, p, head, entry) {
                list_del(&this->entry);
                kfree(this);
        }
        spin_unlock_irqrestore(&dev->lock, flags);
        if (head == &dev->local)
                notify_sigd(dev);
}

int atm_add_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
                 enum atm_addr_type_t atype)
{
        unsigned long flags;
        struct atm_dev_addr *this;
        struct list_head *head;
        int error;

        error = check_addr(addr);
        if (error)
                return error;
        spin_lock_irqsave(&dev->lock, flags);
        if (atype == ATM_ADDR_LECS)
                head = &dev->lecs;
        else
                head = &dev->local;
        list_for_each_entry(this, head, entry) {
                if (identical(&this->addr, addr)) {
                        spin_unlock_irqrestore(&dev->lock, flags);
                        return -EEXIST;
                }
        }
        this = kmalloc(sizeof(struct atm_dev_addr), GFP_ATOMIC);
        if (!this) {
                spin_unlock_irqrestore(&dev->lock, flags);
                return -ENOMEM;
        }
        this->addr = *addr;
        list_add(&this->entry, head);
        spin_unlock_irqrestore(&dev->lock, flags);
        if (head == &dev->local)
                notify_sigd(dev);
        return 0;
}

int atm_del_addr(struct atm_dev *dev, const struct sockaddr_atmsvc *addr,
                 enum atm_addr_type_t atype)
{
        unsigned long flags;
        struct atm_dev_addr *this;
        struct list_head *head;
        int error;

        error = check_addr(addr);
        if (error)
                return error;
        spin_lock_irqsave(&dev->lock, flags);
        if (atype == ATM_ADDR_LECS)
                head = &dev->lecs;
        else
                head = &dev->local;
        list_for_each_entry(this, head, entry) {
                if (identical(&this->addr, addr)) {
                        list_del(&this->entry);
                        spin_unlock_irqrestore(&dev->lock, flags);
                        kfree(this);
                        if (head == &dev->local)
                                notify_sigd(dev);
                        return 0;
                }
        }
        spin_unlock_irqrestore(&dev->lock, flags);
        return -ENOENT;
}

int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf,
                 size_t size, enum atm_addr_type_t atype)
{
        unsigned long flags;
        struct atm_dev_addr *this;
        struct list_head *head;
        int total = 0, error;
        struct sockaddr_atmsvc *tmp_buf, *tmp_bufp;

        spin_lock_irqsave(&dev->lock, flags);
        if (atype == ATM_ADDR_LECS)
                head = &dev->lecs;
        else
                head = &dev->local;
        list_for_each_entry(this, head, entry)
            total += sizeof(struct sockaddr_atmsvc);
        tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC);
        if (!tmp_buf) {
                spin_unlock_irqrestore(&dev->lock, flags);
                return -ENOMEM;
        }
        list_for_each_entry(this, head, entry)
            memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc));
        spin_unlock_irqrestore(&dev->lock, flags);
        error = total > size ? -E2BIG : total;
        if (copy_to_user(buf, tmp_buf, total < size ? total : size))
                error = -EFAULT;
        kfree(tmp_buf);
        return error;
}

/* [<][>][^][v][top][bottom][index][help] */

[funini.com] -> [kei@sodan] -> Kernel Reading