diff options
-rw-r--r-- | include/linux/atmdev.h | 10 | ||||
-rw-r--r-- | include/net/sctp/user.h | 33 | ||||
-rw-r--r-- | net/atm/addr.c | 51 | ||||
-rw-r--r-- | net/atm/addr.h | 12 | ||||
-rw-r--r-- | net/atm/br2684.c | 2 | ||||
-rw-r--r-- | net/atm/resources.c | 20 | ||||
-rw-r--r-- | net/sctp/socket.c | 252 |
7 files changed, 319 insertions, 61 deletions
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h index f1fd849e5535..aca9b344bd35 100644 --- a/include/linux/atmdev.h +++ b/include/linux/atmdev.h | |||
@@ -76,6 +76,13 @@ struct atm_dev_stats { | |||
76 | /* set interface ESI */ | 76 | /* set interface ESI */ |
77 | #define ATM_SETESIF _IOW('a',ATMIOC_ITF+13,struct atmif_sioc) | 77 | #define ATM_SETESIF _IOW('a',ATMIOC_ITF+13,struct atmif_sioc) |
78 | /* force interface ESI */ | 78 | /* force interface ESI */ |
79 | #define ATM_ADDLECSADDR _IOW('a', ATMIOC_ITF+14, struct atmif_sioc) | ||
80 | /* register a LECS address */ | ||
81 | #define ATM_DELLECSADDR _IOW('a', ATMIOC_ITF+15, struct atmif_sioc) | ||
82 | /* unregister a LECS address */ | ||
83 | #define ATM_GETLECSADDR _IOW('a', ATMIOC_ITF+16, struct atmif_sioc) | ||
84 | /* retrieve LECS address(es) */ | ||
85 | |||
79 | #define ATM_GETSTAT _IOW('a',ATMIOC_SARCOM+0,struct atmif_sioc) | 86 | #define ATM_GETSTAT _IOW('a',ATMIOC_SARCOM+0,struct atmif_sioc) |
80 | /* get AAL layer statistics */ | 87 | /* get AAL layer statistics */ |
81 | #define ATM_GETSTATZ _IOW('a',ATMIOC_SARCOM+1,struct atmif_sioc) | 88 | #define ATM_GETSTATZ _IOW('a',ATMIOC_SARCOM+1,struct atmif_sioc) |
@@ -328,6 +335,8 @@ struct atm_dev_addr { | |||
328 | struct list_head entry; /* next address */ | 335 | struct list_head entry; /* next address */ |
329 | }; | 336 | }; |
330 | 337 | ||
338 | enum atm_addr_type_t { ATM_ADDR_LOCAL, ATM_ADDR_LECS }; | ||
339 | |||
331 | struct atm_dev { | 340 | struct atm_dev { |
332 | const struct atmdev_ops *ops; /* device operations; NULL if unused */ | 341 | const struct atmdev_ops *ops; /* device operations; NULL if unused */ |
333 | const struct atmphy_ops *phy; /* PHY operations, may be undefined */ | 342 | const struct atmphy_ops *phy; /* PHY operations, may be undefined */ |
@@ -338,6 +347,7 @@ struct atm_dev { | |||
338 | void *phy_data; /* private PHY date */ | 347 | void *phy_data; /* private PHY date */ |
339 | unsigned long flags; /* device flags (ATM_DF_*) */ | 348 | unsigned long flags; /* device flags (ATM_DF_*) */ |
340 | struct list_head local; /* local ATM addresses */ | 349 | struct list_head local; /* local ATM addresses */ |
350 | struct list_head lecs; /* LECS ATM addresses learned via ILMI */ | ||
341 | unsigned char esi[ESI_LEN]; /* ESI ("MAC" addr) */ | 351 | unsigned char esi[ESI_LEN]; /* ESI ("MAC" addr) */ |
342 | struct atm_cirange ci_range; /* VPI/VCI range */ | 352 | struct atm_cirange ci_range; /* VPI/VCI range */ |
343 | struct k_atm_dev_stats stats; /* statistics */ | 353 | struct k_atm_dev_stats stats; /* statistics */ |
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index f6328aeddcce..1c5f19f995ad 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h | |||
@@ -103,16 +103,20 @@ enum sctp_optname { | |||
103 | #define SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_BINDX_REM | 103 | #define SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_BINDX_REM |
104 | SCTP_SOCKOPT_PEELOFF, /* peel off association. */ | 104 | SCTP_SOCKOPT_PEELOFF, /* peel off association. */ |
105 | #define SCTP_SOCKOPT_PEELOFF SCTP_SOCKOPT_PEELOFF | 105 | #define SCTP_SOCKOPT_PEELOFF SCTP_SOCKOPT_PEELOFF |
106 | SCTP_GET_PEER_ADDRS_NUM, /* Get number of peer addresss. */ | 106 | SCTP_GET_PEER_ADDRS_NUM_OLD, /* Get number of peer addresss. */ |
107 | #define SCTP_GET_PEER_ADDRS_NUM SCTP_GET_PEER_ADDRS_NUM | 107 | #define SCTP_GET_PEER_ADDRS_NUM_OLD SCTP_GET_PEER_ADDRS_NUM_OLD |
108 | SCTP_GET_PEER_ADDRS_OLD, /* Get all peer addresss. */ | ||
109 | #define SCTP_GET_PEER_ADDRS_OLD SCTP_GET_PEER_ADDRS_OLD | ||
110 | SCTP_GET_LOCAL_ADDRS_NUM_OLD, /* Get number of local addresss. */ | ||
111 | #define SCTP_GET_LOCAL_ADDRS_NUM_OLD SCTP_GET_LOCAL_ADDRS_NUM_OLD | ||
112 | SCTP_GET_LOCAL_ADDRS_OLD, /* Get all local addresss. */ | ||
113 | #define SCTP_GET_LOCAL_ADDRS_OLD SCTP_GET_LOCAL_ADDRS_OLD | ||
114 | SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */ | ||
115 | #define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX | ||
108 | SCTP_GET_PEER_ADDRS, /* Get all peer addresss. */ | 116 | SCTP_GET_PEER_ADDRS, /* Get all peer addresss. */ |
109 | #define SCTP_GET_PEER_ADDRS SCTP_GET_PEER_ADDRS | 117 | #define SCTP_GET_PEER_ADDRS SCTP_GET_PEER_ADDRS |
110 | SCTP_GET_LOCAL_ADDRS_NUM, /* Get number of local addresss. */ | ||
111 | #define SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS_NUM | ||
112 | SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */ | 118 | SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */ |
113 | #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS | 119 | #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS |
114 | SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */ | ||
115 | #define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX | ||
116 | }; | 120 | }; |
117 | 121 | ||
118 | /* | 122 | /* |
@@ -239,7 +243,7 @@ struct sctp_paddr_change { | |||
239 | int spc_state; | 243 | int spc_state; |
240 | int spc_error; | 244 | int spc_error; |
241 | sctp_assoc_t spc_assoc_id; | 245 | sctp_assoc_t spc_assoc_id; |
242 | }; | 246 | } __attribute__((packed, aligned(4))); |
243 | 247 | ||
244 | /* | 248 | /* |
245 | * spc_state: 32 bits (signed integer) | 249 | * spc_state: 32 bits (signed integer) |
@@ -464,7 +468,7 @@ struct sctp_assocparams { | |||
464 | struct sctp_setpeerprim { | 468 | struct sctp_setpeerprim { |
465 | sctp_assoc_t sspp_assoc_id; | 469 | sctp_assoc_t sspp_assoc_id; |
466 | struct sockaddr_storage sspp_addr; | 470 | struct sockaddr_storage sspp_addr; |
467 | }; | 471 | } __attribute__((packed, aligned(4))); |
468 | 472 | ||
469 | /* | 473 | /* |
470 | * 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) | 474 | * 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) |
@@ -477,7 +481,7 @@ struct sctp_setpeerprim { | |||
477 | struct sctp_prim { | 481 | struct sctp_prim { |
478 | sctp_assoc_t ssp_assoc_id; | 482 | sctp_assoc_t ssp_assoc_id; |
479 | struct sockaddr_storage ssp_addr; | 483 | struct sockaddr_storage ssp_addr; |
480 | }; | 484 | } __attribute__((packed, aligned(4))); |
481 | 485 | ||
482 | /* | 486 | /* |
483 | * 7.1.11 Set Adaption Layer Indicator (SCTP_ADAPTION_LAYER) | 487 | * 7.1.11 Set Adaption Layer Indicator (SCTP_ADAPTION_LAYER) |
@@ -504,7 +508,7 @@ struct sctp_paddrparams { | |||
504 | struct sockaddr_storage spp_address; | 508 | struct sockaddr_storage spp_address; |
505 | __u32 spp_hbinterval; | 509 | __u32 spp_hbinterval; |
506 | __u16 spp_pathmaxrxt; | 510 | __u16 spp_pathmaxrxt; |
507 | }; | 511 | } __attribute__((packed, aligned(4))); |
508 | 512 | ||
509 | /* | 513 | /* |
510 | * 7.2.2 Peer Address Information | 514 | * 7.2.2 Peer Address Information |
@@ -523,7 +527,7 @@ struct sctp_paddrinfo { | |||
523 | __u32 spinfo_srtt; | 527 | __u32 spinfo_srtt; |
524 | __u32 spinfo_rto; | 528 | __u32 spinfo_rto; |
525 | __u32 spinfo_mtu; | 529 | __u32 spinfo_mtu; |
526 | }; | 530 | } __attribute__((packed, aligned(4))); |
527 | 531 | ||
528 | /* Peer addresses's state. */ | 532 | /* Peer addresses's state. */ |
529 | enum sctp_spinfo_state { | 533 | enum sctp_spinfo_state { |
@@ -559,11 +563,16 @@ struct sctp_status { | |||
559 | * SCTP_GET_LOCAL_ADDRS socket options used internally to implement | 563 | * SCTP_GET_LOCAL_ADDRS socket options used internally to implement |
560 | * sctp_getpaddrs() and sctp_getladdrs() API. | 564 | * sctp_getpaddrs() and sctp_getladdrs() API. |
561 | */ | 565 | */ |
562 | struct sctp_getaddrs { | 566 | struct sctp_getaddrs_old { |
563 | sctp_assoc_t assoc_id; | 567 | sctp_assoc_t assoc_id; |
564 | int addr_num; | 568 | int addr_num; |
565 | struct sockaddr __user *addrs; | 569 | struct sockaddr __user *addrs; |
566 | }; | 570 | }; |
571 | struct sctp_getaddrs { | ||
572 | sctp_assoc_t assoc_id; /*input*/ | ||
573 | __u32 addr_num; /*output*/ | ||
574 | __u8 addrs[0]; /*output, variable size*/ | ||
575 | }; | ||
567 | 576 | ||
568 | /* These are bit fields for msghdr->msg_flags. See section 5.1. */ | 577 | /* These are bit fields for msghdr->msg_flags. See section 5.1. */ |
569 | /* On user space Linux, these live in <bits/socket.h> as an enum. */ | 578 | /* On user space Linux, these live in <bits/socket.h> as an enum. */ |
diff --git a/net/atm/addr.c b/net/atm/addr.c index a30d0bf48063..3060fd0ba4b9 100644 --- a/net/atm/addr.c +++ b/net/atm/addr.c | |||
@@ -44,31 +44,43 @@ static void notify_sigd(struct atm_dev *dev) | |||
44 | sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL); | 44 | sigd_enq(NULL, as_itf_notify, NULL, &pvc, NULL); |
45 | } | 45 | } |
46 | 46 | ||
47 | void atm_reset_addr(struct atm_dev *dev) | 47 | void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t atype) |
48 | { | 48 | { |
49 | unsigned long flags; | 49 | unsigned long flags; |
50 | struct atm_dev_addr *this, *p; | 50 | struct atm_dev_addr *this, *p; |
51 | struct list_head *head; | ||
51 | 52 | ||
52 | spin_lock_irqsave(&dev->lock, flags); | 53 | spin_lock_irqsave(&dev->lock, flags); |
53 | list_for_each_entry_safe(this, p, &dev->local, entry) { | 54 | if (atype == ATM_ADDR_LECS) |
55 | head = &dev->lecs; | ||
56 | else | ||
57 | head = &dev->local; | ||
58 | list_for_each_entry_safe(this, p, head, entry) { | ||
54 | list_del(&this->entry); | 59 | list_del(&this->entry); |
55 | kfree(this); | 60 | kfree(this); |
56 | } | 61 | } |
57 | spin_unlock_irqrestore(&dev->lock, flags); | 62 | spin_unlock_irqrestore(&dev->lock, flags); |
58 | notify_sigd(dev); | 63 | if (head == &dev->local) |
64 | notify_sigd(dev); | ||
59 | } | 65 | } |
60 | 66 | ||
61 | int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr) | 67 | int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, |
68 | enum atm_addr_type_t atype) | ||
62 | { | 69 | { |
63 | unsigned long flags; | 70 | unsigned long flags; |
64 | struct atm_dev_addr *this; | 71 | struct atm_dev_addr *this; |
72 | struct list_head *head; | ||
65 | int error; | 73 | int error; |
66 | 74 | ||
67 | error = check_addr(addr); | 75 | error = check_addr(addr); |
68 | if (error) | 76 | if (error) |
69 | return error; | 77 | return error; |
70 | spin_lock_irqsave(&dev->lock, flags); | 78 | spin_lock_irqsave(&dev->lock, flags); |
71 | list_for_each_entry(this, &dev->local, entry) { | 79 | if (atype == ATM_ADDR_LECS) |
80 | head = &dev->lecs; | ||
81 | else | ||
82 | head = &dev->local; | ||
83 | list_for_each_entry(this, head, entry) { | ||
72 | if (identical(&this->addr, addr)) { | 84 | if (identical(&this->addr, addr)) { |
73 | spin_unlock_irqrestore(&dev->lock, flags); | 85 | spin_unlock_irqrestore(&dev->lock, flags); |
74 | return -EEXIST; | 86 | return -EEXIST; |
@@ -80,28 +92,36 @@ int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr) | |||
80 | return -ENOMEM; | 92 | return -ENOMEM; |
81 | } | 93 | } |
82 | this->addr = *addr; | 94 | this->addr = *addr; |
83 | list_add(&this->entry, &dev->local); | 95 | list_add(&this->entry, head); |
84 | spin_unlock_irqrestore(&dev->lock, flags); | 96 | spin_unlock_irqrestore(&dev->lock, flags); |
85 | notify_sigd(dev); | 97 | if (head == &dev->local) |
98 | notify_sigd(dev); | ||
86 | return 0; | 99 | return 0; |
87 | } | 100 | } |
88 | 101 | ||
89 | int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr) | 102 | int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, |
103 | enum atm_addr_type_t atype) | ||
90 | { | 104 | { |
91 | unsigned long flags; | 105 | unsigned long flags; |
92 | struct atm_dev_addr *this; | 106 | struct atm_dev_addr *this; |
107 | struct list_head *head; | ||
93 | int error; | 108 | int error; |
94 | 109 | ||
95 | error = check_addr(addr); | 110 | error = check_addr(addr); |
96 | if (error) | 111 | if (error) |
97 | return error; | 112 | return error; |
98 | spin_lock_irqsave(&dev->lock, flags); | 113 | spin_lock_irqsave(&dev->lock, flags); |
99 | list_for_each_entry(this, &dev->local, entry) { | 114 | if (atype == ATM_ADDR_LECS) |
115 | head = &dev->lecs; | ||
116 | else | ||
117 | head = &dev->local; | ||
118 | list_for_each_entry(this, head, entry) { | ||
100 | if (identical(&this->addr, addr)) { | 119 | if (identical(&this->addr, addr)) { |
101 | list_del(&this->entry); | 120 | list_del(&this->entry); |
102 | spin_unlock_irqrestore(&dev->lock, flags); | 121 | spin_unlock_irqrestore(&dev->lock, flags); |
103 | kfree(this); | 122 | kfree(this); |
104 | notify_sigd(dev); | 123 | if (head == &dev->local) |
124 | notify_sigd(dev); | ||
105 | return 0; | 125 | return 0; |
106 | } | 126 | } |
107 | } | 127 | } |
@@ -110,22 +130,27 @@ int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr) | |||
110 | } | 130 | } |
111 | 131 | ||
112 | int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf, | 132 | int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user * buf, |
113 | size_t size) | 133 | size_t size, enum atm_addr_type_t atype) |
114 | { | 134 | { |
115 | unsigned long flags; | 135 | unsigned long flags; |
116 | struct atm_dev_addr *this; | 136 | struct atm_dev_addr *this; |
137 | struct list_head *head; | ||
117 | int total = 0, error; | 138 | int total = 0, error; |
118 | struct sockaddr_atmsvc *tmp_buf, *tmp_bufp; | 139 | struct sockaddr_atmsvc *tmp_buf, *tmp_bufp; |
119 | 140 | ||
120 | spin_lock_irqsave(&dev->lock, flags); | 141 | spin_lock_irqsave(&dev->lock, flags); |
121 | list_for_each_entry(this, &dev->local, entry) | 142 | if (atype == ATM_ADDR_LECS) |
143 | head = &dev->lecs; | ||
144 | else | ||
145 | head = &dev->local; | ||
146 | list_for_each_entry(this, head, entry) | ||
122 | total += sizeof(struct sockaddr_atmsvc); | 147 | total += sizeof(struct sockaddr_atmsvc); |
123 | tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC); | 148 | tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC); |
124 | if (!tmp_buf) { | 149 | if (!tmp_buf) { |
125 | spin_unlock_irqrestore(&dev->lock, flags); | 150 | spin_unlock_irqrestore(&dev->lock, flags); |
126 | return -ENOMEM; | 151 | return -ENOMEM; |
127 | } | 152 | } |
128 | list_for_each_entry(this, &dev->local, entry) | 153 | list_for_each_entry(this, head, entry) |
129 | memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc)); | 154 | memcpy(tmp_bufp++, &this->addr, sizeof(struct sockaddr_atmsvc)); |
130 | spin_unlock_irqrestore(&dev->lock, flags); | 155 | spin_unlock_irqrestore(&dev->lock, flags); |
131 | error = total > size ? -E2BIG : total; | 156 | error = total > size ? -E2BIG : total; |
diff --git a/net/atm/addr.h b/net/atm/addr.h index 3099d21feeaa..f39433ad45da 100644 --- a/net/atm/addr.h +++ b/net/atm/addr.h | |||
@@ -9,10 +9,12 @@ | |||
9 | #include <linux/atm.h> | 9 | #include <linux/atm.h> |
10 | #include <linux/atmdev.h> | 10 | #include <linux/atmdev.h> |
11 | 11 | ||
12 | 12 | void atm_reset_addr(struct atm_dev *dev, enum atm_addr_type_t type); | |
13 | void atm_reset_addr(struct atm_dev *dev); | 13 | int atm_add_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, |
14 | int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); | 14 | enum atm_addr_type_t type); |
15 | int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr); | 15 | int atm_del_addr(struct atm_dev *dev, struct sockaddr_atmsvc *addr, |
16 | int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc __user *buf,size_t size); | 16 | enum atm_addr_type_t type); |
17 | int atm_get_addr(struct atm_dev *dev, struct sockaddr_atmsvc __user *buf, | ||
18 | size_t size, enum atm_addr_type_t type); | ||
17 | 19 | ||
18 | #endif | 20 | #endif |
diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 289956c4dd3e..72f3f7b8de80 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c | |||
@@ -220,7 +220,7 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
220 | /* netif_stop_queue(dev); */ | 220 | /* netif_stop_queue(dev); */ |
221 | dev_kfree_skb(skb); | 221 | dev_kfree_skb(skb); |
222 | read_unlock(&devs_lock); | 222 | read_unlock(&devs_lock); |
223 | return -EUNATCH; | 223 | return 0; |
224 | } | 224 | } |
225 | if (!br2684_xmit_vcc(skb, brdev, brvcc)) { | 225 | if (!br2684_xmit_vcc(skb, brdev, brvcc)) { |
226 | /* | 226 | /* |
diff --git a/net/atm/resources.c b/net/atm/resources.c index a57a9268bd24..415d2615d475 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c | |||
@@ -40,6 +40,7 @@ static struct atm_dev *__alloc_atm_dev(const char *type) | |||
40 | dev->link_rate = ATM_OC3_PCR; | 40 | dev->link_rate = ATM_OC3_PCR; |
41 | spin_lock_init(&dev->lock); | 41 | spin_lock_init(&dev->lock); |
42 | INIT_LIST_HEAD(&dev->local); | 42 | INIT_LIST_HEAD(&dev->local); |
43 | INIT_LIST_HEAD(&dev->lecs); | ||
43 | 44 | ||
44 | return dev; | 45 | return dev; |
45 | } | 46 | } |
@@ -320,10 +321,12 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
320 | error = -EPERM; | 321 | error = -EPERM; |
321 | goto done; | 322 | goto done; |
322 | } | 323 | } |
323 | atm_reset_addr(dev); | 324 | atm_reset_addr(dev, ATM_ADDR_LOCAL); |
324 | break; | 325 | break; |
325 | case ATM_ADDADDR: | 326 | case ATM_ADDADDR: |
326 | case ATM_DELADDR: | 327 | case ATM_DELADDR: |
328 | case ATM_ADDLECSADDR: | ||
329 | case ATM_DELLECSADDR: | ||
327 | if (!capable(CAP_NET_ADMIN)) { | 330 | if (!capable(CAP_NET_ADMIN)) { |
328 | error = -EPERM; | 331 | error = -EPERM; |
329 | goto done; | 332 | goto done; |
@@ -335,14 +338,21 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
335 | error = -EFAULT; | 338 | error = -EFAULT; |
336 | goto done; | 339 | goto done; |
337 | } | 340 | } |
338 | if (cmd == ATM_ADDADDR) | 341 | if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR) |
339 | error = atm_add_addr(dev, &addr); | 342 | error = atm_add_addr(dev, &addr, |
343 | (cmd == ATM_ADDADDR ? | ||
344 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); | ||
340 | else | 345 | else |
341 | error = atm_del_addr(dev, &addr); | 346 | error = atm_del_addr(dev, &addr, |
347 | (cmd == ATM_DELADDR ? | ||
348 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); | ||
342 | goto done; | 349 | goto done; |
343 | } | 350 | } |
344 | case ATM_GETADDR: | 351 | case ATM_GETADDR: |
345 | error = atm_get_addr(dev, buf, len); | 352 | case ATM_GETLECSADDR: |
353 | error = atm_get_addr(dev, buf, len, | ||
354 | (cmd == ATM_GETADDR ? | ||
355 | ATM_ADDR_LOCAL : ATM_ADDR_LECS)); | ||
346 | if (error < 0) | 356 | if (error < 0) |
347 | goto done; | 357 | goto done; |
348 | size = error; | 358 | size = error; |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 91ec8c936913..02e068d3450d 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -3159,8 +3159,9 @@ static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval | |||
3159 | return 0; | 3159 | return 0; |
3160 | } | 3160 | } |
3161 | 3161 | ||
3162 | static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, | 3162 | static int sctp_getsockopt_peer_addrs_num_old(struct sock *sk, int len, |
3163 | char __user *optval, int __user *optlen) | 3163 | char __user *optval, |
3164 | int __user *optlen) | ||
3164 | { | 3165 | { |
3165 | sctp_assoc_t id; | 3166 | sctp_assoc_t id; |
3166 | struct sctp_association *asoc; | 3167 | struct sctp_association *asoc; |
@@ -3185,23 +3186,28 @@ static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, | |||
3185 | return cnt; | 3186 | return cnt; |
3186 | } | 3187 | } |
3187 | 3188 | ||
3188 | static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, | 3189 | /* |
3189 | char __user *optval, int __user *optlen) | 3190 | * Old API for getting list of peer addresses. Does not work for 32-bit |
3191 | * programs running on a 64-bit kernel | ||
3192 | */ | ||
3193 | static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len, | ||
3194 | char __user *optval, | ||
3195 | int __user *optlen) | ||
3190 | { | 3196 | { |
3191 | struct sctp_association *asoc; | 3197 | struct sctp_association *asoc; |
3192 | struct list_head *pos; | 3198 | struct list_head *pos; |
3193 | int cnt = 0; | 3199 | int cnt = 0; |
3194 | struct sctp_getaddrs getaddrs; | 3200 | struct sctp_getaddrs_old getaddrs; |
3195 | struct sctp_transport *from; | 3201 | struct sctp_transport *from; |
3196 | void __user *to; | 3202 | void __user *to; |
3197 | union sctp_addr temp; | 3203 | union sctp_addr temp; |
3198 | struct sctp_sock *sp = sctp_sk(sk); | 3204 | struct sctp_sock *sp = sctp_sk(sk); |
3199 | int addrlen; | 3205 | int addrlen; |
3200 | 3206 | ||
3201 | if (len != sizeof(struct sctp_getaddrs)) | 3207 | if (len != sizeof(struct sctp_getaddrs_old)) |
3202 | return -EINVAL; | 3208 | return -EINVAL; |
3203 | 3209 | ||
3204 | if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) | 3210 | if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs_old))) |
3205 | return -EFAULT; | 3211 | return -EFAULT; |
3206 | 3212 | ||
3207 | if (getaddrs.addr_num <= 0) return -EINVAL; | 3213 | if (getaddrs.addr_num <= 0) return -EINVAL; |
@@ -3225,15 +3231,69 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, | |||
3225 | if (cnt >= getaddrs.addr_num) break; | 3231 | if (cnt >= getaddrs.addr_num) break; |
3226 | } | 3232 | } |
3227 | getaddrs.addr_num = cnt; | 3233 | getaddrs.addr_num = cnt; |
3228 | if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs))) | 3234 | if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old))) |
3235 | return -EFAULT; | ||
3236 | |||
3237 | return 0; | ||
3238 | } | ||
3239 | |||
3240 | static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, | ||
3241 | char __user *optval, int __user *optlen) | ||
3242 | { | ||
3243 | struct sctp_association *asoc; | ||
3244 | struct list_head *pos; | ||
3245 | int cnt = 0; | ||
3246 | struct sctp_getaddrs getaddrs; | ||
3247 | struct sctp_transport *from; | ||
3248 | void __user *to; | ||
3249 | union sctp_addr temp; | ||
3250 | struct sctp_sock *sp = sctp_sk(sk); | ||
3251 | int addrlen; | ||
3252 | size_t space_left; | ||
3253 | int bytes_copied; | ||
3254 | |||
3255 | if (len < sizeof(struct sctp_getaddrs)) | ||
3256 | return -EINVAL; | ||
3257 | |||
3258 | if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) | ||
3259 | return -EFAULT; | ||
3260 | |||
3261 | /* For UDP-style sockets, id specifies the association to query. */ | ||
3262 | asoc = sctp_id2assoc(sk, getaddrs.assoc_id); | ||
3263 | if (!asoc) | ||
3264 | return -EINVAL; | ||
3265 | |||
3266 | to = optval + offsetof(struct sctp_getaddrs,addrs); | ||
3267 | space_left = len - sizeof(struct sctp_getaddrs) - | ||
3268 | offsetof(struct sctp_getaddrs,addrs); | ||
3269 | |||
3270 | list_for_each(pos, &asoc->peer.transport_addr_list) { | ||
3271 | from = list_entry(pos, struct sctp_transport, transports); | ||
3272 | memcpy(&temp, &from->ipaddr, sizeof(temp)); | ||
3273 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); | ||
3274 | addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len; | ||
3275 | if(space_left < addrlen) | ||
3276 | return -ENOMEM; | ||
3277 | temp.v4.sin_port = htons(temp.v4.sin_port); | ||
3278 | if (copy_to_user(to, &temp, addrlen)) | ||
3279 | return -EFAULT; | ||
3280 | to += addrlen; | ||
3281 | cnt++; | ||
3282 | space_left -= addrlen; | ||
3283 | } | ||
3284 | |||
3285 | if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) | ||
3286 | return -EFAULT; | ||
3287 | bytes_copied = ((char __user *)to) - optval; | ||
3288 | if (put_user(bytes_copied, optlen)) | ||
3229 | return -EFAULT; | 3289 | return -EFAULT; |
3230 | 3290 | ||
3231 | return 0; | 3291 | return 0; |
3232 | } | 3292 | } |
3233 | 3293 | ||
3234 | static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len, | 3294 | static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, |
3235 | char __user *optval, | 3295 | char __user *optval, |
3236 | int __user *optlen) | 3296 | int __user *optlen) |
3237 | { | 3297 | { |
3238 | sctp_assoc_t id; | 3298 | sctp_assoc_t id; |
3239 | struct sctp_bind_addr *bp; | 3299 | struct sctp_bind_addr *bp; |
@@ -3306,8 +3366,8 @@ done: | |||
3306 | /* Helper function that copies local addresses to user and returns the number | 3366 | /* Helper function that copies local addresses to user and returns the number |
3307 | * of addresses copied. | 3367 | * of addresses copied. |
3308 | */ | 3368 | */ |
3309 | static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, int max_addrs, | 3369 | static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs, |
3310 | void __user *to) | 3370 | void __user *to) |
3311 | { | 3371 | { |
3312 | struct list_head *pos; | 3372 | struct list_head *pos; |
3313 | struct sctp_sockaddr_entry *addr; | 3373 | struct sctp_sockaddr_entry *addr; |
@@ -3341,14 +3401,54 @@ static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, int max_addrs, | |||
3341 | return cnt; | 3401 | return cnt; |
3342 | } | 3402 | } |
3343 | 3403 | ||
3344 | static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | 3404 | static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, |
3345 | char __user *optval, int __user *optlen) | 3405 | void * __user *to, size_t space_left) |
3406 | { | ||
3407 | struct list_head *pos; | ||
3408 | struct sctp_sockaddr_entry *addr; | ||
3409 | unsigned long flags; | ||
3410 | union sctp_addr temp; | ||
3411 | int cnt = 0; | ||
3412 | int addrlen; | ||
3413 | |||
3414 | sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); | ||
3415 | list_for_each(pos, &sctp_local_addr_list) { | ||
3416 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); | ||
3417 | if ((PF_INET == sk->sk_family) && | ||
3418 | (AF_INET6 == addr->a.sa.sa_family)) | ||
3419 | continue; | ||
3420 | memcpy(&temp, &addr->a, sizeof(temp)); | ||
3421 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), | ||
3422 | &temp); | ||
3423 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | ||
3424 | if(space_left<addrlen) | ||
3425 | return -ENOMEM; | ||
3426 | temp.v4.sin_port = htons(port); | ||
3427 | if (copy_to_user(*to, &temp, addrlen)) { | ||
3428 | sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, | ||
3429 | flags); | ||
3430 | return -EFAULT; | ||
3431 | } | ||
3432 | *to += addrlen; | ||
3433 | cnt ++; | ||
3434 | space_left -= addrlen; | ||
3435 | } | ||
3436 | sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags); | ||
3437 | |||
3438 | return cnt; | ||
3439 | } | ||
3440 | |||
3441 | /* Old API for getting list of local addresses. Does not work for 32-bit | ||
3442 | * programs running on a 64-bit kernel | ||
3443 | */ | ||
3444 | static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, | ||
3445 | char __user *optval, int __user *optlen) | ||
3346 | { | 3446 | { |
3347 | struct sctp_bind_addr *bp; | 3447 | struct sctp_bind_addr *bp; |
3348 | struct sctp_association *asoc; | 3448 | struct sctp_association *asoc; |
3349 | struct list_head *pos; | 3449 | struct list_head *pos; |
3350 | int cnt = 0; | 3450 | int cnt = 0; |
3351 | struct sctp_getaddrs getaddrs; | 3451 | struct sctp_getaddrs_old getaddrs; |
3352 | struct sctp_sockaddr_entry *addr; | 3452 | struct sctp_sockaddr_entry *addr; |
3353 | void __user *to; | 3453 | void __user *to; |
3354 | union sctp_addr temp; | 3454 | union sctp_addr temp; |
@@ -3357,10 +3457,10 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
3357 | rwlock_t *addr_lock; | 3457 | rwlock_t *addr_lock; |
3358 | int err = 0; | 3458 | int err = 0; |
3359 | 3459 | ||
3360 | if (len != sizeof(struct sctp_getaddrs)) | 3460 | if (len != sizeof(struct sctp_getaddrs_old)) |
3361 | return -EINVAL; | 3461 | return -EINVAL; |
3362 | 3462 | ||
3363 | if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) | 3463 | if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs_old))) |
3364 | return -EFAULT; | 3464 | return -EFAULT; |
3365 | 3465 | ||
3366 | if (getaddrs.addr_num <= 0) return -EINVAL; | 3466 | if (getaddrs.addr_num <= 0) return -EINVAL; |
@@ -3392,8 +3492,9 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
3392 | addr = list_entry(bp->address_list.next, | 3492 | addr = list_entry(bp->address_list.next, |
3393 | struct sctp_sockaddr_entry, list); | 3493 | struct sctp_sockaddr_entry, list); |
3394 | if (sctp_is_any(&addr->a)) { | 3494 | if (sctp_is_any(&addr->a)) { |
3395 | cnt = sctp_copy_laddrs_to_user(sk, bp->port, | 3495 | cnt = sctp_copy_laddrs_to_user_old(sk, bp->port, |
3396 | getaddrs.addr_num, to); | 3496 | getaddrs.addr_num, |
3497 | to); | ||
3397 | if (cnt < 0) { | 3498 | if (cnt < 0) { |
3398 | err = cnt; | 3499 | err = cnt; |
3399 | goto unlock; | 3500 | goto unlock; |
@@ -3419,7 +3520,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
3419 | 3520 | ||
3420 | copy_getaddrs: | 3521 | copy_getaddrs: |
3421 | getaddrs.addr_num = cnt; | 3522 | getaddrs.addr_num = cnt; |
3422 | if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs))) | 3523 | if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old))) |
3423 | err = -EFAULT; | 3524 | err = -EFAULT; |
3424 | 3525 | ||
3425 | unlock: | 3526 | unlock: |
@@ -3427,6 +3528,99 @@ unlock: | |||
3427 | return err; | 3528 | return err; |
3428 | } | 3529 | } |
3429 | 3530 | ||
3531 | static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | ||
3532 | char __user *optval, int __user *optlen) | ||
3533 | { | ||
3534 | struct sctp_bind_addr *bp; | ||
3535 | struct sctp_association *asoc; | ||
3536 | struct list_head *pos; | ||
3537 | int cnt = 0; | ||
3538 | struct sctp_getaddrs getaddrs; | ||
3539 | struct sctp_sockaddr_entry *addr; | ||
3540 | void __user *to; | ||
3541 | union sctp_addr temp; | ||
3542 | struct sctp_sock *sp = sctp_sk(sk); | ||
3543 | int addrlen; | ||
3544 | rwlock_t *addr_lock; | ||
3545 | int err = 0; | ||
3546 | size_t space_left; | ||
3547 | int bytes_copied; | ||
3548 | |||
3549 | if (len <= sizeof(struct sctp_getaddrs)) | ||
3550 | return -EINVAL; | ||
3551 | |||
3552 | if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) | ||
3553 | return -EFAULT; | ||
3554 | |||
3555 | /* | ||
3556 | * For UDP-style sockets, id specifies the association to query. | ||
3557 | * If the id field is set to the value '0' then the locally bound | ||
3558 | * addresses are returned without regard to any particular | ||
3559 | * association. | ||
3560 | */ | ||
3561 | if (0 == getaddrs.assoc_id) { | ||
3562 | bp = &sctp_sk(sk)->ep->base.bind_addr; | ||
3563 | addr_lock = &sctp_sk(sk)->ep->base.addr_lock; | ||
3564 | } else { | ||
3565 | asoc = sctp_id2assoc(sk, getaddrs.assoc_id); | ||
3566 | if (!asoc) | ||
3567 | return -EINVAL; | ||
3568 | bp = &asoc->base.bind_addr; | ||
3569 | addr_lock = &asoc->base.addr_lock; | ||
3570 | } | ||
3571 | |||
3572 | to = optval + offsetof(struct sctp_getaddrs,addrs); | ||
3573 | space_left = len - sizeof(struct sctp_getaddrs) - | ||
3574 | offsetof(struct sctp_getaddrs,addrs); | ||
3575 | |||
3576 | sctp_read_lock(addr_lock); | ||
3577 | |||
3578 | /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid | ||
3579 | * addresses from the global local address list. | ||
3580 | */ | ||
3581 | if (sctp_list_single_entry(&bp->address_list)) { | ||
3582 | addr = list_entry(bp->address_list.next, | ||
3583 | struct sctp_sockaddr_entry, list); | ||
3584 | if (sctp_is_any(&addr->a)) { | ||
3585 | cnt = sctp_copy_laddrs_to_user(sk, bp->port, | ||
3586 | &to, space_left); | ||
3587 | if (cnt < 0) { | ||
3588 | err = cnt; | ||
3589 | goto unlock; | ||
3590 | } | ||
3591 | goto copy_getaddrs; | ||
3592 | } | ||
3593 | } | ||
3594 | |||
3595 | list_for_each(pos, &bp->address_list) { | ||
3596 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); | ||
3597 | memcpy(&temp, &addr->a, sizeof(temp)); | ||
3598 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); | ||
3599 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | ||
3600 | if(space_left < addrlen) | ||
3601 | return -ENOMEM; /*fixme: right error?*/ | ||
3602 | temp.v4.sin_port = htons(temp.v4.sin_port); | ||
3603 | if (copy_to_user(to, &temp, addrlen)) { | ||
3604 | err = -EFAULT; | ||
3605 | goto unlock; | ||
3606 | } | ||
3607 | to += addrlen; | ||
3608 | cnt ++; | ||
3609 | space_left -= addrlen; | ||
3610 | } | ||
3611 | |||
3612 | copy_getaddrs: | ||
3613 | if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) | ||
3614 | return -EFAULT; | ||
3615 | bytes_copied = ((char __user *)to) - optval; | ||
3616 | if (put_user(bytes_copied, optlen)) | ||
3617 | return -EFAULT; | ||
3618 | |||
3619 | unlock: | ||
3620 | sctp_read_unlock(addr_lock); | ||
3621 | return err; | ||
3622 | } | ||
3623 | |||
3430 | /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) | 3624 | /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) |
3431 | * | 3625 | * |
3432 | * Requests that the local SCTP stack use the enclosed peer address as | 3626 | * Requests that the local SCTP stack use the enclosed peer address as |
@@ -3807,12 +4001,20 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
3807 | case SCTP_INITMSG: | 4001 | case SCTP_INITMSG: |
3808 | retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); | 4002 | retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); |
3809 | break; | 4003 | break; |
3810 | case SCTP_GET_PEER_ADDRS_NUM: | 4004 | case SCTP_GET_PEER_ADDRS_NUM_OLD: |
3811 | retval = sctp_getsockopt_peer_addrs_num(sk, len, optval, | 4005 | retval = sctp_getsockopt_peer_addrs_num_old(sk, len, optval, |
4006 | optlen); | ||
4007 | break; | ||
4008 | case SCTP_GET_LOCAL_ADDRS_NUM_OLD: | ||
4009 | retval = sctp_getsockopt_local_addrs_num_old(sk, len, optval, | ||
4010 | optlen); | ||
4011 | break; | ||
4012 | case SCTP_GET_PEER_ADDRS_OLD: | ||
4013 | retval = sctp_getsockopt_peer_addrs_old(sk, len, optval, | ||
3812 | optlen); | 4014 | optlen); |
3813 | break; | 4015 | break; |
3814 | case SCTP_GET_LOCAL_ADDRS_NUM: | 4016 | case SCTP_GET_LOCAL_ADDRS_OLD: |
3815 | retval = sctp_getsockopt_local_addrs_num(sk, len, optval, | 4017 | retval = sctp_getsockopt_local_addrs_old(sk, len, optval, |
3816 | optlen); | 4018 | optlen); |
3817 | break; | 4019 | break; |
3818 | case SCTP_GET_PEER_ADDRS: | 4020 | case SCTP_GET_PEER_ADDRS: |