diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-23 23:44:19 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-03-23 23:44:19 -0500 |
commit | 1ebbe2b20091d306453a5cf480a87e6cd28ae76f (patch) | |
tree | f5cd7a0fa69b8b1938cb5a0faed2e7b0628072a5 /net | |
parent | ac58c9059da8886b5e8cde012a80266b18ca146e (diff) | |
parent | 674a396c6d2ba0341ebdd7c1c9950f32f018e2dd (diff) |
Merge branch 'linus'
Diffstat (limited to 'net')
283 files changed, 21060 insertions, 6525 deletions
diff --git a/net/802/psnap.c b/net/802/psnap.c index 34e42968b477..270b9d2cae65 100644 --- a/net/802/psnap.c +++ b/net/802/psnap.c | |||
@@ -59,10 +59,8 @@ static int snap_rcv(struct sk_buff *skb, struct net_device *dev, | |||
59 | proto = find_snap_client(skb->h.raw); | 59 | proto = find_snap_client(skb->h.raw); |
60 | if (proto) { | 60 | if (proto) { |
61 | /* Pass the frame on. */ | 61 | /* Pass the frame on. */ |
62 | u8 *hdr = skb->data; | ||
63 | skb->h.raw += 5; | 62 | skb->h.raw += 5; |
64 | skb_pull(skb, 5); | 63 | skb_pull_rcsum(skb, 5); |
65 | skb_postpull_rcsum(skb, hdr, 5); | ||
66 | rc = proto->rcvfunc(skb, dev, &snap_packet_type, orig_dev); | 64 | rc = proto->rcvfunc(skb, dev, &snap_packet_type, orig_dev); |
67 | } else { | 65 | } else { |
68 | skb->sk = NULL; | 66 | skb->sk = NULL; |
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index fa76220708ce..3948949a609a 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -69,7 +69,7 @@ static struct packet_type vlan_packet_type = { | |||
69 | 69 | ||
70 | /* Bits of netdev state that are propagated from real device to virtual */ | 70 | /* Bits of netdev state that are propagated from real device to virtual */ |
71 | #define VLAN_LINK_STATE_MASK \ | 71 | #define VLAN_LINK_STATE_MASK \ |
72 | ((1<<__LINK_STATE_PRESENT)|(1<<__LINK_STATE_NOCARRIER)) | 72 | ((1<<__LINK_STATE_PRESENT)|(1<<__LINK_STATE_NOCARRIER)|(1<<__LINK_STATE_DORMANT)) |
73 | 73 | ||
74 | /* End of global variables definitions. */ | 74 | /* End of global variables definitions. */ |
75 | 75 | ||
@@ -344,6 +344,26 @@ static void vlan_setup(struct net_device *new_dev) | |||
344 | new_dev->do_ioctl = vlan_dev_ioctl; | 344 | new_dev->do_ioctl = vlan_dev_ioctl; |
345 | } | 345 | } |
346 | 346 | ||
347 | static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev) | ||
348 | { | ||
349 | /* Have to respect userspace enforced dormant state | ||
350 | * of real device, also must allow supplicant running | ||
351 | * on VLAN device | ||
352 | */ | ||
353 | if (dev->operstate == IF_OPER_DORMANT) | ||
354 | netif_dormant_on(vlandev); | ||
355 | else | ||
356 | netif_dormant_off(vlandev); | ||
357 | |||
358 | if (netif_carrier_ok(dev)) { | ||
359 | if (!netif_carrier_ok(vlandev)) | ||
360 | netif_carrier_on(vlandev); | ||
361 | } else { | ||
362 | if (netif_carrier_ok(vlandev)) | ||
363 | netif_carrier_off(vlandev); | ||
364 | } | ||
365 | } | ||
366 | |||
347 | /* Attach a VLAN device to a mac address (ie Ethernet Card). | 367 | /* Attach a VLAN device to a mac address (ie Ethernet Card). |
348 | * Returns the device that was created, or NULL if there was | 368 | * Returns the device that was created, or NULL if there was |
349 | * an error of some kind. | 369 | * an error of some kind. |
@@ -450,7 +470,7 @@ static struct net_device *register_vlan_device(const char *eth_IF_name, | |||
450 | new_dev->flags = real_dev->flags; | 470 | new_dev->flags = real_dev->flags; |
451 | new_dev->flags &= ~IFF_UP; | 471 | new_dev->flags &= ~IFF_UP; |
452 | 472 | ||
453 | new_dev->state = real_dev->state & VLAN_LINK_STATE_MASK; | 473 | new_dev->state = real_dev->state & ~(1<<__LINK_STATE_START); |
454 | 474 | ||
455 | /* need 4 bytes for extra VLAN header info, | 475 | /* need 4 bytes for extra VLAN header info, |
456 | * hope the underlying device can handle it. | 476 | * hope the underlying device can handle it. |
@@ -498,6 +518,10 @@ static struct net_device *register_vlan_device(const char *eth_IF_name, | |||
498 | if (register_netdevice(new_dev)) | 518 | if (register_netdevice(new_dev)) |
499 | goto out_free_newdev; | 519 | goto out_free_newdev; |
500 | 520 | ||
521 | new_dev->iflink = real_dev->ifindex; | ||
522 | vlan_transfer_operstate(real_dev, new_dev); | ||
523 | linkwatch_fire_event(new_dev); /* _MUST_ call rfc2863_policy() */ | ||
524 | |||
501 | /* So, got the sucker initialized, now lets place | 525 | /* So, got the sucker initialized, now lets place |
502 | * it into our local structure. | 526 | * it into our local structure. |
503 | */ | 527 | */ |
@@ -573,25 +597,12 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
573 | switch (event) { | 597 | switch (event) { |
574 | case NETDEV_CHANGE: | 598 | case NETDEV_CHANGE: |
575 | /* Propagate real device state to vlan devices */ | 599 | /* Propagate real device state to vlan devices */ |
576 | flgs = dev->state & VLAN_LINK_STATE_MASK; | ||
577 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 600 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { |
578 | vlandev = grp->vlan_devices[i]; | 601 | vlandev = grp->vlan_devices[i]; |
579 | if (!vlandev) | 602 | if (!vlandev) |
580 | continue; | 603 | continue; |
581 | 604 | ||
582 | if (netif_carrier_ok(dev)) { | 605 | vlan_transfer_operstate(dev, vlandev); |
583 | if (!netif_carrier_ok(vlandev)) | ||
584 | netif_carrier_on(vlandev); | ||
585 | } else { | ||
586 | if (netif_carrier_ok(vlandev)) | ||
587 | netif_carrier_off(vlandev); | ||
588 | } | ||
589 | |||
590 | if ((vlandev->state & VLAN_LINK_STATE_MASK) != flgs) { | ||
591 | vlandev->state = (vlandev->state &~ VLAN_LINK_STATE_MASK) | ||
592 | | flgs; | ||
593 | netdev_state_change(vlandev); | ||
594 | } | ||
595 | } | 606 | } |
596 | break; | 607 | break; |
597 | 608 | ||
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 0f604d227da2..da9cfe927158 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
@@ -163,10 +163,8 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, | |||
163 | stats->rx_packets++; | 163 | stats->rx_packets++; |
164 | stats->rx_bytes += skb->len; | 164 | stats->rx_bytes += skb->len; |
165 | 165 | ||
166 | skb_pull(skb, VLAN_HLEN); /* take off the VLAN header (4 bytes currently) */ | 166 | /* Take off the VLAN header (4 bytes currently) */ |
167 | 167 | skb_pull_rcsum(skb, VLAN_HLEN); | |
168 | /* Need to correct hardware checksum */ | ||
169 | skb_postpull_rcsum(skb, vhdr, VLAN_HLEN); | ||
170 | 168 | ||
171 | /* Ok, lets check to make sure the device (dev) we | 169 | /* Ok, lets check to make sure the device (dev) we |
172 | * came in on is what this VLAN is attached to. | 170 | * came in on is what this VLAN is attached to. |
diff --git a/net/atm/clip.c b/net/atm/clip.c index 73370de97539..3ab4e7947bab 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c | |||
@@ -289,7 +289,6 @@ static void clip_neigh_error(struct neighbour *neigh,struct sk_buff *skb) | |||
289 | 289 | ||
290 | static struct neigh_ops clip_neigh_ops = { | 290 | static struct neigh_ops clip_neigh_ops = { |
291 | .family = AF_INET, | 291 | .family = AF_INET, |
292 | .destructor = clip_neigh_destroy, | ||
293 | .solicit = clip_neigh_solicit, | 292 | .solicit = clip_neigh_solicit, |
294 | .error_report = clip_neigh_error, | 293 | .error_report = clip_neigh_error, |
295 | .output = dev_queue_xmit, | 294 | .output = dev_queue_xmit, |
@@ -347,6 +346,7 @@ static struct neigh_table clip_tbl = { | |||
347 | /* parameters are copied from ARP ... */ | 346 | /* parameters are copied from ARP ... */ |
348 | .parms = { | 347 | .parms = { |
349 | .tbl = &clip_tbl, | 348 | .tbl = &clip_tbl, |
349 | .neigh_destructor = clip_neigh_destroy, | ||
350 | .base_reachable_time = 30 * HZ, | 350 | .base_reachable_time = 30 * HZ, |
351 | .retrans_time = 1 * HZ, | 351 | .retrans_time = 1 * HZ, |
352 | .gc_staletime = 60 * HZ, | 352 | .gc_staletime = 60 * HZ, |
diff --git a/net/atm/common.c b/net/atm/common.c index 6656b111cc05..ae002220fa99 100644 --- a/net/atm/common.c +++ b/net/atm/common.c | |||
@@ -451,12 +451,12 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci) | |||
451 | dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf); | 451 | dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf); |
452 | } else { | 452 | } else { |
453 | dev = NULL; | 453 | dev = NULL; |
454 | down(&atm_dev_mutex); | 454 | mutex_lock(&atm_dev_mutex); |
455 | if (!list_empty(&atm_devs)) { | 455 | if (!list_empty(&atm_devs)) { |
456 | dev = list_entry(atm_devs.next, struct atm_dev, dev_list); | 456 | dev = list_entry(atm_devs.next, struct atm_dev, dev_list); |
457 | atm_dev_hold(dev); | 457 | atm_dev_hold(dev); |
458 | } | 458 | } |
459 | up(&atm_dev_mutex); | 459 | mutex_unlock(&atm_dev_mutex); |
460 | } | 460 | } |
461 | if (!dev) | 461 | if (!dev) |
462 | return -ENODEV; | 462 | return -ENODEV; |
diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c index eb109af7eb4a..851cfa6312af 100644 --- a/net/atm/ioctl.c +++ b/net/atm/ioctl.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/atmmpc.h> | 18 | #include <linux/atmmpc.h> |
19 | #include <net/atmclip.h> | 19 | #include <net/atmclip.h> |
20 | #include <linux/atmlec.h> | 20 | #include <linux/atmlec.h> |
21 | #include <linux/mutex.h> | ||
21 | #include <asm/ioctls.h> | 22 | #include <asm/ioctls.h> |
22 | 23 | ||
23 | #include "resources.h" | 24 | #include "resources.h" |
@@ -25,22 +26,22 @@ | |||
25 | #include "common.h" | 26 | #include "common.h" |
26 | 27 | ||
27 | 28 | ||
28 | static DECLARE_MUTEX(ioctl_mutex); | 29 | static DEFINE_MUTEX(ioctl_mutex); |
29 | static LIST_HEAD(ioctl_list); | 30 | static LIST_HEAD(ioctl_list); |
30 | 31 | ||
31 | 32 | ||
32 | void register_atm_ioctl(struct atm_ioctl *ioctl) | 33 | void register_atm_ioctl(struct atm_ioctl *ioctl) |
33 | { | 34 | { |
34 | down(&ioctl_mutex); | 35 | mutex_lock(&ioctl_mutex); |
35 | list_add_tail(&ioctl->list, &ioctl_list); | 36 | list_add_tail(&ioctl->list, &ioctl_list); |
36 | up(&ioctl_mutex); | 37 | mutex_unlock(&ioctl_mutex); |
37 | } | 38 | } |
38 | 39 | ||
39 | void deregister_atm_ioctl(struct atm_ioctl *ioctl) | 40 | void deregister_atm_ioctl(struct atm_ioctl *ioctl) |
40 | { | 41 | { |
41 | down(&ioctl_mutex); | 42 | mutex_lock(&ioctl_mutex); |
42 | list_del(&ioctl->list); | 43 | list_del(&ioctl->list); |
43 | up(&ioctl_mutex); | 44 | mutex_unlock(&ioctl_mutex); |
44 | } | 45 | } |
45 | 46 | ||
46 | EXPORT_SYMBOL(register_atm_ioctl); | 47 | EXPORT_SYMBOL(register_atm_ioctl); |
@@ -137,7 +138,7 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
137 | 138 | ||
138 | error = -ENOIOCTLCMD; | 139 | error = -ENOIOCTLCMD; |
139 | 140 | ||
140 | down(&ioctl_mutex); | 141 | mutex_lock(&ioctl_mutex); |
141 | list_for_each(pos, &ioctl_list) { | 142 | list_for_each(pos, &ioctl_list) { |
142 | struct atm_ioctl * ic = list_entry(pos, struct atm_ioctl, list); | 143 | struct atm_ioctl * ic = list_entry(pos, struct atm_ioctl, list); |
143 | if (try_module_get(ic->owner)) { | 144 | if (try_module_get(ic->owner)) { |
@@ -147,7 +148,7 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
147 | break; | 148 | break; |
148 | } | 149 | } |
149 | } | 150 | } |
150 | up(&ioctl_mutex); | 151 | mutex_unlock(&ioctl_mutex); |
151 | 152 | ||
152 | if (error != -ENOIOCTLCMD) | 153 | if (error != -ENOIOCTLCMD) |
153 | goto done; | 154 | goto done; |
diff --git a/net/atm/resources.c b/net/atm/resources.c index 224190537c90..18ac80698f83 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/bitops.h> | 18 | #include <linux/bitops.h> |
19 | #include <linux/capability.h> | 19 | #include <linux/capability.h> |
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/mutex.h> | ||
22 | |||
21 | #include <net/sock.h> /* for struct sock */ | 23 | #include <net/sock.h> /* for struct sock */ |
22 | 24 | ||
23 | #include "common.h" | 25 | #include "common.h" |
@@ -26,7 +28,7 @@ | |||
26 | 28 | ||
27 | 29 | ||
28 | LIST_HEAD(atm_devs); | 30 | LIST_HEAD(atm_devs); |
29 | DECLARE_MUTEX(atm_dev_mutex); | 31 | DEFINE_MUTEX(atm_dev_mutex); |
30 | 32 | ||
31 | static struct atm_dev *__alloc_atm_dev(const char *type) | 33 | static struct atm_dev *__alloc_atm_dev(const char *type) |
32 | { | 34 | { |
@@ -65,9 +67,9 @@ struct atm_dev *atm_dev_lookup(int number) | |||
65 | { | 67 | { |
66 | struct atm_dev *dev; | 68 | struct atm_dev *dev; |
67 | 69 | ||
68 | down(&atm_dev_mutex); | 70 | mutex_lock(&atm_dev_mutex); |
69 | dev = __atm_dev_lookup(number); | 71 | dev = __atm_dev_lookup(number); |
70 | up(&atm_dev_mutex); | 72 | mutex_unlock(&atm_dev_mutex); |
71 | return dev; | 73 | return dev; |
72 | } | 74 | } |
73 | 75 | ||
@@ -83,11 +85,11 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, | |||
83 | type); | 85 | type); |
84 | return NULL; | 86 | return NULL; |
85 | } | 87 | } |
86 | down(&atm_dev_mutex); | 88 | mutex_lock(&atm_dev_mutex); |
87 | if (number != -1) { | 89 | if (number != -1) { |
88 | if ((inuse = __atm_dev_lookup(number))) { | 90 | if ((inuse = __atm_dev_lookup(number))) { |
89 | atm_dev_put(inuse); | 91 | atm_dev_put(inuse); |
90 | up(&atm_dev_mutex); | 92 | mutex_unlock(&atm_dev_mutex); |
91 | kfree(dev); | 93 | kfree(dev); |
92 | return NULL; | 94 | return NULL; |
93 | } | 95 | } |
@@ -112,12 +114,12 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, | |||
112 | printk(KERN_ERR "atm_dev_register: " | 114 | printk(KERN_ERR "atm_dev_register: " |
113 | "atm_proc_dev_register failed for dev %s\n", | 115 | "atm_proc_dev_register failed for dev %s\n", |
114 | type); | 116 | type); |
115 | up(&atm_dev_mutex); | 117 | mutex_unlock(&atm_dev_mutex); |
116 | kfree(dev); | 118 | kfree(dev); |
117 | return NULL; | 119 | return NULL; |
118 | } | 120 | } |
119 | list_add_tail(&dev->dev_list, &atm_devs); | 121 | list_add_tail(&dev->dev_list, &atm_devs); |
120 | up(&atm_dev_mutex); | 122 | mutex_unlock(&atm_dev_mutex); |
121 | 123 | ||
122 | return dev; | 124 | return dev; |
123 | } | 125 | } |
@@ -133,9 +135,9 @@ void atm_dev_deregister(struct atm_dev *dev) | |||
133 | * with same number can appear, such we need deregister proc, | 135 | * with same number can appear, such we need deregister proc, |
134 | * release async all vccs and remove them from vccs list too | 136 | * release async all vccs and remove them from vccs list too |
135 | */ | 137 | */ |
136 | down(&atm_dev_mutex); | 138 | mutex_lock(&atm_dev_mutex); |
137 | list_del(&dev->dev_list); | 139 | list_del(&dev->dev_list); |
138 | up(&atm_dev_mutex); | 140 | mutex_unlock(&atm_dev_mutex); |
139 | 141 | ||
140 | atm_dev_release_vccs(dev); | 142 | atm_dev_release_vccs(dev); |
141 | atm_proc_dev_deregister(dev); | 143 | atm_proc_dev_deregister(dev); |
@@ -196,16 +198,16 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
196 | return -EFAULT; | 198 | return -EFAULT; |
197 | if (get_user(len, &iobuf->length)) | 199 | if (get_user(len, &iobuf->length)) |
198 | return -EFAULT; | 200 | return -EFAULT; |
199 | down(&atm_dev_mutex); | 201 | mutex_lock(&atm_dev_mutex); |
200 | list_for_each(p, &atm_devs) | 202 | list_for_each(p, &atm_devs) |
201 | size += sizeof(int); | 203 | size += sizeof(int); |
202 | if (size > len) { | 204 | if (size > len) { |
203 | up(&atm_dev_mutex); | 205 | mutex_unlock(&atm_dev_mutex); |
204 | return -E2BIG; | 206 | return -E2BIG; |
205 | } | 207 | } |
206 | tmp_buf = kmalloc(size, GFP_ATOMIC); | 208 | tmp_buf = kmalloc(size, GFP_ATOMIC); |
207 | if (!tmp_buf) { | 209 | if (!tmp_buf) { |
208 | up(&atm_dev_mutex); | 210 | mutex_unlock(&atm_dev_mutex); |
209 | return -ENOMEM; | 211 | return -ENOMEM; |
210 | } | 212 | } |
211 | tmp_p = tmp_buf; | 213 | tmp_p = tmp_buf; |
@@ -213,7 +215,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) | |||
213 | dev = list_entry(p, struct atm_dev, dev_list); | 215 | dev = list_entry(p, struct atm_dev, dev_list); |
214 | *tmp_p++ = dev->number; | 216 | *tmp_p++ = dev->number; |
215 | } | 217 | } |
216 | up(&atm_dev_mutex); | 218 | mutex_unlock(&atm_dev_mutex); |
217 | error = ((copy_to_user(buf, tmp_buf, size)) || | 219 | error = ((copy_to_user(buf, tmp_buf, size)) || |
218 | put_user(size, &iobuf->length)) | 220 | put_user(size, &iobuf->length)) |
219 | ? -EFAULT : 0; | 221 | ? -EFAULT : 0; |
@@ -400,13 +402,13 @@ static __inline__ void *dev_get_idx(loff_t left) | |||
400 | 402 | ||
401 | void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) | 403 | void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) |
402 | { | 404 | { |
403 | down(&atm_dev_mutex); | 405 | mutex_lock(&atm_dev_mutex); |
404 | return *pos ? dev_get_idx(*pos) : (void *) 1; | 406 | return *pos ? dev_get_idx(*pos) : (void *) 1; |
405 | } | 407 | } |
406 | 408 | ||
407 | void atm_dev_seq_stop(struct seq_file *seq, void *v) | 409 | void atm_dev_seq_stop(struct seq_file *seq, void *v) |
408 | { | 410 | { |
409 | up(&atm_dev_mutex); | 411 | mutex_unlock(&atm_dev_mutex); |
410 | } | 412 | } |
411 | 413 | ||
412 | void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 414 | void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
diff --git a/net/atm/resources.h b/net/atm/resources.h index b7fb82a93b42..ac7222fee7a8 100644 --- a/net/atm/resources.h +++ b/net/atm/resources.h | |||
@@ -8,10 +8,11 @@ | |||
8 | 8 | ||
9 | #include <linux/config.h> | 9 | #include <linux/config.h> |
10 | #include <linux/atmdev.h> | 10 | #include <linux/atmdev.h> |
11 | #include <linux/mutex.h> | ||
11 | 12 | ||
12 | 13 | ||
13 | extern struct list_head atm_devs; | 14 | extern struct list_head atm_devs; |
14 | extern struct semaphore atm_dev_mutex; | 15 | extern struct mutex atm_dev_mutex; |
15 | 16 | ||
16 | int atm_dev_ioctl(unsigned int cmd, void __user *arg); | 17 | int atm_dev_ioctl(unsigned int cmd, void __user *arg); |
17 | 18 | ||
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index cbb20c32a6c8..d908d49dc9f8 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c | |||
@@ -532,8 +532,8 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) | |||
532 | dev = alloc_netdev(sizeof(struct bnep_session), | 532 | dev = alloc_netdev(sizeof(struct bnep_session), |
533 | (*req->device) ? req->device : "bnep%d", | 533 | (*req->device) ? req->device : "bnep%d", |
534 | bnep_net_setup); | 534 | bnep_net_setup); |
535 | if (!dev) | 535 | if (!dev) |
536 | return ENOMEM; | 536 | return -ENOMEM; |
537 | 537 | ||
538 | 538 | ||
539 | down_write(&bnep_session_sem); | 539 | down_write(&bnep_session_sem); |
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 5b4253c61f62..e99010ce8bb2 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c | |||
@@ -37,6 +37,8 @@ | |||
37 | #include <linux/wait.h> | 37 | #include <linux/wait.h> |
38 | #include <linux/device.h> | 38 | #include <linux/device.h> |
39 | #include <linux/net.h> | 39 | #include <linux/net.h> |
40 | #include <linux/mutex.h> | ||
41 | |||
40 | #include <net/sock.h> | 42 | #include <net/sock.h> |
41 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
42 | #include <asm/unaligned.h> | 44 | #include <asm/unaligned.h> |
@@ -57,9 +59,9 @@ static unsigned int l2cap_mtu = RFCOMM_MAX_L2CAP_MTU; | |||
57 | 59 | ||
58 | static struct task_struct *rfcomm_thread; | 60 | static struct task_struct *rfcomm_thread; |
59 | 61 | ||
60 | static DECLARE_MUTEX(rfcomm_sem); | 62 | static DEFINE_MUTEX(rfcomm_mutex); |
61 | #define rfcomm_lock() down(&rfcomm_sem); | 63 | #define rfcomm_lock() mutex_lock(&rfcomm_mutex) |
62 | #define rfcomm_unlock() up(&rfcomm_sem); | 64 | #define rfcomm_unlock() mutex_unlock(&rfcomm_mutex) |
63 | 65 | ||
64 | static unsigned long rfcomm_event; | 66 | static unsigned long rfcomm_event; |
65 | 67 | ||
diff --git a/net/bridge/Kconfig b/net/bridge/Kconfig index db23d59746cf..12265aff7099 100644 --- a/net/bridge/Kconfig +++ b/net/bridge/Kconfig | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | config BRIDGE | 5 | config BRIDGE |
6 | tristate "802.1d Ethernet Bridging" | 6 | tristate "802.1d Ethernet Bridging" |
7 | select LLC | ||
7 | ---help--- | 8 | ---help--- |
8 | If you say Y here, then your Linux box will be able to act as an | 9 | If you say Y here, then your Linux box will be able to act as an |
9 | Ethernet bridge, which means that the different Ethernet segments it | 10 | Ethernet bridge, which means that the different Ethernet segments it |
diff --git a/net/bridge/br.c b/net/bridge/br.c index 188cc1ac49eb..22d806cf40ca 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c | |||
@@ -19,13 +19,23 @@ | |||
19 | #include <linux/netdevice.h> | 19 | #include <linux/netdevice.h> |
20 | #include <linux/etherdevice.h> | 20 | #include <linux/etherdevice.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/llc.h> | ||
23 | #include <net/llc.h> | ||
22 | 24 | ||
23 | #include "br_private.h" | 25 | #include "br_private.h" |
24 | 26 | ||
25 | int (*br_should_route_hook) (struct sk_buff **pskb) = NULL; | 27 | int (*br_should_route_hook) (struct sk_buff **pskb) = NULL; |
26 | 28 | ||
29 | static struct llc_sap *br_stp_sap; | ||
30 | |||
27 | static int __init br_init(void) | 31 | static int __init br_init(void) |
28 | { | 32 | { |
33 | br_stp_sap = llc_sap_open(LLC_SAP_BSPAN, br_stp_rcv); | ||
34 | if (!br_stp_sap) { | ||
35 | printk(KERN_ERR "bridge: can't register sap for STP\n"); | ||
36 | return -EBUSY; | ||
37 | } | ||
38 | |||
29 | br_fdb_init(); | 39 | br_fdb_init(); |
30 | 40 | ||
31 | #ifdef CONFIG_BRIDGE_NETFILTER | 41 | #ifdef CONFIG_BRIDGE_NETFILTER |
@@ -45,6 +55,8 @@ static int __init br_init(void) | |||
45 | 55 | ||
46 | static void __exit br_deinit(void) | 56 | static void __exit br_deinit(void) |
47 | { | 57 | { |
58 | llc_sap_close(br_stp_sap); | ||
59 | |||
48 | #ifdef CONFIG_BRIDGE_NETFILTER | 60 | #ifdef CONFIG_BRIDGE_NETFILTER |
49 | br_netfilter_fini(); | 61 | br_netfilter_fini(); |
50 | #endif | 62 | #endif |
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 0b33a7b3a00c..0c88a2ac32c1 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c | |||
@@ -27,6 +27,7 @@ static struct net_device_stats *br_dev_get_stats(struct net_device *dev) | |||
27 | return &br->statistics; | 27 | return &br->statistics; |
28 | } | 28 | } |
29 | 29 | ||
30 | /* net device transmit always called with no BH (preempt_disabled) */ | ||
30 | int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) | 31 | int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) |
31 | { | 32 | { |
32 | struct net_bridge *br = netdev_priv(dev); | 33 | struct net_bridge *br = netdev_priv(dev); |
@@ -39,7 +40,6 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
39 | skb->mac.raw = skb->data; | 40 | skb->mac.raw = skb->data; |
40 | skb_pull(skb, ETH_HLEN); | 41 | skb_pull(skb, ETH_HLEN); |
41 | 42 | ||
42 | rcu_read_lock(); | ||
43 | if (dest[0] & 1) | 43 | if (dest[0] & 1) |
44 | br_flood_deliver(br, skb, 0); | 44 | br_flood_deliver(br, skb, 0); |
45 | else if ((dst = __br_fdb_get(br, dest)) != NULL) | 45 | else if ((dst = __br_fdb_get(br, dest)) != NULL) |
@@ -47,7 +47,6 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
47 | else | 47 | else |
48 | br_flood_deliver(br, skb, 0); | 48 | br_flood_deliver(br, skb, 0); |
49 | 49 | ||
50 | rcu_read_unlock(); | ||
51 | return 0; | 50 | return 0; |
52 | } | 51 | } |
53 | 52 | ||
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 1f08a59b51ea..3a73b8c94271 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
@@ -341,7 +341,6 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, | |||
341 | if (hold_time(br) == 0) | 341 | if (hold_time(br) == 0) |
342 | return; | 342 | return; |
343 | 343 | ||
344 | rcu_read_lock(); | ||
345 | fdb = fdb_find(head, addr); | 344 | fdb = fdb_find(head, addr); |
346 | if (likely(fdb)) { | 345 | if (likely(fdb)) { |
347 | /* attempt to update an entry for a local interface */ | 346 | /* attempt to update an entry for a local interface */ |
@@ -356,13 +355,12 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source, | |||
356 | fdb->ageing_timer = jiffies; | 355 | fdb->ageing_timer = jiffies; |
357 | } | 356 | } |
358 | } else { | 357 | } else { |
359 | spin_lock_bh(&br->hash_lock); | 358 | spin_lock(&br->hash_lock); |
360 | if (!fdb_find(head, addr)) | 359 | if (!fdb_find(head, addr)) |
361 | fdb_create(head, source, addr, 0); | 360 | fdb_create(head, source, addr, 0); |
362 | /* else we lose race and someone else inserts | 361 | /* else we lose race and someone else inserts |
363 | * it first, don't bother updating | 362 | * it first, don't bother updating |
364 | */ | 363 | */ |
365 | spin_unlock_bh(&br->hash_lock); | 364 | spin_unlock(&br->hash_lock); |
366 | } | 365 | } |
367 | rcu_read_unlock(); | ||
368 | } | 366 | } |
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index f36b35edd60c..59eef42d4a42 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -210,7 +210,8 @@ static struct net_device *new_bridge_dev(const char *name) | |||
210 | 210 | ||
211 | br->bridge_id.prio[0] = 0x80; | 211 | br->bridge_id.prio[0] = 0x80; |
212 | br->bridge_id.prio[1] = 0x00; | 212 | br->bridge_id.prio[1] = 0x00; |
213 | memset(br->bridge_id.addr, 0, ETH_ALEN); | 213 | |
214 | memcpy(br->group_addr, br_group_address, ETH_ALEN); | ||
214 | 215 | ||
215 | br->feature_mask = dev->features; | 216 | br->feature_mask = dev->features; |
216 | br->stp_enabled = 0; | 217 | br->stp_enabled = 0; |
@@ -237,12 +238,11 @@ static int find_portno(struct net_bridge *br) | |||
237 | struct net_bridge_port *p; | 238 | struct net_bridge_port *p; |
238 | unsigned long *inuse; | 239 | unsigned long *inuse; |
239 | 240 | ||
240 | inuse = kmalloc(BITS_TO_LONGS(BR_MAX_PORTS)*sizeof(unsigned long), | 241 | inuse = kcalloc(BITS_TO_LONGS(BR_MAX_PORTS), sizeof(unsigned long), |
241 | GFP_KERNEL); | 242 | GFP_KERNEL); |
242 | if (!inuse) | 243 | if (!inuse) |
243 | return -ENOMEM; | 244 | return -ENOMEM; |
244 | 245 | ||
245 | memset(inuse, 0, BITS_TO_LONGS(BR_MAX_PORTS)*sizeof(unsigned long)); | ||
246 | set_bit(0, inuse); /* zero is reserved */ | 246 | set_bit(0, inuse); /* zero is reserved */ |
247 | list_for_each_entry(p, &br->port_list, list) { | 247 | list_for_each_entry(p, &br->port_list, list) { |
248 | set_bit(p->port_no, inuse); | 248 | set_bit(p->port_no, inuse); |
@@ -264,11 +264,10 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, | |||
264 | if (index < 0) | 264 | if (index < 0) |
265 | return ERR_PTR(index); | 265 | return ERR_PTR(index); |
266 | 266 | ||
267 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 267 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
268 | if (p == NULL) | 268 | if (p == NULL) |
269 | return ERR_PTR(-ENOMEM); | 269 | return ERR_PTR(-ENOMEM); |
270 | 270 | ||
271 | memset(p, 0, sizeof(*p)); | ||
272 | p->br = br; | 271 | p->br = br; |
273 | dev_hold(dev); | 272 | dev_hold(dev); |
274 | p->dev = dev; | 273 | p->dev = dev; |
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 4eef83755315..b7766562d72c 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -19,13 +19,8 @@ | |||
19 | #include <linux/netfilter_bridge.h> | 19 | #include <linux/netfilter_bridge.h> |
20 | #include "br_private.h" | 20 | #include "br_private.h" |
21 | 21 | ||
22 | const unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; | 22 | /* Bridge group multicast address 802.1d (pg 51). */ |
23 | 23 | const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; | |
24 | static int br_pass_frame_up_finish(struct sk_buff *skb) | ||
25 | { | ||
26 | netif_receive_skb(skb); | ||
27 | return 0; | ||
28 | } | ||
29 | 24 | ||
30 | static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb) | 25 | static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb) |
31 | { | 26 | { |
@@ -38,7 +33,7 @@ static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb) | |||
38 | skb->dev = br->dev; | 33 | skb->dev = br->dev; |
39 | 34 | ||
40 | NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, | 35 | NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, |
41 | br_pass_frame_up_finish); | 36 | netif_receive_skb); |
42 | } | 37 | } |
43 | 38 | ||
44 | /* note: already called with rcu_read_lock (preempt_disabled) */ | 39 | /* note: already called with rcu_read_lock (preempt_disabled) */ |
@@ -100,6 +95,25 @@ drop: | |||
100 | goto out; | 95 | goto out; |
101 | } | 96 | } |
102 | 97 | ||
98 | /* note: already called with rcu_read_lock (preempt_disabled) */ | ||
99 | static int br_handle_local_finish(struct sk_buff *skb) | ||
100 | { | ||
101 | struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); | ||
102 | |||
103 | if (p && p->state != BR_STATE_DISABLED) | ||
104 | br_fdb_update(p->br, p, eth_hdr(skb)->h_source); | ||
105 | |||
106 | return 0; /* process further */ | ||
107 | } | ||
108 | |||
109 | /* Does address match the link local multicast address. | ||
110 | * 01:80:c2:00:00:0X | ||
111 | */ | ||
112 | static inline int is_link_local(const unsigned char *dest) | ||
113 | { | ||
114 | return memcmp(dest, br_group_address, 5) == 0 && (dest[5] & 0xf0) == 0; | ||
115 | } | ||
116 | |||
103 | /* | 117 | /* |
104 | * Called via br_handle_frame_hook. | 118 | * Called via br_handle_frame_hook. |
105 | * Return 0 if *pskb should be processed furthur | 119 | * Return 0 if *pskb should be processed furthur |
@@ -117,15 +131,10 @@ int br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb) | |||
117 | if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) | 131 | if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) |
118 | goto err; | 132 | goto err; |
119 | 133 | ||
120 | if (p->br->stp_enabled && | 134 | if (unlikely(is_link_local(dest))) { |
121 | !memcmp(dest, bridge_ula, 5) && | 135 | skb->pkt_type = PACKET_HOST; |
122 | !(dest[5] & 0xF0)) { | 136 | return NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, |
123 | if (!dest[5]) { | 137 | NULL, br_handle_local_finish) != 0; |
124 | NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, | ||
125 | NULL, br_stp_handle_bpdu); | ||
126 | return 1; | ||
127 | } | ||
128 | goto err; | ||
129 | } | 138 | } |
130 | 139 | ||
131 | if (p->state == BR_STATE_FORWARDING || p->state == BR_STATE_LEARNING) { | 140 | if (p->state == BR_STATE_FORWARDING || p->state == BR_STATE_LEARNING) { |
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index e060aad8624d..f29450b788be 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
@@ -61,15 +61,25 @@ static int brnf_filter_vlan_tagged = 1; | |||
61 | #define brnf_filter_vlan_tagged 1 | 61 | #define brnf_filter_vlan_tagged 1 |
62 | #endif | 62 | #endif |
63 | 63 | ||
64 | #define IS_VLAN_IP (skb->protocol == __constant_htons(ETH_P_8021Q) && \ | 64 | static __be16 inline vlan_proto(const struct sk_buff *skb) |
65 | hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_IP) && \ | 65 | { |
66 | brnf_filter_vlan_tagged) | 66 | return vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; |
67 | #define IS_VLAN_IPV6 (skb->protocol == __constant_htons(ETH_P_8021Q) && \ | 67 | } |
68 | hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_IPV6) && \ | 68 | |
69 | brnf_filter_vlan_tagged) | 69 | #define IS_VLAN_IP(skb) \ |
70 | #define IS_VLAN_ARP (skb->protocol == __constant_htons(ETH_P_8021Q) && \ | 70 | (skb->protocol == htons(ETH_P_8021Q) && \ |
71 | hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_ARP) && \ | 71 | vlan_proto(skb) == htons(ETH_P_IP) && \ |
72 | brnf_filter_vlan_tagged) | 72 | brnf_filter_vlan_tagged) |
73 | |||
74 | #define IS_VLAN_IPV6(skb) \ | ||
75 | (skb->protocol == htons(ETH_P_8021Q) && \ | ||
76 | vlan_proto(skb) == htons(ETH_P_IPV6) &&\ | ||
77 | brnf_filter_vlan_tagged) | ||
78 | |||
79 | #define IS_VLAN_ARP(skb) \ | ||
80 | (skb->protocol == htons(ETH_P_8021Q) && \ | ||
81 | vlan_proto(skb) == htons(ETH_P_ARP) && \ | ||
82 | brnf_filter_vlan_tagged) | ||
73 | 83 | ||
74 | /* We need these fake structures to make netfilter happy -- | 84 | /* We need these fake structures to make netfilter happy -- |
75 | * lots of places assume that skb->dst != NULL, which isn't | 85 | * lots of places assume that skb->dst != NULL, which isn't |
@@ -103,6 +113,25 @@ static inline struct net_device *bridge_parent(const struct net_device *dev) | |||
103 | return port ? port->br->dev : NULL; | 113 | return port ? port->br->dev : NULL; |
104 | } | 114 | } |
105 | 115 | ||
116 | static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) | ||
117 | { | ||
118 | skb->nf_bridge = kzalloc(sizeof(struct nf_bridge_info), GFP_ATOMIC); | ||
119 | if (likely(skb->nf_bridge)) | ||
120 | atomic_set(&(skb->nf_bridge->use), 1); | ||
121 | |||
122 | return skb->nf_bridge; | ||
123 | } | ||
124 | |||
125 | static inline void nf_bridge_save_header(struct sk_buff *skb) | ||
126 | { | ||
127 | int header_size = 16; | ||
128 | |||
129 | if (skb->protocol == htons(ETH_P_8021Q)) | ||
130 | header_size = 18; | ||
131 | |||
132 | memcpy(skb->nf_bridge->data, skb->data - header_size, header_size); | ||
133 | } | ||
134 | |||
106 | /* PF_BRIDGE/PRE_ROUTING *********************************************/ | 135 | /* PF_BRIDGE/PRE_ROUTING *********************************************/ |
107 | /* Undo the changes made for ip6tables PREROUTING and continue the | 136 | /* Undo the changes made for ip6tables PREROUTING and continue the |
108 | * bridge PRE_ROUTING hook. */ | 137 | * bridge PRE_ROUTING hook. */ |
@@ -120,7 +149,7 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) | |||
120 | dst_hold(skb->dst); | 149 | dst_hold(skb->dst); |
121 | 150 | ||
122 | skb->dev = nf_bridge->physindev; | 151 | skb->dev = nf_bridge->physindev; |
123 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | 152 | if (skb->protocol == htons(ETH_P_8021Q)) { |
124 | skb_push(skb, VLAN_HLEN); | 153 | skb_push(skb, VLAN_HLEN); |
125 | skb->nh.raw -= VLAN_HLEN; | 154 | skb->nh.raw -= VLAN_HLEN; |
126 | } | 155 | } |
@@ -136,7 +165,7 @@ static void __br_dnat_complain(void) | |||
136 | 165 | ||
137 | if (jiffies - last_complaint >= 5 * HZ) { | 166 | if (jiffies - last_complaint >= 5 * HZ) { |
138 | printk(KERN_WARNING "Performing cross-bridge DNAT requires IP " | 167 | printk(KERN_WARNING "Performing cross-bridge DNAT requires IP " |
139 | "forwarding to be enabled\n"); | 168 | "forwarding to be enabled\n"); |
140 | last_complaint = jiffies; | 169 | last_complaint = jiffies; |
141 | } | 170 | } |
142 | } | 171 | } |
@@ -196,7 +225,7 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) | |||
196 | if (!skb->dev) | 225 | if (!skb->dev) |
197 | kfree_skb(skb); | 226 | kfree_skb(skb); |
198 | else { | 227 | else { |
199 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | 228 | if (skb->protocol == htons(ETH_P_8021Q)) { |
200 | skb_pull(skb, VLAN_HLEN); | 229 | skb_pull(skb, VLAN_HLEN); |
201 | skb->nh.raw += VLAN_HLEN; | 230 | skb->nh.raw += VLAN_HLEN; |
202 | } | 231 | } |
@@ -218,12 +247,17 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) | |||
218 | nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; | 247 | nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; |
219 | 248 | ||
220 | if (dnat_took_place(skb)) { | 249 | if (dnat_took_place(skb)) { |
221 | if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, | 250 | if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev)) { |
222 | dev)) { | ||
223 | struct rtable *rt; | 251 | struct rtable *rt; |
224 | struct flowi fl = { .nl_u = | 252 | struct flowi fl = { |
225 | { .ip4_u = { .daddr = iph->daddr, .saddr = 0 , | 253 | .nl_u = { |
226 | .tos = RT_TOS(iph->tos)} }, .proto = 0}; | 254 | .ip4_u = { |
255 | .daddr = iph->daddr, | ||
256 | .saddr = 0, | ||
257 | .tos = RT_TOS(iph->tos) }, | ||
258 | }, | ||
259 | .proto = 0, | ||
260 | }; | ||
227 | 261 | ||
228 | if (!ip_route_output_key(&rt, &fl)) { | 262 | if (!ip_route_output_key(&rt, &fl)) { |
229 | /* - Bridged-and-DNAT'ed traffic doesn't | 263 | /* - Bridged-and-DNAT'ed traffic doesn't |
@@ -247,7 +281,7 @@ bridged_dnat: | |||
247 | nf_bridge->mask |= BRNF_BRIDGED_DNAT; | 281 | nf_bridge->mask |= BRNF_BRIDGED_DNAT; |
248 | skb->dev = nf_bridge->physindev; | 282 | skb->dev = nf_bridge->physindev; |
249 | if (skb->protocol == | 283 | if (skb->protocol == |
250 | __constant_htons(ETH_P_8021Q)) { | 284 | htons(ETH_P_8021Q)) { |
251 | skb_push(skb, VLAN_HLEN); | 285 | skb_push(skb, VLAN_HLEN); |
252 | skb->nh.raw -= VLAN_HLEN; | 286 | skb->nh.raw -= VLAN_HLEN; |
253 | } | 287 | } |
@@ -257,8 +291,7 @@ bridged_dnat: | |||
257 | 1); | 291 | 1); |
258 | return 0; | 292 | return 0; |
259 | } | 293 | } |
260 | memcpy(eth_hdr(skb)->h_dest, dev->dev_addr, | 294 | memcpy(eth_hdr(skb)->h_dest, dev->dev_addr, ETH_ALEN); |
261 | ETH_ALEN); | ||
262 | skb->pkt_type = PACKET_HOST; | 295 | skb->pkt_type = PACKET_HOST; |
263 | } | 296 | } |
264 | } else { | 297 | } else { |
@@ -267,7 +300,7 @@ bridged_dnat: | |||
267 | } | 300 | } |
268 | 301 | ||
269 | skb->dev = nf_bridge->physindev; | 302 | skb->dev = nf_bridge->physindev; |
270 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | 303 | if (skb->protocol == htons(ETH_P_8021Q)) { |
271 | skb_push(skb, VLAN_HLEN); | 304 | skb_push(skb, VLAN_HLEN); |
272 | skb->nh.raw -= VLAN_HLEN; | 305 | skb->nh.raw -= VLAN_HLEN; |
273 | } | 306 | } |
@@ -297,10 +330,10 @@ static struct net_device *setup_pre_routing(struct sk_buff *skb) | |||
297 | /* We only check the length. A bridge shouldn't do any hop-by-hop stuff anyway */ | 330 | /* We only check the length. A bridge shouldn't do any hop-by-hop stuff anyway */ |
298 | static int check_hbh_len(struct sk_buff *skb) | 331 | static int check_hbh_len(struct sk_buff *skb) |
299 | { | 332 | { |
300 | unsigned char *raw = (u8*)(skb->nh.ipv6h+1); | 333 | unsigned char *raw = (u8 *) (skb->nh.ipv6h + 1); |
301 | u32 pkt_len; | 334 | u32 pkt_len; |
302 | int off = raw - skb->nh.raw; | 335 | int off = raw - skb->nh.raw; |
303 | int len = (raw[1]+1)<<3; | 336 | int len = (raw[1] + 1) << 3; |
304 | 337 | ||
305 | if ((raw + len) - skb->data > skb_headlen(skb)) | 338 | if ((raw + len) - skb->data > skb_headlen(skb)) |
306 | goto bad; | 339 | goto bad; |
@@ -309,7 +342,7 @@ static int check_hbh_len(struct sk_buff *skb) | |||
309 | len -= 2; | 342 | len -= 2; |
310 | 343 | ||
311 | while (len > 0) { | 344 | while (len > 0) { |
312 | int optlen = skb->nh.raw[off+1]+2; | 345 | int optlen = skb->nh.raw[off + 1] + 2; |
313 | 346 | ||
314 | switch (skb->nh.raw[off]) { | 347 | switch (skb->nh.raw[off]) { |
315 | case IPV6_TLV_PAD0: | 348 | case IPV6_TLV_PAD0: |
@@ -320,16 +353,16 @@ static int check_hbh_len(struct sk_buff *skb) | |||
320 | break; | 353 | break; |
321 | 354 | ||
322 | case IPV6_TLV_JUMBO: | 355 | case IPV6_TLV_JUMBO: |
323 | if (skb->nh.raw[off+1] != 4 || (off&3) != 2) | 356 | if (skb->nh.raw[off + 1] != 4 || (off & 3) != 2) |
324 | goto bad; | 357 | goto bad; |
325 | pkt_len = ntohl(*(u32*)(skb->nh.raw+off+2)); | 358 | pkt_len = ntohl(*(u32 *) (skb->nh.raw + off + 2)); |
326 | if (pkt_len <= IPV6_MAXPLEN || | 359 | if (pkt_len <= IPV6_MAXPLEN || |
327 | skb->nh.ipv6h->payload_len) | 360 | skb->nh.ipv6h->payload_len) |
328 | goto bad; | 361 | goto bad; |
329 | if (pkt_len > skb->len - sizeof(struct ipv6hdr)) | 362 | if (pkt_len > skb->len - sizeof(struct ipv6hdr)) |
330 | goto bad; | 363 | goto bad; |
331 | if (pskb_trim_rcsum(skb, | 364 | if (pskb_trim_rcsum(skb, |
332 | pkt_len+sizeof(struct ipv6hdr))) | 365 | pkt_len + sizeof(struct ipv6hdr))) |
333 | goto bad; | 366 | goto bad; |
334 | break; | 367 | break; |
335 | default: | 368 | default: |
@@ -350,12 +383,13 @@ bad: | |||
350 | /* Replicate the checks that IPv6 does on packet reception and pass the packet | 383 | /* Replicate the checks that IPv6 does on packet reception and pass the packet |
351 | * to ip6tables, which doesn't support NAT, so things are fairly simple. */ | 384 | * to ip6tables, which doesn't support NAT, so things are fairly simple. */ |
352 | static unsigned int br_nf_pre_routing_ipv6(unsigned int hook, | 385 | static unsigned int br_nf_pre_routing_ipv6(unsigned int hook, |
353 | struct sk_buff *skb, const struct net_device *in, | 386 | struct sk_buff *skb, |
354 | const struct net_device *out, int (*okfn)(struct sk_buff *)) | 387 | const struct net_device *in, |
388 | const struct net_device *out, | ||
389 | int (*okfn)(struct sk_buff *)) | ||
355 | { | 390 | { |
356 | struct ipv6hdr *hdr; | 391 | struct ipv6hdr *hdr; |
357 | u32 pkt_len; | 392 | u32 pkt_len; |
358 | struct nf_bridge_info *nf_bridge; | ||
359 | 393 | ||
360 | if (skb->len < sizeof(struct ipv6hdr)) | 394 | if (skb->len < sizeof(struct ipv6hdr)) |
361 | goto inhdr_error; | 395 | goto inhdr_error; |
@@ -381,10 +415,10 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook, | |||
381 | } | 415 | } |
382 | } | 416 | } |
383 | if (hdr->nexthdr == NEXTHDR_HOP && check_hbh_len(skb)) | 417 | if (hdr->nexthdr == NEXTHDR_HOP && check_hbh_len(skb)) |
384 | goto inhdr_error; | 418 | goto inhdr_error; |
385 | 419 | ||
386 | nf_bridge_put(skb->nf_bridge); | 420 | nf_bridge_put(skb->nf_bridge); |
387 | if ((nf_bridge = nf_bridge_alloc(skb)) == NULL) | 421 | if (!nf_bridge_alloc(skb)) |
388 | return NF_DROP; | 422 | return NF_DROP; |
389 | if (!setup_pre_routing(skb)) | 423 | if (!setup_pre_routing(skb)) |
390 | return NF_DROP; | 424 | return NF_DROP; |
@@ -412,10 +446,8 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, | |||
412 | struct iphdr *iph; | 446 | struct iphdr *iph; |
413 | __u32 len; | 447 | __u32 len; |
414 | struct sk_buff *skb = *pskb; | 448 | struct sk_buff *skb = *pskb; |
415 | struct nf_bridge_info *nf_bridge; | ||
416 | struct vlan_ethhdr *hdr = vlan_eth_hdr(*pskb); | ||
417 | 449 | ||
418 | if (skb->protocol == __constant_htons(ETH_P_IPV6) || IS_VLAN_IPV6) { | 450 | if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb)) { |
419 | #ifdef CONFIG_SYSCTL | 451 | #ifdef CONFIG_SYSCTL |
420 | if (!brnf_call_ip6tables) | 452 | if (!brnf_call_ip6tables) |
421 | return NF_ACCEPT; | 453 | return NF_ACCEPT; |
@@ -423,10 +455,8 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, | |||
423 | if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL) | 455 | if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL) |
424 | goto out; | 456 | goto out; |
425 | 457 | ||
426 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | 458 | if (skb->protocol == htons(ETH_P_8021Q)) { |
427 | u8 *vhdr = skb->data; | 459 | skb_pull_rcsum(skb, VLAN_HLEN); |
428 | skb_pull(skb, VLAN_HLEN); | ||
429 | skb_postpull_rcsum(skb, vhdr, VLAN_HLEN); | ||
430 | skb->nh.raw += VLAN_HLEN; | 460 | skb->nh.raw += VLAN_HLEN; |
431 | } | 461 | } |
432 | return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn); | 462 | return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn); |
@@ -436,16 +466,14 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, | |||
436 | return NF_ACCEPT; | 466 | return NF_ACCEPT; |
437 | #endif | 467 | #endif |
438 | 468 | ||
439 | if (skb->protocol != __constant_htons(ETH_P_IP) && !IS_VLAN_IP) | 469 | if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP(skb)) |
440 | return NF_ACCEPT; | 470 | return NF_ACCEPT; |
441 | 471 | ||
442 | if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL) | 472 | if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL) |
443 | goto out; | 473 | goto out; |
444 | 474 | ||
445 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | 475 | if (skb->protocol == htons(ETH_P_8021Q)) { |
446 | u8 *vhdr = skb->data; | 476 | skb_pull_rcsum(skb, VLAN_HLEN); |
447 | skb_pull(skb, VLAN_HLEN); | ||
448 | skb_postpull_rcsum(skb, vhdr, VLAN_HLEN); | ||
449 | skb->nh.raw += VLAN_HLEN; | 477 | skb->nh.raw += VLAN_HLEN; |
450 | } | 478 | } |
451 | 479 | ||
@@ -456,15 +484,15 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, | |||
456 | if (iph->ihl < 5 || iph->version != 4) | 484 | if (iph->ihl < 5 || iph->version != 4) |
457 | goto inhdr_error; | 485 | goto inhdr_error; |
458 | 486 | ||
459 | if (!pskb_may_pull(skb, 4*iph->ihl)) | 487 | if (!pskb_may_pull(skb, 4 * iph->ihl)) |
460 | goto inhdr_error; | 488 | goto inhdr_error; |
461 | 489 | ||
462 | iph = skb->nh.iph; | 490 | iph = skb->nh.iph; |
463 | if (ip_fast_csum((__u8 *)iph, iph->ihl) != 0) | 491 | if (ip_fast_csum((__u8 *) iph, iph->ihl) != 0) |
464 | goto inhdr_error; | 492 | goto inhdr_error; |
465 | 493 | ||
466 | len = ntohs(iph->tot_len); | 494 | len = ntohs(iph->tot_len); |
467 | if (skb->len < len || len < 4*iph->ihl) | 495 | if (skb->len < len || len < 4 * iph->ihl) |
468 | goto inhdr_error; | 496 | goto inhdr_error; |
469 | 497 | ||
470 | if (skb->len > len) { | 498 | if (skb->len > len) { |
@@ -473,8 +501,8 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, | |||
473 | skb->ip_summed = CHECKSUM_NONE; | 501 | skb->ip_summed = CHECKSUM_NONE; |
474 | } | 502 | } |
475 | 503 | ||
476 | nf_bridge_put(skb->nf_bridge); | 504 | nf_bridge_put(skb->nf_bridge); |
477 | if ((nf_bridge = nf_bridge_alloc(skb)) == NULL) | 505 | if (!nf_bridge_alloc(skb)) |
478 | return NF_DROP; | 506 | return NF_DROP; |
479 | if (!setup_pre_routing(skb)) | 507 | if (!setup_pre_routing(skb)) |
480 | return NF_DROP; | 508 | return NF_DROP; |
@@ -486,7 +514,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, | |||
486 | return NF_STOLEN; | 514 | return NF_STOLEN; |
487 | 515 | ||
488 | inhdr_error: | 516 | inhdr_error: |
489 | // IP_INC_STATS_BH(IpInHdrErrors); | 517 | // IP_INC_STATS_BH(IpInHdrErrors); |
490 | out: | 518 | out: |
491 | return NF_DROP; | 519 | return NF_DROP; |
492 | } | 520 | } |
@@ -500,8 +528,9 @@ out: | |||
500 | * register an IPv4 PRE_ROUTING 'sabotage' hook that will | 528 | * register an IPv4 PRE_ROUTING 'sabotage' hook that will |
501 | * prevent this from happening. */ | 529 | * prevent this from happening. */ |
502 | static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff **pskb, | 530 | static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff **pskb, |
503 | const struct net_device *in, const struct net_device *out, | 531 | const struct net_device *in, |
504 | int (*okfn)(struct sk_buff *)) | 532 | const struct net_device *out, |
533 | int (*okfn)(struct sk_buff *)) | ||
505 | { | 534 | { |
506 | struct sk_buff *skb = *pskb; | 535 | struct sk_buff *skb = *pskb; |
507 | 536 | ||
@@ -513,15 +542,13 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff **pskb, | |||
513 | return NF_ACCEPT; | 542 | return NF_ACCEPT; |
514 | } | 543 | } |
515 | 544 | ||
516 | |||
517 | /* PF_BRIDGE/FORWARD *************************************************/ | 545 | /* PF_BRIDGE/FORWARD *************************************************/ |
518 | static int br_nf_forward_finish(struct sk_buff *skb) | 546 | static int br_nf_forward_finish(struct sk_buff *skb) |
519 | { | 547 | { |
520 | struct nf_bridge_info *nf_bridge = skb->nf_bridge; | 548 | struct nf_bridge_info *nf_bridge = skb->nf_bridge; |
521 | struct net_device *in; | 549 | struct net_device *in; |
522 | struct vlan_ethhdr *hdr = vlan_eth_hdr(skb); | ||
523 | 550 | ||
524 | if (skb->protocol != __constant_htons(ETH_P_ARP) && !IS_VLAN_ARP) { | 551 | if (skb->protocol != htons(ETH_P_ARP) && !IS_VLAN_ARP(skb)) { |
525 | in = nf_bridge->physindev; | 552 | in = nf_bridge->physindev; |
526 | if (nf_bridge->mask & BRNF_PKT_TYPE) { | 553 | if (nf_bridge->mask & BRNF_PKT_TYPE) { |
527 | skb->pkt_type = PACKET_OTHERHOST; | 554 | skb->pkt_type = PACKET_OTHERHOST; |
@@ -530,12 +557,12 @@ static int br_nf_forward_finish(struct sk_buff *skb) | |||
530 | } else { | 557 | } else { |
531 | in = *((struct net_device **)(skb->cb)); | 558 | in = *((struct net_device **)(skb->cb)); |
532 | } | 559 | } |
533 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | 560 | if (skb->protocol == htons(ETH_P_8021Q)) { |
534 | skb_push(skb, VLAN_HLEN); | 561 | skb_push(skb, VLAN_HLEN); |
535 | skb->nh.raw -= VLAN_HLEN; | 562 | skb->nh.raw -= VLAN_HLEN; |
536 | } | 563 | } |
537 | NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in, | 564 | NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in, |
538 | skb->dev, br_forward_finish, 1); | 565 | skb->dev, br_forward_finish, 1); |
539 | return 0; | 566 | return 0; |
540 | } | 567 | } |
541 | 568 | ||
@@ -545,12 +572,12 @@ static int br_nf_forward_finish(struct sk_buff *skb) | |||
545 | * because of the physdev module. For ARP, indev and outdev are the | 572 | * because of the physdev module. For ARP, indev and outdev are the |
546 | * bridge ports. */ | 573 | * bridge ports. */ |
547 | static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb, | 574 | static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb, |
548 | const struct net_device *in, const struct net_device *out, | 575 | const struct net_device *in, |
549 | int (*okfn)(struct sk_buff *)) | 576 | const struct net_device *out, |
577 | int (*okfn)(struct sk_buff *)) | ||
550 | { | 578 | { |
551 | struct sk_buff *skb = *pskb; | 579 | struct sk_buff *skb = *pskb; |
552 | struct nf_bridge_info *nf_bridge; | 580 | struct nf_bridge_info *nf_bridge; |
553 | struct vlan_ethhdr *hdr = vlan_eth_hdr(skb); | ||
554 | struct net_device *parent; | 581 | struct net_device *parent; |
555 | int pf; | 582 | int pf; |
556 | 583 | ||
@@ -561,12 +588,12 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb, | |||
561 | if (!parent) | 588 | if (!parent) |
562 | return NF_DROP; | 589 | return NF_DROP; |
563 | 590 | ||
564 | if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP) | 591 | if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb)) |
565 | pf = PF_INET; | 592 | pf = PF_INET; |
566 | else | 593 | else |
567 | pf = PF_INET6; | 594 | pf = PF_INET6; |
568 | 595 | ||
569 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | 596 | if (skb->protocol == htons(ETH_P_8021Q)) { |
570 | skb_pull(*pskb, VLAN_HLEN); | 597 | skb_pull(*pskb, VLAN_HLEN); |
571 | (*pskb)->nh.raw += VLAN_HLEN; | 598 | (*pskb)->nh.raw += VLAN_HLEN; |
572 | } | 599 | } |
@@ -588,11 +615,11 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb, | |||
588 | } | 615 | } |
589 | 616 | ||
590 | static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb, | 617 | static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb, |
591 | const struct net_device *in, const struct net_device *out, | 618 | const struct net_device *in, |
592 | int (*okfn)(struct sk_buff *)) | 619 | const struct net_device *out, |
620 | int (*okfn)(struct sk_buff *)) | ||
593 | { | 621 | { |
594 | struct sk_buff *skb = *pskb; | 622 | struct sk_buff *skb = *pskb; |
595 | struct vlan_ethhdr *hdr = vlan_eth_hdr(skb); | ||
596 | struct net_device **d = (struct net_device **)(skb->cb); | 623 | struct net_device **d = (struct net_device **)(skb->cb); |
597 | 624 | ||
598 | #ifdef CONFIG_SYSCTL | 625 | #ifdef CONFIG_SYSCTL |
@@ -600,15 +627,15 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb, | |||
600 | return NF_ACCEPT; | 627 | return NF_ACCEPT; |
601 | #endif | 628 | #endif |
602 | 629 | ||
603 | if (skb->protocol != __constant_htons(ETH_P_ARP)) { | 630 | if (skb->protocol != htons(ETH_P_ARP)) { |
604 | if (!IS_VLAN_ARP) | 631 | if (!IS_VLAN_ARP(skb)) |
605 | return NF_ACCEPT; | 632 | return NF_ACCEPT; |
606 | skb_pull(*pskb, VLAN_HLEN); | 633 | skb_pull(*pskb, VLAN_HLEN); |
607 | (*pskb)->nh.raw += VLAN_HLEN; | 634 | (*pskb)->nh.raw += VLAN_HLEN; |
608 | } | 635 | } |
609 | 636 | ||
610 | if (skb->nh.arph->ar_pln != 4) { | 637 | if (skb->nh.arph->ar_pln != 4) { |
611 | if (IS_VLAN_ARP) { | 638 | if (IS_VLAN_ARP(skb)) { |
612 | skb_push(*pskb, VLAN_HLEN); | 639 | skb_push(*pskb, VLAN_HLEN); |
613 | (*pskb)->nh.raw -= VLAN_HLEN; | 640 | (*pskb)->nh.raw -= VLAN_HLEN; |
614 | } | 641 | } |
@@ -621,17 +648,16 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb, | |||
621 | return NF_STOLEN; | 648 | return NF_STOLEN; |
622 | } | 649 | } |
623 | 650 | ||
624 | |||
625 | /* PF_BRIDGE/LOCAL_OUT ***********************************************/ | 651 | /* PF_BRIDGE/LOCAL_OUT ***********************************************/ |
626 | static int br_nf_local_out_finish(struct sk_buff *skb) | 652 | static int br_nf_local_out_finish(struct sk_buff *skb) |
627 | { | 653 | { |
628 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | 654 | if (skb->protocol == htons(ETH_P_8021Q)) { |
629 | skb_push(skb, VLAN_HLEN); | 655 | skb_push(skb, VLAN_HLEN); |
630 | skb->nh.raw -= VLAN_HLEN; | 656 | skb->nh.raw -= VLAN_HLEN; |
631 | } | 657 | } |
632 | 658 | ||
633 | NF_HOOK_THRESH(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, | 659 | NF_HOOK_THRESH(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, |
634 | br_forward_finish, NF_BR_PRI_FIRST + 1); | 660 | br_forward_finish, NF_BR_PRI_FIRST + 1); |
635 | 661 | ||
636 | return 0; | 662 | return 0; |
637 | } | 663 | } |
@@ -657,19 +683,19 @@ static int br_nf_local_out_finish(struct sk_buff *skb) | |||
657 | * even routed packets that didn't arrive on a bridge interface have their | 683 | * even routed packets that didn't arrive on a bridge interface have their |
658 | * nf_bridge->physindev set. */ | 684 | * nf_bridge->physindev set. */ |
659 | static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb, | 685 | static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb, |
660 | const struct net_device *in, const struct net_device *out, | 686 | const struct net_device *in, |
661 | int (*okfn)(struct sk_buff *)) | 687 | const struct net_device *out, |
688 | int (*okfn)(struct sk_buff *)) | ||
662 | { | 689 | { |
663 | struct net_device *realindev, *realoutdev; | 690 | struct net_device *realindev, *realoutdev; |
664 | struct sk_buff *skb = *pskb; | 691 | struct sk_buff *skb = *pskb; |
665 | struct nf_bridge_info *nf_bridge; | 692 | struct nf_bridge_info *nf_bridge; |
666 | struct vlan_ethhdr *hdr = vlan_eth_hdr(skb); | ||
667 | int pf; | 693 | int pf; |
668 | 694 | ||
669 | if (!skb->nf_bridge) | 695 | if (!skb->nf_bridge) |
670 | return NF_ACCEPT; | 696 | return NF_ACCEPT; |
671 | 697 | ||
672 | if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP) | 698 | if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb)) |
673 | pf = PF_INET; | 699 | pf = PF_INET; |
674 | else | 700 | else |
675 | pf = PF_INET6; | 701 | pf = PF_INET6; |
@@ -695,7 +721,7 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb, | |||
695 | skb->pkt_type = PACKET_OTHERHOST; | 721 | skb->pkt_type = PACKET_OTHERHOST; |
696 | nf_bridge->mask ^= BRNF_PKT_TYPE; | 722 | nf_bridge->mask ^= BRNF_PKT_TYPE; |
697 | } | 723 | } |
698 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | 724 | if (skb->protocol == htons(ETH_P_8021Q)) { |
699 | skb_push(skb, VLAN_HLEN); | 725 | skb_push(skb, VLAN_HLEN); |
700 | skb->nh.raw -= VLAN_HLEN; | 726 | skb->nh.raw -= VLAN_HLEN; |
701 | } | 727 | } |
@@ -713,14 +739,14 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb, | |||
713 | if (nf_bridge->netoutdev) | 739 | if (nf_bridge->netoutdev) |
714 | realoutdev = nf_bridge->netoutdev; | 740 | realoutdev = nf_bridge->netoutdev; |
715 | #endif | 741 | #endif |
716 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | 742 | if (skb->protocol == htons(ETH_P_8021Q)) { |
717 | skb_pull(skb, VLAN_HLEN); | 743 | skb_pull(skb, VLAN_HLEN); |
718 | (*pskb)->nh.raw += VLAN_HLEN; | 744 | (*pskb)->nh.raw += VLAN_HLEN; |
719 | } | 745 | } |
720 | /* IP forwarded traffic has a physindev, locally | 746 | /* IP forwarded traffic has a physindev, locally |
721 | * generated traffic hasn't. */ | 747 | * generated traffic hasn't. */ |
722 | if (realindev != NULL) { | 748 | if (realindev != NULL) { |
723 | if (!(nf_bridge->mask & BRNF_DONT_TAKE_PARENT) ) { | 749 | if (!(nf_bridge->mask & BRNF_DONT_TAKE_PARENT)) { |
724 | struct net_device *parent = bridge_parent(realindev); | 750 | struct net_device *parent = bridge_parent(realindev); |
725 | if (parent) | 751 | if (parent) |
726 | realindev = parent; | 752 | realindev = parent; |
@@ -742,12 +768,12 @@ out: | |||
742 | 768 | ||
743 | /* PF_BRIDGE/POST_ROUTING ********************************************/ | 769 | /* PF_BRIDGE/POST_ROUTING ********************************************/ |
744 | static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, | 770 | static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, |
745 | const struct net_device *in, const struct net_device *out, | 771 | const struct net_device *in, |
746 | int (*okfn)(struct sk_buff *)) | 772 | const struct net_device *out, |
773 | int (*okfn)(struct sk_buff *)) | ||
747 | { | 774 | { |
748 | struct sk_buff *skb = *pskb; | 775 | struct sk_buff *skb = *pskb; |
749 | struct nf_bridge_info *nf_bridge = (*pskb)->nf_bridge; | 776 | struct nf_bridge_info *nf_bridge = (*pskb)->nf_bridge; |
750 | struct vlan_ethhdr *hdr = vlan_eth_hdr(skb); | ||
751 | struct net_device *realoutdev = bridge_parent(skb->dev); | 777 | struct net_device *realoutdev = bridge_parent(skb->dev); |
752 | int pf; | 778 | int pf; |
753 | 779 | ||
@@ -756,7 +782,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, | |||
756 | * keep the check just to be sure... */ | 782 | * keep the check just to be sure... */ |
757 | if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) { | 783 | if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) { |
758 | printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: " | 784 | printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: " |
759 | "bad mac.raw pointer."); | 785 | "bad mac.raw pointer."); |
760 | goto print_error; | 786 | goto print_error; |
761 | } | 787 | } |
762 | #endif | 788 | #endif |
@@ -767,7 +793,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, | |||
767 | if (!realoutdev) | 793 | if (!realoutdev) |
768 | return NF_DROP; | 794 | return NF_DROP; |
769 | 795 | ||
770 | if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP) | 796 | if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb)) |
771 | pf = PF_INET; | 797 | pf = PF_INET; |
772 | else | 798 | else |
773 | pf = PF_INET6; | 799 | pf = PF_INET6; |
@@ -786,7 +812,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, | |||
786 | nf_bridge->mask |= BRNF_PKT_TYPE; | 812 | nf_bridge->mask |= BRNF_PKT_TYPE; |
787 | } | 813 | } |
788 | 814 | ||
789 | if (skb->protocol == __constant_htons(ETH_P_8021Q)) { | 815 | if (skb->protocol == htons(ETH_P_8021Q)) { |
790 | skb_pull(skb, VLAN_HLEN); | 816 | skb_pull(skb, VLAN_HLEN); |
791 | skb->nh.raw += VLAN_HLEN; | 817 | skb->nh.raw += VLAN_HLEN; |
792 | } | 818 | } |
@@ -798,7 +824,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, | |||
798 | realoutdev = nf_bridge->netoutdev; | 824 | realoutdev = nf_bridge->netoutdev; |
799 | #endif | 825 | #endif |
800 | NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL, realoutdev, | 826 | NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL, realoutdev, |
801 | br_dev_queue_push_xmit); | 827 | br_dev_queue_push_xmit); |
802 | 828 | ||
803 | return NF_STOLEN; | 829 | return NF_STOLEN; |
804 | 830 | ||
@@ -810,18 +836,18 @@ print_error: | |||
810 | printk("[%s]", realoutdev->name); | 836 | printk("[%s]", realoutdev->name); |
811 | } | 837 | } |
812 | printk(" head:%p, raw:%p, data:%p\n", skb->head, skb->mac.raw, | 838 | printk(" head:%p, raw:%p, data:%p\n", skb->head, skb->mac.raw, |
813 | skb->data); | 839 | skb->data); |
814 | return NF_ACCEPT; | 840 | return NF_ACCEPT; |
815 | #endif | 841 | #endif |
816 | } | 842 | } |
817 | 843 | ||
818 | |||
819 | /* IP/SABOTAGE *****************************************************/ | 844 | /* IP/SABOTAGE *****************************************************/ |
820 | /* Don't hand locally destined packets to PF_INET(6)/PRE_ROUTING | 845 | /* Don't hand locally destined packets to PF_INET(6)/PRE_ROUTING |
821 | * for the second time. */ | 846 | * for the second time. */ |
822 | static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff **pskb, | 847 | static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff **pskb, |
823 | const struct net_device *in, const struct net_device *out, | 848 | const struct net_device *in, |
824 | int (*okfn)(struct sk_buff *)) | 849 | const struct net_device *out, |
850 | int (*okfn)(struct sk_buff *)) | ||
825 | { | 851 | { |
826 | if ((*pskb)->nf_bridge && | 852 | if ((*pskb)->nf_bridge && |
827 | !((*pskb)->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)) { | 853 | !((*pskb)->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)) { |
@@ -835,18 +861,18 @@ static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff **pskb, | |||
835 | * and PF_INET(6)/POST_ROUTING until we have done the forwarding | 861 | * and PF_INET(6)/POST_ROUTING until we have done the forwarding |
836 | * decision in the bridge code and have determined nf_bridge->physoutdev. */ | 862 | * decision in the bridge code and have determined nf_bridge->physoutdev. */ |
837 | static unsigned int ip_sabotage_out(unsigned int hook, struct sk_buff **pskb, | 863 | static unsigned int ip_sabotage_out(unsigned int hook, struct sk_buff **pskb, |
838 | const struct net_device *in, const struct net_device *out, | 864 | const struct net_device *in, |
839 | int (*okfn)(struct sk_buff *)) | 865 | const struct net_device *out, |
866 | int (*okfn)(struct sk_buff *)) | ||
840 | { | 867 | { |
841 | struct sk_buff *skb = *pskb; | 868 | struct sk_buff *skb = *pskb; |
842 | 869 | ||
843 | if ((out->hard_start_xmit == br_dev_xmit && | 870 | if ((out->hard_start_xmit == br_dev_xmit && |
844 | okfn != br_nf_forward_finish && | 871 | okfn != br_nf_forward_finish && |
845 | okfn != br_nf_local_out_finish && | 872 | okfn != br_nf_local_out_finish && okfn != br_dev_queue_push_xmit) |
846 | okfn != br_dev_queue_push_xmit) | ||
847 | #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) | 873 | #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) |
848 | || ((out->priv_flags & IFF_802_1Q_VLAN) && | 874 | || ((out->priv_flags & IFF_802_1Q_VLAN) && |
849 | VLAN_DEV_INFO(out)->real_dev->hard_start_xmit == br_dev_xmit) | 875 | VLAN_DEV_INFO(out)->real_dev->hard_start_xmit == br_dev_xmit) |
850 | #endif | 876 | #endif |
851 | ) { | 877 | ) { |
852 | struct nf_bridge_info *nf_bridge; | 878 | struct nf_bridge_info *nf_bridge; |
@@ -971,8 +997,8 @@ static struct nf_hook_ops br_nf_ops[] = { | |||
971 | 997 | ||
972 | #ifdef CONFIG_SYSCTL | 998 | #ifdef CONFIG_SYSCTL |
973 | static | 999 | static |
974 | int brnf_sysctl_call_tables(ctl_table *ctl, int write, struct file * filp, | 1000 | int brnf_sysctl_call_tables(ctl_table * ctl, int write, struct file *filp, |
975 | void __user *buffer, size_t *lenp, loff_t *ppos) | 1001 | void __user * buffer, size_t * lenp, loff_t * ppos) |
976 | { | 1002 | { |
977 | int ret; | 1003 | int ret; |
978 | 1004 | ||
@@ -1059,7 +1085,8 @@ int br_netfilter_init(void) | |||
1059 | #ifdef CONFIG_SYSCTL | 1085 | #ifdef CONFIG_SYSCTL |
1060 | brnf_sysctl_header = register_sysctl_table(brnf_net_table, 0); | 1086 | brnf_sysctl_header = register_sysctl_table(brnf_net_table, 0); |
1061 | if (brnf_sysctl_header == NULL) { | 1087 | if (brnf_sysctl_header == NULL) { |
1062 | printk(KERN_WARNING "br_netfilter: can't register to sysctl.\n"); | 1088 | printk(KERN_WARNING |
1089 | "br_netfilter: can't register to sysctl.\n"); | ||
1063 | for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++) | 1090 | for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++) |
1064 | nf_unregister_hook(&br_nf_ops[i]); | 1091 | nf_unregister_hook(&br_nf_ops[i]); |
1065 | return -EFAULT; | 1092 | return -EFAULT; |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 8f10e09f251b..86ecea7ed372 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -109,6 +109,7 @@ struct net_bridge | |||
109 | unsigned long bridge_hello_time; | 109 | unsigned long bridge_hello_time; |
110 | unsigned long bridge_forward_delay; | 110 | unsigned long bridge_forward_delay; |
111 | 111 | ||
112 | u8 group_addr[ETH_ALEN]; | ||
112 | u16 root_port; | 113 | u16 root_port; |
113 | unsigned char stp_enabled; | 114 | unsigned char stp_enabled; |
114 | unsigned char topology_change; | 115 | unsigned char topology_change; |
@@ -122,7 +123,7 @@ struct net_bridge | |||
122 | }; | 123 | }; |
123 | 124 | ||
124 | extern struct notifier_block br_device_notifier; | 125 | extern struct notifier_block br_device_notifier; |
125 | extern const unsigned char bridge_ula[6]; | 126 | extern const u8 br_group_address[ETH_ALEN]; |
126 | 127 | ||
127 | /* called under bridge lock */ | 128 | /* called under bridge lock */ |
128 | static inline int br_is_root_bridge(const struct net_bridge *br) | 129 | static inline int br_is_root_bridge(const struct net_bridge *br) |
@@ -217,7 +218,8 @@ extern void br_stp_set_path_cost(struct net_bridge_port *p, | |||
217 | extern ssize_t br_show_bridge_id(char *buf, const struct bridge_id *id); | 218 | extern ssize_t br_show_bridge_id(char *buf, const struct bridge_id *id); |
218 | 219 | ||
219 | /* br_stp_bpdu.c */ | 220 | /* br_stp_bpdu.c */ |
220 | extern int br_stp_handle_bpdu(struct sk_buff *skb); | 221 | extern int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, |
222 | struct packet_type *pt, struct net_device *orig_dev); | ||
221 | 223 | ||
222 | /* br_stp_timer.c */ | 224 | /* br_stp_timer.c */ |
223 | extern void br_stp_timer_init(struct net_bridge *br); | 225 | extern void br_stp_timer_init(struct net_bridge *br); |
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 296f6a487c52..8934a54792be 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c | |||
@@ -15,158 +15,162 @@ | |||
15 | 15 | ||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/netfilter_bridge.h> | 17 | #include <linux/netfilter_bridge.h> |
18 | #include <linux/etherdevice.h> | ||
19 | #include <linux/llc.h> | ||
20 | #include <net/llc.h> | ||
21 | #include <net/llc_pdu.h> | ||
18 | 22 | ||
19 | #include "br_private.h" | 23 | #include "br_private.h" |
20 | #include "br_private_stp.h" | 24 | #include "br_private_stp.h" |
21 | 25 | ||
22 | #define JIFFIES_TO_TICKS(j) (((j) << 8) / HZ) | 26 | #define STP_HZ 256 |
23 | #define TICKS_TO_JIFFIES(j) (((j) * HZ) >> 8) | ||
24 | 27 | ||
25 | static void br_send_bpdu(struct net_bridge_port *p, unsigned char *data, int length) | 28 | #define LLC_RESERVE sizeof(struct llc_pdu_un) |
29 | |||
30 | static void br_send_bpdu(struct net_bridge_port *p, | ||
31 | const unsigned char *data, int length) | ||
26 | { | 32 | { |
27 | struct net_device *dev; | ||
28 | struct sk_buff *skb; | 33 | struct sk_buff *skb; |
29 | int size; | ||
30 | 34 | ||
31 | if (!p->br->stp_enabled) | 35 | if (!p->br->stp_enabled) |
32 | return; | 36 | return; |
33 | 37 | ||
34 | size = length + 2*ETH_ALEN + 2; | 38 | skb = dev_alloc_skb(length+LLC_RESERVE); |
35 | if (size < 60) | 39 | if (!skb) |
36 | size = 60; | ||
37 | |||
38 | dev = p->dev; | ||
39 | |||
40 | if ((skb = dev_alloc_skb(size)) == NULL) { | ||
41 | printk(KERN_INFO "br: memory squeeze!\n"); | ||
42 | return; | 40 | return; |
43 | } | ||
44 | 41 | ||
45 | skb->dev = dev; | 42 | skb->dev = p->dev; |
46 | skb->protocol = htons(ETH_P_802_2); | 43 | skb->protocol = htons(ETH_P_802_2); |
47 | skb->mac.raw = skb_put(skb, size); | 44 | |
48 | memcpy(skb->mac.raw, bridge_ula, ETH_ALEN); | 45 | skb_reserve(skb, LLC_RESERVE); |
49 | memcpy(skb->mac.raw+ETH_ALEN, dev->dev_addr, ETH_ALEN); | 46 | memcpy(__skb_put(skb, length), data, length); |
50 | skb->mac.raw[2*ETH_ALEN] = 0; | 47 | |
51 | skb->mac.raw[2*ETH_ALEN+1] = length; | 48 | llc_pdu_header_init(skb, LLC_PDU_TYPE_U, LLC_SAP_BSPAN, |
52 | skb->nh.raw = skb->mac.raw + 2*ETH_ALEN + 2; | 49 | LLC_SAP_BSPAN, LLC_PDU_CMD); |
53 | memcpy(skb->nh.raw, data, length); | 50 | llc_pdu_init_as_ui_cmd(skb); |
54 | memset(skb->nh.raw + length, 0xa5, size - length - 2*ETH_ALEN - 2); | 51 | |
52 | llc_mac_hdr_init(skb, p->dev->dev_addr, p->br->group_addr); | ||
55 | 53 | ||
56 | NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, | 54 | NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, |
57 | dev_queue_xmit); | 55 | dev_queue_xmit); |
58 | } | 56 | } |
59 | 57 | ||
60 | static __inline__ void br_set_ticks(unsigned char *dest, int jiff) | 58 | static inline void br_set_ticks(unsigned char *dest, int j) |
61 | { | 59 | { |
62 | __u16 ticks; | 60 | unsigned long ticks = (STP_HZ * j)/ HZ; |
63 | 61 | ||
64 | ticks = JIFFIES_TO_TICKS(jiff); | 62 | *((__be16 *) dest) = htons(ticks); |
65 | dest[0] = (ticks >> 8) & 0xFF; | ||
66 | dest[1] = ticks & 0xFF; | ||
67 | } | 63 | } |
68 | 64 | ||
69 | static __inline__ int br_get_ticks(unsigned char *dest) | 65 | static inline int br_get_ticks(const unsigned char *src) |
70 | { | 66 | { |
71 | return TICKS_TO_JIFFIES((dest[0] << 8) | dest[1]); | 67 | unsigned long ticks = ntohs(*(__be16 *)src); |
68 | |||
69 | return (ticks * HZ + STP_HZ - 1) / STP_HZ; | ||
72 | } | 70 | } |
73 | 71 | ||
74 | /* called under bridge lock */ | 72 | /* called under bridge lock */ |
75 | void br_send_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu) | 73 | void br_send_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu) |
76 | { | 74 | { |
77 | unsigned char buf[38]; | 75 | unsigned char buf[35]; |
78 | 76 | ||
79 | buf[0] = 0x42; | 77 | buf[0] = 0; |
80 | buf[1] = 0x42; | 78 | buf[1] = 0; |
81 | buf[2] = 0x03; | 79 | buf[2] = 0; |
82 | buf[3] = 0; | 80 | buf[3] = BPDU_TYPE_CONFIG; |
83 | buf[4] = 0; | 81 | buf[4] = (bpdu->topology_change ? 0x01 : 0) | |
84 | buf[5] = 0; | ||
85 | buf[6] = BPDU_TYPE_CONFIG; | ||
86 | buf[7] = (bpdu->topology_change ? 0x01 : 0) | | ||
87 | (bpdu->topology_change_ack ? 0x80 : 0); | 82 | (bpdu->topology_change_ack ? 0x80 : 0); |
88 | buf[8] = bpdu->root.prio[0]; | 83 | buf[5] = bpdu->root.prio[0]; |
89 | buf[9] = bpdu->root.prio[1]; | 84 | buf[6] = bpdu->root.prio[1]; |
90 | buf[10] = bpdu->root.addr[0]; | 85 | buf[7] = bpdu->root.addr[0]; |
91 | buf[11] = bpdu->root.addr[1]; | 86 | buf[8] = bpdu->root.addr[1]; |
92 | buf[12] = bpdu->root.addr[2]; | 87 | buf[9] = bpdu->root.addr[2]; |
93 | buf[13] = bpdu->root.addr[3]; | 88 | buf[10] = bpdu->root.addr[3]; |
94 | buf[14] = bpdu->root.addr[4]; | 89 | buf[11] = bpdu->root.addr[4]; |
95 | buf[15] = bpdu->root.addr[5]; | 90 | buf[12] = bpdu->root.addr[5]; |
96 | buf[16] = (bpdu->root_path_cost >> 24) & 0xFF; | 91 | buf[13] = (bpdu->root_path_cost >> 24) & 0xFF; |
97 | buf[17] = (bpdu->root_path_cost >> 16) & 0xFF; | 92 | buf[14] = (bpdu->root_path_cost >> 16) & 0xFF; |
98 | buf[18] = (bpdu->root_path_cost >> 8) & 0xFF; | 93 | buf[15] = (bpdu->root_path_cost >> 8) & 0xFF; |
99 | buf[19] = bpdu->root_path_cost & 0xFF; | 94 | buf[16] = bpdu->root_path_cost & 0xFF; |
100 | buf[20] = bpdu->bridge_id.prio[0]; | 95 | buf[17] = bpdu->bridge_id.prio[0]; |
101 | buf[21] = bpdu->bridge_id.prio[1]; | 96 | buf[18] = bpdu->bridge_id.prio[1]; |
102 | buf[22] = bpdu->bridge_id.addr[0]; | 97 | buf[19] = bpdu->bridge_id.addr[0]; |
103 | buf[23] = bpdu->bridge_id.addr[1]; | 98 | buf[20] = bpdu->bridge_id.addr[1]; |
104 | buf[24] = bpdu->bridge_id.addr[2]; | 99 | buf[21] = bpdu->bridge_id.addr[2]; |
105 | buf[25] = bpdu->bridge_id.addr[3]; | 100 | buf[22] = bpdu->bridge_id.addr[3]; |
106 | buf[26] = bpdu->bridge_id.addr[4]; | 101 | buf[23] = bpdu->bridge_id.addr[4]; |
107 | buf[27] = bpdu->bridge_id.addr[5]; | 102 | buf[24] = bpdu->bridge_id.addr[5]; |
108 | buf[28] = (bpdu->port_id >> 8) & 0xFF; | 103 | buf[25] = (bpdu->port_id >> 8) & 0xFF; |
109 | buf[29] = bpdu->port_id & 0xFF; | 104 | buf[26] = bpdu->port_id & 0xFF; |
110 | 105 | ||
111 | br_set_ticks(buf+30, bpdu->message_age); | 106 | br_set_ticks(buf+27, bpdu->message_age); |
112 | br_set_ticks(buf+32, bpdu->max_age); | 107 | br_set_ticks(buf+29, bpdu->max_age); |
113 | br_set_ticks(buf+34, bpdu->hello_time); | 108 | br_set_ticks(buf+31, bpdu->hello_time); |
114 | br_set_ticks(buf+36, bpdu->forward_delay); | 109 | br_set_ticks(buf+33, bpdu->forward_delay); |
115 | 110 | ||
116 | br_send_bpdu(p, buf, 38); | 111 | br_send_bpdu(p, buf, 35); |
117 | } | 112 | } |
118 | 113 | ||
119 | /* called under bridge lock */ | 114 | /* called under bridge lock */ |
120 | void br_send_tcn_bpdu(struct net_bridge_port *p) | 115 | void br_send_tcn_bpdu(struct net_bridge_port *p) |
121 | { | 116 | { |
122 | unsigned char buf[7]; | 117 | unsigned char buf[4]; |
123 | 118 | ||
124 | buf[0] = 0x42; | 119 | buf[0] = 0; |
125 | buf[1] = 0x42; | 120 | buf[1] = 0; |
126 | buf[2] = 0x03; | 121 | buf[2] = 0; |
127 | buf[3] = 0; | 122 | buf[3] = BPDU_TYPE_TCN; |
128 | buf[4] = 0; | ||
129 | buf[5] = 0; | ||
130 | buf[6] = BPDU_TYPE_TCN; | ||
131 | br_send_bpdu(p, buf, 7); | 123 | br_send_bpdu(p, buf, 7); |
132 | } | 124 | } |
133 | 125 | ||
134 | static const unsigned char header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00}; | 126 | /* |
135 | 127 | * Called from llc. | |
136 | /* NO locks, but rcu_read_lock (preempt_disabled) */ | 128 | * |
137 | int br_stp_handle_bpdu(struct sk_buff *skb) | 129 | * NO locks, but rcu_read_lock (preempt_disabled) |
130 | */ | ||
131 | int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, | ||
132 | struct packet_type *pt, struct net_device *orig_dev) | ||
138 | { | 133 | { |
139 | struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); | 134 | const struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); |
135 | const unsigned char *dest = eth_hdr(skb)->h_dest; | ||
136 | struct net_bridge_port *p = rcu_dereference(dev->br_port); | ||
140 | struct net_bridge *br; | 137 | struct net_bridge *br; |
141 | unsigned char *buf; | 138 | const unsigned char *buf; |
142 | 139 | ||
143 | if (!p) | 140 | if (!p) |
144 | goto err; | 141 | goto err; |
145 | 142 | ||
146 | br = p->br; | 143 | if (pdu->ssap != LLC_SAP_BSPAN |
147 | spin_lock(&br->lock); | 144 | || pdu->dsap != LLC_SAP_BSPAN |
145 | || pdu->ctrl_1 != LLC_PDU_TYPE_U) | ||
146 | goto err; | ||
148 | 147 | ||
149 | if (p->state == BR_STATE_DISABLED || !(br->dev->flags & IFF_UP)) | 148 | if (!pskb_may_pull(skb, 4)) |
150 | goto out; | 149 | goto err; |
150 | |||
151 | /* compare of protocol id and version */ | ||
152 | buf = skb->data; | ||
153 | if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0) | ||
154 | goto err; | ||
151 | 155 | ||
152 | /* insert into forwarding database after filtering to avoid spoofing */ | 156 | br = p->br; |
153 | br_fdb_update(br, p, eth_hdr(skb)->h_source); | 157 | spin_lock(&br->lock); |
154 | 158 | ||
155 | if (!br->stp_enabled) | 159 | if (p->state == BR_STATE_DISABLED |
160 | || !br->stp_enabled | ||
161 | || !(br->dev->flags & IFF_UP)) | ||
156 | goto out; | 162 | goto out; |
157 | 163 | ||
158 | /* need at least the 802 and STP headers */ | 164 | if (compare_ether_addr(dest, br->group_addr) != 0) |
159 | if (!pskb_may_pull(skb, sizeof(header)+1) || | ||
160 | memcmp(skb->data, header, sizeof(header))) | ||
161 | goto out; | 165 | goto out; |
162 | 166 | ||
163 | buf = skb_pull(skb, sizeof(header)); | 167 | buf = skb_pull(skb, 3); |
164 | 168 | ||
165 | if (buf[0] == BPDU_TYPE_CONFIG) { | 169 | if (buf[0] == BPDU_TYPE_CONFIG) { |
166 | struct br_config_bpdu bpdu; | 170 | struct br_config_bpdu bpdu; |
167 | 171 | ||
168 | if (!pskb_may_pull(skb, 32)) | 172 | if (!pskb_may_pull(skb, 32)) |
169 | goto out; | 173 | goto out; |
170 | 174 | ||
171 | buf = skb->data; | 175 | buf = skb->data; |
172 | bpdu.topology_change = (buf[1] & 0x01) ? 1 : 0; | 176 | bpdu.topology_change = (buf[1] & 0x01) ? 1 : 0; |
diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c index 9bef55f56425..d0fcde82c6fc 100644 --- a/net/bridge/br_stp_timer.c +++ b/net/bridge/br_stp_timer.c | |||
@@ -39,13 +39,13 @@ static void br_hello_timer_expired(unsigned long arg) | |||
39 | struct net_bridge *br = (struct net_bridge *)arg; | 39 | struct net_bridge *br = (struct net_bridge *)arg; |
40 | 40 | ||
41 | pr_debug("%s: hello timer expired\n", br->dev->name); | 41 | pr_debug("%s: hello timer expired\n", br->dev->name); |
42 | spin_lock_bh(&br->lock); | 42 | spin_lock(&br->lock); |
43 | if (br->dev->flags & IFF_UP) { | 43 | if (br->dev->flags & IFF_UP) { |
44 | br_config_bpdu_generation(br); | 44 | br_config_bpdu_generation(br); |
45 | 45 | ||
46 | mod_timer(&br->hello_timer, jiffies + br->hello_time); | 46 | mod_timer(&br->hello_timer, jiffies + br->hello_time); |
47 | } | 47 | } |
48 | spin_unlock_bh(&br->lock); | 48 | spin_unlock(&br->lock); |
49 | } | 49 | } |
50 | 50 | ||
51 | static void br_message_age_timer_expired(unsigned long arg) | 51 | static void br_message_age_timer_expired(unsigned long arg) |
@@ -71,7 +71,7 @@ static void br_message_age_timer_expired(unsigned long arg) | |||
71 | * running when we are the root bridge. So.. this was_root | 71 | * running when we are the root bridge. So.. this was_root |
72 | * check is redundant. I'm leaving it in for now, though. | 72 | * check is redundant. I'm leaving it in for now, though. |
73 | */ | 73 | */ |
74 | spin_lock_bh(&br->lock); | 74 | spin_lock(&br->lock); |
75 | if (p->state == BR_STATE_DISABLED) | 75 | if (p->state == BR_STATE_DISABLED) |
76 | goto unlock; | 76 | goto unlock; |
77 | was_root = br_is_root_bridge(br); | 77 | was_root = br_is_root_bridge(br); |
@@ -82,7 +82,7 @@ static void br_message_age_timer_expired(unsigned long arg) | |||
82 | if (br_is_root_bridge(br) && !was_root) | 82 | if (br_is_root_bridge(br) && !was_root) |
83 | br_become_root_bridge(br); | 83 | br_become_root_bridge(br); |
84 | unlock: | 84 | unlock: |
85 | spin_unlock_bh(&br->lock); | 85 | spin_unlock(&br->lock); |
86 | } | 86 | } |
87 | 87 | ||
88 | static void br_forward_delay_timer_expired(unsigned long arg) | 88 | static void br_forward_delay_timer_expired(unsigned long arg) |
@@ -92,7 +92,7 @@ static void br_forward_delay_timer_expired(unsigned long arg) | |||
92 | 92 | ||
93 | pr_debug("%s: %d(%s) forward delay timer\n", | 93 | pr_debug("%s: %d(%s) forward delay timer\n", |
94 | br->dev->name, p->port_no, p->dev->name); | 94 | br->dev->name, p->port_no, p->dev->name); |
95 | spin_lock_bh(&br->lock); | 95 | spin_lock(&br->lock); |
96 | if (p->state == BR_STATE_LISTENING) { | 96 | if (p->state == BR_STATE_LISTENING) { |
97 | p->state = BR_STATE_LEARNING; | 97 | p->state = BR_STATE_LEARNING; |
98 | mod_timer(&p->forward_delay_timer, | 98 | mod_timer(&p->forward_delay_timer, |
@@ -103,7 +103,7 @@ static void br_forward_delay_timer_expired(unsigned long arg) | |||
103 | br_topology_change_detection(br); | 103 | br_topology_change_detection(br); |
104 | } | 104 | } |
105 | br_log_state(p); | 105 | br_log_state(p); |
106 | spin_unlock_bh(&br->lock); | 106 | spin_unlock(&br->lock); |
107 | } | 107 | } |
108 | 108 | ||
109 | static void br_tcn_timer_expired(unsigned long arg) | 109 | static void br_tcn_timer_expired(unsigned long arg) |
@@ -111,13 +111,13 @@ static void br_tcn_timer_expired(unsigned long arg) | |||
111 | struct net_bridge *br = (struct net_bridge *) arg; | 111 | struct net_bridge *br = (struct net_bridge *) arg; |
112 | 112 | ||
113 | pr_debug("%s: tcn timer expired\n", br->dev->name); | 113 | pr_debug("%s: tcn timer expired\n", br->dev->name); |
114 | spin_lock_bh(&br->lock); | 114 | spin_lock(&br->lock); |
115 | if (br->dev->flags & IFF_UP) { | 115 | if (br->dev->flags & IFF_UP) { |
116 | br_transmit_tcn(br); | 116 | br_transmit_tcn(br); |
117 | 117 | ||
118 | mod_timer(&br->tcn_timer,jiffies + br->bridge_hello_time); | 118 | mod_timer(&br->tcn_timer,jiffies + br->bridge_hello_time); |
119 | } | 119 | } |
120 | spin_unlock_bh(&br->lock); | 120 | spin_unlock(&br->lock); |
121 | } | 121 | } |
122 | 122 | ||
123 | static void br_topology_change_timer_expired(unsigned long arg) | 123 | static void br_topology_change_timer_expired(unsigned long arg) |
@@ -125,10 +125,10 @@ static void br_topology_change_timer_expired(unsigned long arg) | |||
125 | struct net_bridge *br = (struct net_bridge *) arg; | 125 | struct net_bridge *br = (struct net_bridge *) arg; |
126 | 126 | ||
127 | pr_debug("%s: topo change timer expired\n", br->dev->name); | 127 | pr_debug("%s: topo change timer expired\n", br->dev->name); |
128 | spin_lock_bh(&br->lock); | 128 | spin_lock(&br->lock); |
129 | br->topology_change_detected = 0; | 129 | br->topology_change_detected = 0; |
130 | br->topology_change = 0; | 130 | br->topology_change = 0; |
131 | spin_unlock_bh(&br->lock); | 131 | spin_unlock(&br->lock); |
132 | } | 132 | } |
133 | 133 | ||
134 | static void br_hold_timer_expired(unsigned long arg) | 134 | static void br_hold_timer_expired(unsigned long arg) |
@@ -138,45 +138,36 @@ static void br_hold_timer_expired(unsigned long arg) | |||
138 | pr_debug("%s: %d(%s) hold timer expired\n", | 138 | pr_debug("%s: %d(%s) hold timer expired\n", |
139 | p->br->dev->name, p->port_no, p->dev->name); | 139 | p->br->dev->name, p->port_no, p->dev->name); |
140 | 140 | ||
141 | spin_lock_bh(&p->br->lock); | 141 | spin_lock(&p->br->lock); |
142 | if (p->config_pending) | 142 | if (p->config_pending) |
143 | br_transmit_config(p); | 143 | br_transmit_config(p); |
144 | spin_unlock_bh(&p->br->lock); | 144 | spin_unlock(&p->br->lock); |
145 | } | ||
146 | |||
147 | static inline void br_timer_init(struct timer_list *timer, | ||
148 | void (*_function)(unsigned long), | ||
149 | unsigned long _data) | ||
150 | { | ||
151 | init_timer(timer); | ||
152 | timer->function = _function; | ||
153 | timer->data = _data; | ||
154 | } | 145 | } |
155 | 146 | ||
156 | void br_stp_timer_init(struct net_bridge *br) | 147 | void br_stp_timer_init(struct net_bridge *br) |
157 | { | 148 | { |
158 | br_timer_init(&br->hello_timer, br_hello_timer_expired, | 149 | setup_timer(&br->hello_timer, br_hello_timer_expired, |
159 | (unsigned long) br); | 150 | (unsigned long) br); |
160 | 151 | ||
161 | br_timer_init(&br->tcn_timer, br_tcn_timer_expired, | 152 | setup_timer(&br->tcn_timer, br_tcn_timer_expired, |
162 | (unsigned long) br); | 153 | (unsigned long) br); |
163 | 154 | ||
164 | br_timer_init(&br->topology_change_timer, | 155 | setup_timer(&br->topology_change_timer, |
165 | br_topology_change_timer_expired, | 156 | br_topology_change_timer_expired, |
166 | (unsigned long) br); | 157 | (unsigned long) br); |
167 | 158 | ||
168 | br_timer_init(&br->gc_timer, br_fdb_cleanup, (unsigned long) br); | 159 | setup_timer(&br->gc_timer, br_fdb_cleanup, (unsigned long) br); |
169 | } | 160 | } |
170 | 161 | ||
171 | void br_stp_port_timer_init(struct net_bridge_port *p) | 162 | void br_stp_port_timer_init(struct net_bridge_port *p) |
172 | { | 163 | { |
173 | br_timer_init(&p->message_age_timer, br_message_age_timer_expired, | 164 | setup_timer(&p->message_age_timer, br_message_age_timer_expired, |
174 | (unsigned long) p); | 165 | (unsigned long) p); |
175 | 166 | ||
176 | br_timer_init(&p->forward_delay_timer, br_forward_delay_timer_expired, | 167 | setup_timer(&p->forward_delay_timer, br_forward_delay_timer_expired, |
177 | (unsigned long) p); | 168 | (unsigned long) p); |
178 | 169 | ||
179 | br_timer_init(&p->hold_timer, br_hold_timer_expired, | 170 | setup_timer(&p->hold_timer, br_hold_timer_expired, |
180 | (unsigned long) p); | 171 | (unsigned long) p); |
181 | } | 172 | } |
182 | 173 | ||
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 6f577f16c4c0..96bcb2ff59ab 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c | |||
@@ -242,6 +242,54 @@ static ssize_t show_gc_timer(struct class_device *cd, char *buf) | |||
242 | } | 242 | } |
243 | static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); | 243 | static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); |
244 | 244 | ||
245 | static ssize_t show_group_addr(struct class_device *cd, char *buf) | ||
246 | { | ||
247 | struct net_bridge *br = to_bridge(cd); | ||
248 | return sprintf(buf, "%x:%x:%x:%x:%x:%x\n", | ||
249 | br->group_addr[0], br->group_addr[1], | ||
250 | br->group_addr[2], br->group_addr[3], | ||
251 | br->group_addr[4], br->group_addr[5]); | ||
252 | } | ||
253 | |||
254 | static ssize_t store_group_addr(struct class_device *cd, const char *buf, | ||
255 | size_t len) | ||
256 | { | ||
257 | struct net_bridge *br = to_bridge(cd); | ||
258 | unsigned new_addr[6]; | ||
259 | int i; | ||
260 | |||
261 | if (!capable(CAP_NET_ADMIN)) | ||
262 | return -EPERM; | ||
263 | |||
264 | if (sscanf(buf, "%x:%x:%x:%x:%x:%x", | ||
265 | &new_addr[0], &new_addr[1], &new_addr[2], | ||
266 | &new_addr[3], &new_addr[4], &new_addr[5]) != 6) | ||
267 | return -EINVAL; | ||
268 | |||
269 | /* Must be 01:80:c2:00:00:0X */ | ||
270 | for (i = 0; i < 5; i++) | ||
271 | if (new_addr[i] != br_group_address[i]) | ||
272 | return -EINVAL; | ||
273 | |||
274 | if (new_addr[5] & ~0xf) | ||
275 | return -EINVAL; | ||
276 | |||
277 | if (new_addr[5] == 1 /* 802.3x Pause address */ | ||
278 | || new_addr[5] == 2 /* 802.3ad Slow protocols */ | ||
279 | || new_addr[5] == 3) /* 802.1X PAE address */ | ||
280 | return -EINVAL; | ||
281 | |||
282 | spin_lock_bh(&br->lock); | ||
283 | for (i = 0; i < 6; i++) | ||
284 | br->group_addr[i] = new_addr[i]; | ||
285 | spin_unlock_bh(&br->lock); | ||
286 | return len; | ||
287 | } | ||
288 | |||
289 | static CLASS_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR, | ||
290 | show_group_addr, store_group_addr); | ||
291 | |||
292 | |||
245 | static struct attribute *bridge_attrs[] = { | 293 | static struct attribute *bridge_attrs[] = { |
246 | &class_device_attr_forward_delay.attr, | 294 | &class_device_attr_forward_delay.attr, |
247 | &class_device_attr_hello_time.attr, | 295 | &class_device_attr_hello_time.attr, |
@@ -259,6 +307,7 @@ static struct attribute *bridge_attrs[] = { | |||
259 | &class_device_attr_tcn_timer.attr, | 307 | &class_device_attr_tcn_timer.attr, |
260 | &class_device_attr_topology_change_timer.attr, | 308 | &class_device_attr_topology_change_timer.attr, |
261 | &class_device_attr_gc_timer.attr, | 309 | &class_device_attr_gc_timer.attr, |
310 | &class_device_attr_group_addr.attr, | ||
262 | NULL | 311 | NULL |
263 | }; | 312 | }; |
264 | 313 | ||
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index cbd4020cc84d..997953367204 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #define ASSERT_READ_LOCK(x) | 35 | #define ASSERT_READ_LOCK(x) |
36 | #define ASSERT_WRITE_LOCK(x) | 36 | #define ASSERT_WRITE_LOCK(x) |
37 | #include <linux/netfilter_ipv4/listhelp.h> | 37 | #include <linux/netfilter_ipv4/listhelp.h> |
38 | #include <linux/mutex.h> | ||
38 | 39 | ||
39 | #if 0 | 40 | #if 0 |
40 | /* use this for remote debugging | 41 | /* use this for remote debugging |
@@ -81,7 +82,7 @@ static void print_string(char *str) | |||
81 | 82 | ||
82 | 83 | ||
83 | 84 | ||
84 | static DECLARE_MUTEX(ebt_mutex); | 85 | static DEFINE_MUTEX(ebt_mutex); |
85 | static LIST_HEAD(ebt_tables); | 86 | static LIST_HEAD(ebt_tables); |
86 | static LIST_HEAD(ebt_targets); | 87 | static LIST_HEAD(ebt_targets); |
87 | static LIST_HEAD(ebt_matches); | 88 | static LIST_HEAD(ebt_matches); |
@@ -296,18 +297,18 @@ letscontinue: | |||
296 | /* If it succeeds, returns element and locks mutex */ | 297 | /* If it succeeds, returns element and locks mutex */ |
297 | static inline void * | 298 | static inline void * |
298 | find_inlist_lock_noload(struct list_head *head, const char *name, int *error, | 299 | find_inlist_lock_noload(struct list_head *head, const char *name, int *error, |
299 | struct semaphore *mutex) | 300 | struct mutex *mutex) |
300 | { | 301 | { |
301 | void *ret; | 302 | void *ret; |
302 | 303 | ||
303 | *error = down_interruptible(mutex); | 304 | *error = mutex_lock_interruptible(mutex); |
304 | if (*error != 0) | 305 | if (*error != 0) |
305 | return NULL; | 306 | return NULL; |
306 | 307 | ||
307 | ret = list_named_find(head, name); | 308 | ret = list_named_find(head, name); |
308 | if (!ret) { | 309 | if (!ret) { |
309 | *error = -ENOENT; | 310 | *error = -ENOENT; |
310 | up(mutex); | 311 | mutex_unlock(mutex); |
311 | } | 312 | } |
312 | return ret; | 313 | return ret; |
313 | } | 314 | } |
@@ -317,7 +318,7 @@ find_inlist_lock_noload(struct list_head *head, const char *name, int *error, | |||
317 | #else | 318 | #else |
318 | static void * | 319 | static void * |
319 | find_inlist_lock(struct list_head *head, const char *name, const char *prefix, | 320 | find_inlist_lock(struct list_head *head, const char *name, const char *prefix, |
320 | int *error, struct semaphore *mutex) | 321 | int *error, struct mutex *mutex) |
321 | { | 322 | { |
322 | void *ret; | 323 | void *ret; |
323 | 324 | ||
@@ -331,25 +332,25 @@ find_inlist_lock(struct list_head *head, const char *name, const char *prefix, | |||
331 | #endif | 332 | #endif |
332 | 333 | ||
333 | static inline struct ebt_table * | 334 | static inline struct ebt_table * |
334 | find_table_lock(const char *name, int *error, struct semaphore *mutex) | 335 | find_table_lock(const char *name, int *error, struct mutex *mutex) |
335 | { | 336 | { |
336 | return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex); | 337 | return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex); |
337 | } | 338 | } |
338 | 339 | ||
339 | static inline struct ebt_match * | 340 | static inline struct ebt_match * |
340 | find_match_lock(const char *name, int *error, struct semaphore *mutex) | 341 | find_match_lock(const char *name, int *error, struct mutex *mutex) |
341 | { | 342 | { |
342 | return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex); | 343 | return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex); |
343 | } | 344 | } |
344 | 345 | ||
345 | static inline struct ebt_watcher * | 346 | static inline struct ebt_watcher * |
346 | find_watcher_lock(const char *name, int *error, struct semaphore *mutex) | 347 | find_watcher_lock(const char *name, int *error, struct mutex *mutex) |
347 | { | 348 | { |
348 | return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex); | 349 | return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex); |
349 | } | 350 | } |
350 | 351 | ||
351 | static inline struct ebt_target * | 352 | static inline struct ebt_target * |
352 | find_target_lock(const char *name, int *error, struct semaphore *mutex) | 353 | find_target_lock(const char *name, int *error, struct mutex *mutex) |
353 | { | 354 | { |
354 | return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex); | 355 | return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex); |
355 | } | 356 | } |
@@ -369,10 +370,10 @@ ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e, | |||
369 | return ret; | 370 | return ret; |
370 | m->u.match = match; | 371 | m->u.match = match; |
371 | if (!try_module_get(match->me)) { | 372 | if (!try_module_get(match->me)) { |
372 | up(&ebt_mutex); | 373 | mutex_unlock(&ebt_mutex); |
373 | return -ENOENT; | 374 | return -ENOENT; |
374 | } | 375 | } |
375 | up(&ebt_mutex); | 376 | mutex_unlock(&ebt_mutex); |
376 | if (match->check && | 377 | if (match->check && |
377 | match->check(name, hookmask, e, m->data, m->match_size) != 0) { | 378 | match->check(name, hookmask, e, m->data, m->match_size) != 0) { |
378 | BUGPRINT("match->check failed\n"); | 379 | BUGPRINT("match->check failed\n"); |
@@ -398,10 +399,10 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e, | |||
398 | return ret; | 399 | return ret; |
399 | w->u.watcher = watcher; | 400 | w->u.watcher = watcher; |
400 | if (!try_module_get(watcher->me)) { | 401 | if (!try_module_get(watcher->me)) { |
401 | up(&ebt_mutex); | 402 | mutex_unlock(&ebt_mutex); |
402 | return -ENOENT; | 403 | return -ENOENT; |
403 | } | 404 | } |
404 | up(&ebt_mutex); | 405 | mutex_unlock(&ebt_mutex); |
405 | if (watcher->check && | 406 | if (watcher->check && |
406 | watcher->check(name, hookmask, e, w->data, w->watcher_size) != 0) { | 407 | watcher->check(name, hookmask, e, w->data, w->watcher_size) != 0) { |
407 | BUGPRINT("watcher->check failed\n"); | 408 | BUGPRINT("watcher->check failed\n"); |
@@ -638,11 +639,11 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, | |||
638 | if (!target) | 639 | if (!target) |
639 | goto cleanup_watchers; | 640 | goto cleanup_watchers; |
640 | if (!try_module_get(target->me)) { | 641 | if (!try_module_get(target->me)) { |
641 | up(&ebt_mutex); | 642 | mutex_unlock(&ebt_mutex); |
642 | ret = -ENOENT; | 643 | ret = -ENOENT; |
643 | goto cleanup_watchers; | 644 | goto cleanup_watchers; |
644 | } | 645 | } |
645 | up(&ebt_mutex); | 646 | mutex_unlock(&ebt_mutex); |
646 | 647 | ||
647 | t->u.target = target; | 648 | t->u.target = target; |
648 | if (t->u.target == &ebt_standard_target) { | 649 | if (t->u.target == &ebt_standard_target) { |
@@ -1015,7 +1016,7 @@ static int do_replace(void __user *user, unsigned int len) | |||
1015 | 1016 | ||
1016 | t->private = newinfo; | 1017 | t->private = newinfo; |
1017 | write_unlock_bh(&t->lock); | 1018 | write_unlock_bh(&t->lock); |
1018 | up(&ebt_mutex); | 1019 | mutex_unlock(&ebt_mutex); |
1019 | /* so, a user can change the chains while having messed up her counter | 1020 | /* so, a user can change the chains while having messed up her counter |
1020 | allocation. Only reason why this is done is because this way the lock | 1021 | allocation. Only reason why this is done is because this way the lock |
1021 | is held only once, while this doesn't bring the kernel into a | 1022 | is held only once, while this doesn't bring the kernel into a |
@@ -1045,7 +1046,7 @@ static int do_replace(void __user *user, unsigned int len) | |||
1045 | return ret; | 1046 | return ret; |
1046 | 1047 | ||
1047 | free_unlock: | 1048 | free_unlock: |
1048 | up(&ebt_mutex); | 1049 | mutex_unlock(&ebt_mutex); |
1049 | free_iterate: | 1050 | free_iterate: |
1050 | EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, | 1051 | EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, |
1051 | ebt_cleanup_entry, NULL); | 1052 | ebt_cleanup_entry, NULL); |
@@ -1068,69 +1069,69 @@ int ebt_register_target(struct ebt_target *target) | |||
1068 | { | 1069 | { |
1069 | int ret; | 1070 | int ret; |
1070 | 1071 | ||
1071 | ret = down_interruptible(&ebt_mutex); | 1072 | ret = mutex_lock_interruptible(&ebt_mutex); |
1072 | if (ret != 0) | 1073 | if (ret != 0) |
1073 | return ret; | 1074 | return ret; |
1074 | if (!list_named_insert(&ebt_targets, target)) { | 1075 | if (!list_named_insert(&ebt_targets, target)) { |
1075 | up(&ebt_mutex); | 1076 | mutex_unlock(&ebt_mutex); |
1076 | return -EEXIST; | 1077 | return -EEXIST; |
1077 | } | 1078 | } |
1078 | up(&ebt_mutex); | 1079 | mutex_unlock(&ebt_mutex); |
1079 | 1080 | ||
1080 | return 0; | 1081 | return 0; |
1081 | } | 1082 | } |
1082 | 1083 | ||
1083 | void ebt_unregister_target(struct ebt_target *target) | 1084 | void ebt_unregister_target(struct ebt_target *target) |
1084 | { | 1085 | { |
1085 | down(&ebt_mutex); | 1086 | mutex_lock(&ebt_mutex); |
1086 | LIST_DELETE(&ebt_targets, target); | 1087 | LIST_DELETE(&ebt_targets, target); |
1087 | up(&ebt_mutex); | 1088 | mutex_unlock(&ebt_mutex); |
1088 | } | 1089 | } |
1089 | 1090 | ||
1090 | int ebt_register_match(struct ebt_match *match) | 1091 | int ebt_register_match(struct ebt_match *match) |
1091 | { | 1092 | { |
1092 | int ret; | 1093 | int ret; |
1093 | 1094 | ||
1094 | ret = down_interruptible(&ebt_mutex); | 1095 | ret = mutex_lock_interruptible(&ebt_mutex); |
1095 | if (ret != 0) | 1096 | if (ret != 0) |
1096 | return ret; | 1097 | return ret; |
1097 | if (!list_named_insert(&ebt_matches, match)) { | 1098 | if (!list_named_insert(&ebt_matches, match)) { |
1098 | up(&ebt_mutex); | 1099 | mutex_unlock(&ebt_mutex); |
1099 | return -EEXIST; | 1100 | return -EEXIST; |
1100 | } | 1101 | } |
1101 | up(&ebt_mutex); | 1102 | mutex_unlock(&ebt_mutex); |
1102 | 1103 | ||
1103 | return 0; | 1104 | return 0; |
1104 | } | 1105 | } |
1105 | 1106 | ||
1106 | void ebt_unregister_match(struct ebt_match *match) | 1107 | void ebt_unregister_match(struct ebt_match *match) |
1107 | { | 1108 | { |
1108 | down(&ebt_mutex); | 1109 | mutex_lock(&ebt_mutex); |
1109 | LIST_DELETE(&ebt_matches, match); | 1110 | LIST_DELETE(&ebt_matches, match); |
1110 | up(&ebt_mutex); | 1111 | mutex_unlock(&ebt_mutex); |
1111 | } | 1112 | } |
1112 | 1113 | ||
1113 | int ebt_register_watcher(struct ebt_watcher *watcher) | 1114 | int ebt_register_watcher(struct ebt_watcher *watcher) |
1114 | { | 1115 | { |
1115 | int ret; | 1116 | int ret; |
1116 | 1117 | ||
1117 | ret = down_interruptible(&ebt_mutex); | 1118 | ret = mutex_lock_interruptible(&ebt_mutex); |
1118 | if (ret != 0) | 1119 | if (ret != 0) |
1119 | return ret; | 1120 | return ret; |
1120 | if (!list_named_insert(&ebt_watchers, watcher)) { | 1121 | if (!list_named_insert(&ebt_watchers, watcher)) { |
1121 | up(&ebt_mutex); | 1122 | mutex_unlock(&ebt_mutex); |
1122 | return -EEXIST; | 1123 | return -EEXIST; |
1123 | } | 1124 | } |
1124 | up(&ebt_mutex); | 1125 | mutex_unlock(&ebt_mutex); |
1125 | 1126 | ||
1126 | return 0; | 1127 | return 0; |
1127 | } | 1128 | } |
1128 | 1129 | ||
1129 | void ebt_unregister_watcher(struct ebt_watcher *watcher) | 1130 | void ebt_unregister_watcher(struct ebt_watcher *watcher) |
1130 | { | 1131 | { |
1131 | down(&ebt_mutex); | 1132 | mutex_lock(&ebt_mutex); |
1132 | LIST_DELETE(&ebt_watchers, watcher); | 1133 | LIST_DELETE(&ebt_watchers, watcher); |
1133 | up(&ebt_mutex); | 1134 | mutex_unlock(&ebt_mutex); |
1134 | } | 1135 | } |
1135 | 1136 | ||
1136 | int ebt_register_table(struct ebt_table *table) | 1137 | int ebt_register_table(struct ebt_table *table) |
@@ -1178,7 +1179,7 @@ int ebt_register_table(struct ebt_table *table) | |||
1178 | 1179 | ||
1179 | table->private = newinfo; | 1180 | table->private = newinfo; |
1180 | rwlock_init(&table->lock); | 1181 | rwlock_init(&table->lock); |
1181 | ret = down_interruptible(&ebt_mutex); | 1182 | ret = mutex_lock_interruptible(&ebt_mutex); |
1182 | if (ret != 0) | 1183 | if (ret != 0) |
1183 | goto free_chainstack; | 1184 | goto free_chainstack; |
1184 | 1185 | ||
@@ -1194,10 +1195,10 @@ int ebt_register_table(struct ebt_table *table) | |||
1194 | goto free_unlock; | 1195 | goto free_unlock; |
1195 | } | 1196 | } |
1196 | list_prepend(&ebt_tables, table); | 1197 | list_prepend(&ebt_tables, table); |
1197 | up(&ebt_mutex); | 1198 | mutex_unlock(&ebt_mutex); |
1198 | return 0; | 1199 | return 0; |
1199 | free_unlock: | 1200 | free_unlock: |
1200 | up(&ebt_mutex); | 1201 | mutex_unlock(&ebt_mutex); |
1201 | free_chainstack: | 1202 | free_chainstack: |
1202 | if (newinfo->chainstack) { | 1203 | if (newinfo->chainstack) { |
1203 | for_each_cpu(i) | 1204 | for_each_cpu(i) |
@@ -1218,9 +1219,9 @@ void ebt_unregister_table(struct ebt_table *table) | |||
1218 | BUGPRINT("Request to unregister NULL table!!!\n"); | 1219 | BUGPRINT("Request to unregister NULL table!!!\n"); |
1219 | return; | 1220 | return; |
1220 | } | 1221 | } |
1221 | down(&ebt_mutex); | 1222 | mutex_lock(&ebt_mutex); |
1222 | LIST_DELETE(&ebt_tables, table); | 1223 | LIST_DELETE(&ebt_tables, table); |
1223 | up(&ebt_mutex); | 1224 | mutex_unlock(&ebt_mutex); |
1224 | vfree(table->private->entries); | 1225 | vfree(table->private->entries); |
1225 | if (table->private->chainstack) { | 1226 | if (table->private->chainstack) { |
1226 | for_each_cpu(i) | 1227 | for_each_cpu(i) |
@@ -1281,7 +1282,7 @@ static int update_counters(void __user *user, unsigned int len) | |||
1281 | write_unlock_bh(&t->lock); | 1282 | write_unlock_bh(&t->lock); |
1282 | ret = 0; | 1283 | ret = 0; |
1283 | unlock_mutex: | 1284 | unlock_mutex: |
1284 | up(&ebt_mutex); | 1285 | mutex_unlock(&ebt_mutex); |
1285 | free_tmp: | 1286 | free_tmp: |
1286 | vfree(tmp); | 1287 | vfree(tmp); |
1287 | return ret; | 1288 | return ret; |
@@ -1328,7 +1329,7 @@ static inline int ebt_make_names(struct ebt_entry *e, char *base, char *ubase) | |||
1328 | return 0; | 1329 | return 0; |
1329 | } | 1330 | } |
1330 | 1331 | ||
1331 | /* called with ebt_mutex down */ | 1332 | /* called with ebt_mutex locked */ |
1332 | static int copy_everything_to_user(struct ebt_table *t, void __user *user, | 1333 | static int copy_everything_to_user(struct ebt_table *t, void __user *user, |
1333 | int *len, int cmd) | 1334 | int *len, int cmd) |
1334 | { | 1335 | { |
@@ -1440,7 +1441,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
1440 | case EBT_SO_GET_INIT_INFO: | 1441 | case EBT_SO_GET_INIT_INFO: |
1441 | if (*len != sizeof(struct ebt_replace)){ | 1442 | if (*len != sizeof(struct ebt_replace)){ |
1442 | ret = -EINVAL; | 1443 | ret = -EINVAL; |
1443 | up(&ebt_mutex); | 1444 | mutex_unlock(&ebt_mutex); |
1444 | break; | 1445 | break; |
1445 | } | 1446 | } |
1446 | if (cmd == EBT_SO_GET_INFO) { | 1447 | if (cmd == EBT_SO_GET_INFO) { |
@@ -1452,7 +1453,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
1452 | tmp.entries_size = t->table->entries_size; | 1453 | tmp.entries_size = t->table->entries_size; |
1453 | tmp.valid_hooks = t->table->valid_hooks; | 1454 | tmp.valid_hooks = t->table->valid_hooks; |
1454 | } | 1455 | } |
1455 | up(&ebt_mutex); | 1456 | mutex_unlock(&ebt_mutex); |
1456 | if (copy_to_user(user, &tmp, *len) != 0){ | 1457 | if (copy_to_user(user, &tmp, *len) != 0){ |
1457 | BUGPRINT("c2u Didn't work\n"); | 1458 | BUGPRINT("c2u Didn't work\n"); |
1458 | ret = -EFAULT; | 1459 | ret = -EFAULT; |
@@ -1464,11 +1465,11 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
1464 | case EBT_SO_GET_ENTRIES: | 1465 | case EBT_SO_GET_ENTRIES: |
1465 | case EBT_SO_GET_INIT_ENTRIES: | 1466 | case EBT_SO_GET_INIT_ENTRIES: |
1466 | ret = copy_everything_to_user(t, user, len, cmd); | 1467 | ret = copy_everything_to_user(t, user, len, cmd); |
1467 | up(&ebt_mutex); | 1468 | mutex_unlock(&ebt_mutex); |
1468 | break; | 1469 | break; |
1469 | 1470 | ||
1470 | default: | 1471 | default: |
1471 | up(&ebt_mutex); | 1472 | mutex_unlock(&ebt_mutex); |
1472 | ret = -EINVAL; | 1473 | ret = -EINVAL; |
1473 | } | 1474 | } |
1474 | 1475 | ||
@@ -1476,17 +1477,23 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
1476 | } | 1477 | } |
1477 | 1478 | ||
1478 | static struct nf_sockopt_ops ebt_sockopts = | 1479 | static struct nf_sockopt_ops ebt_sockopts = |
1479 | { { NULL, NULL }, PF_INET, EBT_BASE_CTL, EBT_SO_SET_MAX + 1, do_ebt_set_ctl, | 1480 | { |
1480 | EBT_BASE_CTL, EBT_SO_GET_MAX + 1, do_ebt_get_ctl, 0, NULL | 1481 | .pf = PF_INET, |
1482 | .set_optmin = EBT_BASE_CTL, | ||
1483 | .set_optmax = EBT_SO_SET_MAX + 1, | ||
1484 | .set = do_ebt_set_ctl, | ||
1485 | .get_optmin = EBT_BASE_CTL, | ||
1486 | .get_optmax = EBT_SO_GET_MAX + 1, | ||
1487 | .get = do_ebt_get_ctl, | ||
1481 | }; | 1488 | }; |
1482 | 1489 | ||
1483 | static int __init init(void) | 1490 | static int __init init(void) |
1484 | { | 1491 | { |
1485 | int ret; | 1492 | int ret; |
1486 | 1493 | ||
1487 | down(&ebt_mutex); | 1494 | mutex_lock(&ebt_mutex); |
1488 | list_named_insert(&ebt_targets, &ebt_standard_target); | 1495 | list_named_insert(&ebt_targets, &ebt_standard_target); |
1489 | up(&ebt_mutex); | 1496 | mutex_unlock(&ebt_mutex); |
1490 | if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0) | 1497 | if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0) |
1491 | return ret; | 1498 | return ret; |
1492 | 1499 | ||
diff --git a/net/compat.c b/net/compat.c index e593dace2fdb..8fd37cd7b501 100644 --- a/net/compat.c +++ b/net/compat.c | |||
@@ -416,7 +416,7 @@ struct compat_sock_fprog { | |||
416 | compat_uptr_t filter; /* struct sock_filter * */ | 416 | compat_uptr_t filter; /* struct sock_filter * */ |
417 | }; | 417 | }; |
418 | 418 | ||
419 | static int do_set_attach_filter(int fd, int level, int optname, | 419 | static int do_set_attach_filter(struct socket *sock, int level, int optname, |
420 | char __user *optval, int optlen) | 420 | char __user *optval, int optlen) |
421 | { | 421 | { |
422 | struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval; | 422 | struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval; |
@@ -432,11 +432,12 @@ static int do_set_attach_filter(int fd, int level, int optname, | |||
432 | __put_user(compat_ptr(ptr), &kfprog->filter)) | 432 | __put_user(compat_ptr(ptr), &kfprog->filter)) |
433 | return -EFAULT; | 433 | return -EFAULT; |
434 | 434 | ||
435 | return sys_setsockopt(fd, level, optname, (char __user *)kfprog, | 435 | return sock_setsockopt(sock, level, optname, (char __user *)kfprog, |
436 | sizeof(struct sock_fprog)); | 436 | sizeof(struct sock_fprog)); |
437 | } | 437 | } |
438 | 438 | ||
439 | static int do_set_sock_timeout(int fd, int level, int optname, char __user *optval, int optlen) | 439 | static int do_set_sock_timeout(struct socket *sock, int level, |
440 | int optname, char __user *optval, int optlen) | ||
440 | { | 441 | { |
441 | struct compat_timeval __user *up = (struct compat_timeval __user *) optval; | 442 | struct compat_timeval __user *up = (struct compat_timeval __user *) optval; |
442 | struct timeval ktime; | 443 | struct timeval ktime; |
@@ -451,30 +452,61 @@ static int do_set_sock_timeout(int fd, int level, int optname, char __user *optv | |||
451 | return -EFAULT; | 452 | return -EFAULT; |
452 | old_fs = get_fs(); | 453 | old_fs = get_fs(); |
453 | set_fs(KERNEL_DS); | 454 | set_fs(KERNEL_DS); |
454 | err = sys_setsockopt(fd, level, optname, (char *) &ktime, sizeof(ktime)); | 455 | err = sock_setsockopt(sock, level, optname, (char *) &ktime, sizeof(ktime)); |
455 | set_fs(old_fs); | 456 | set_fs(old_fs); |
456 | 457 | ||
457 | return err; | 458 | return err; |
458 | } | 459 | } |
459 | 460 | ||
461 | static int compat_sock_setsockopt(struct socket *sock, int level, int optname, | ||
462 | char __user *optval, int optlen) | ||
463 | { | ||
464 | if (optname == SO_ATTACH_FILTER) | ||
465 | return do_set_attach_filter(sock, level, optname, | ||
466 | optval, optlen); | ||
467 | if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) | ||
468 | return do_set_sock_timeout(sock, level, optname, optval, optlen); | ||
469 | |||
470 | return sock_setsockopt(sock, level, optname, optval, optlen); | ||
471 | } | ||
472 | |||
460 | asmlinkage long compat_sys_setsockopt(int fd, int level, int optname, | 473 | asmlinkage long compat_sys_setsockopt(int fd, int level, int optname, |
461 | char __user *optval, int optlen) | 474 | char __user *optval, int optlen) |
462 | { | 475 | { |
476 | int err; | ||
477 | struct socket *sock; | ||
478 | |||
463 | /* SO_SET_REPLACE seems to be the same in all levels */ | 479 | /* SO_SET_REPLACE seems to be the same in all levels */ |
464 | if (optname == IPT_SO_SET_REPLACE) | 480 | if (optname == IPT_SO_SET_REPLACE) |
465 | return do_netfilter_replace(fd, level, optname, | 481 | return do_netfilter_replace(fd, level, optname, |
466 | optval, optlen); | 482 | optval, optlen); |
467 | if (level == SOL_SOCKET && optname == SO_ATTACH_FILTER) | ||
468 | return do_set_attach_filter(fd, level, optname, | ||
469 | optval, optlen); | ||
470 | if (level == SOL_SOCKET && | ||
471 | (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) | ||
472 | return do_set_sock_timeout(fd, level, optname, optval, optlen); | ||
473 | 483 | ||
474 | return sys_setsockopt(fd, level, optname, optval, optlen); | 484 | if (optlen < 0) |
485 | return -EINVAL; | ||
486 | |||
487 | if ((sock = sockfd_lookup(fd, &err))!=NULL) | ||
488 | { | ||
489 | err = security_socket_setsockopt(sock,level,optname); | ||
490 | if (err) { | ||
491 | sockfd_put(sock); | ||
492 | return err; | ||
493 | } | ||
494 | |||
495 | if (level == SOL_SOCKET) | ||
496 | err = compat_sock_setsockopt(sock, level, | ||
497 | optname, optval, optlen); | ||
498 | else if (sock->ops->compat_setsockopt) | ||
499 | err = sock->ops->compat_setsockopt(sock, level, | ||
500 | optname, optval, optlen); | ||
501 | else | ||
502 | err = sock->ops->setsockopt(sock, level, | ||
503 | optname, optval, optlen); | ||
504 | sockfd_put(sock); | ||
505 | } | ||
506 | return err; | ||
475 | } | 507 | } |
476 | 508 | ||
477 | static int do_get_sock_timeout(int fd, int level, int optname, | 509 | static int do_get_sock_timeout(struct socket *sock, int level, int optname, |
478 | char __user *optval, int __user *optlen) | 510 | char __user *optval, int __user *optlen) |
479 | { | 511 | { |
480 | struct compat_timeval __user *up; | 512 | struct compat_timeval __user *up; |
@@ -490,7 +522,7 @@ static int do_get_sock_timeout(int fd, int level, int optname, | |||
490 | len = sizeof(ktime); | 522 | len = sizeof(ktime); |
491 | old_fs = get_fs(); | 523 | old_fs = get_fs(); |
492 | set_fs(KERNEL_DS); | 524 | set_fs(KERNEL_DS); |
493 | err = sys_getsockopt(fd, level, optname, (char *) &ktime, &len); | 525 | err = sock_getsockopt(sock, level, optname, (char *) &ktime, &len); |
494 | set_fs(old_fs); | 526 | set_fs(old_fs); |
495 | 527 | ||
496 | if (!err) { | 528 | if (!err) { |
@@ -503,15 +535,61 @@ static int do_get_sock_timeout(int fd, int level, int optname, | |||
503 | return err; | 535 | return err; |
504 | } | 536 | } |
505 | 537 | ||
506 | asmlinkage long compat_sys_getsockopt(int fd, int level, int optname, | 538 | static int compat_sock_getsockopt(struct socket *sock, int level, int optname, |
507 | char __user *optval, int __user *optlen) | 539 | char __user *optval, int __user *optlen) |
508 | { | 540 | { |
509 | if (level == SOL_SOCKET && | 541 | if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) |
510 | (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) | 542 | return do_get_sock_timeout(sock, level, optname, optval, optlen); |
511 | return do_get_sock_timeout(fd, level, optname, optval, optlen); | 543 | return sock_getsockopt(sock, level, optname, optval, optlen); |
512 | return sys_getsockopt(fd, level, optname, optval, optlen); | 544 | } |
545 | |||
546 | int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp) | ||
547 | { | ||
548 | struct compat_timeval __user *ctv = | ||
549 | (struct compat_timeval __user*) userstamp; | ||
550 | int err = -ENOENT; | ||
551 | |||
552 | if (!sock_flag(sk, SOCK_TIMESTAMP)) | ||
553 | sock_enable_timestamp(sk); | ||
554 | if (sk->sk_stamp.tv_sec == -1) | ||
555 | return err; | ||
556 | if (sk->sk_stamp.tv_sec == 0) | ||
557 | do_gettimeofday(&sk->sk_stamp); | ||
558 | if (put_user(sk->sk_stamp.tv_sec, &ctv->tv_sec) || | ||
559 | put_user(sk->sk_stamp.tv_usec, &ctv->tv_usec)) | ||
560 | err = -EFAULT; | ||
561 | return err; | ||
513 | } | 562 | } |
563 | EXPORT_SYMBOL(compat_sock_get_timestamp); | ||
564 | |||
565 | asmlinkage long compat_sys_getsockopt(int fd, int level, int optname, | ||
566 | char __user *optval, int __user *optlen) | ||
567 | { | ||
568 | int err; | ||
569 | struct socket *sock; | ||
570 | |||
571 | if ((sock = sockfd_lookup(fd, &err))!=NULL) | ||
572 | { | ||
573 | err = security_socket_getsockopt(sock, level, | ||
574 | optname); | ||
575 | if (err) { | ||
576 | sockfd_put(sock); | ||
577 | return err; | ||
578 | } | ||
514 | 579 | ||
580 | if (level == SOL_SOCKET) | ||
581 | err = compat_sock_getsockopt(sock, level, | ||
582 | optname, optval, optlen); | ||
583 | else if (sock->ops->compat_getsockopt) | ||
584 | err = sock->ops->compat_getsockopt(sock, level, | ||
585 | optname, optval, optlen); | ||
586 | else | ||
587 | err = sock->ops->getsockopt(sock, level, | ||
588 | optname, optval, optlen); | ||
589 | sockfd_put(sock); | ||
590 | } | ||
591 | return err; | ||
592 | } | ||
515 | /* Argument list sizes for compat_sys_socketcall */ | 593 | /* Argument list sizes for compat_sys_socketcall */ |
516 | #define AL(x) ((x) * sizeof(u32)) | 594 | #define AL(x) ((x) * sizeof(u32)) |
517 | static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), | 595 | static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), |
diff --git a/net/core/dev.c b/net/core/dev.c index ef56c035d44e..08dec6eb922b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -81,6 +81,7 @@ | |||
81 | #include <linux/types.h> | 81 | #include <linux/types.h> |
82 | #include <linux/kernel.h> | 82 | #include <linux/kernel.h> |
83 | #include <linux/sched.h> | 83 | #include <linux/sched.h> |
84 | #include <linux/mutex.h> | ||
84 | #include <linux/string.h> | 85 | #include <linux/string.h> |
85 | #include <linux/mm.h> | 86 | #include <linux/mm.h> |
86 | #include <linux/socket.h> | 87 | #include <linux/socket.h> |
@@ -1759,8 +1760,7 @@ static void net_rx_action(struct softirq_action *h) | |||
1759 | if (dev->quota <= 0 || dev->poll(dev, &budget)) { | 1760 | if (dev->quota <= 0 || dev->poll(dev, &budget)) { |
1760 | netpoll_poll_unlock(have); | 1761 | netpoll_poll_unlock(have); |
1761 | local_irq_disable(); | 1762 | local_irq_disable(); |
1762 | list_del(&dev->poll_list); | 1763 | list_move_tail(&dev->poll_list, &queue->poll_list); |
1763 | list_add_tail(&dev->poll_list, &queue->poll_list); | ||
1764 | if (dev->quota < 0) | 1764 | if (dev->quota < 0) |
1765 | dev->quota += dev->weight; | 1765 | dev->quota += dev->weight; |
1766 | else | 1766 | else |
@@ -2174,12 +2174,20 @@ unsigned dev_get_flags(const struct net_device *dev) | |||
2174 | 2174 | ||
2175 | flags = (dev->flags & ~(IFF_PROMISC | | 2175 | flags = (dev->flags & ~(IFF_PROMISC | |
2176 | IFF_ALLMULTI | | 2176 | IFF_ALLMULTI | |
2177 | IFF_RUNNING)) | | 2177 | IFF_RUNNING | |
2178 | IFF_LOWER_UP | | ||
2179 | IFF_DORMANT)) | | ||
2178 | (dev->gflags & (IFF_PROMISC | | 2180 | (dev->gflags & (IFF_PROMISC | |
2179 | IFF_ALLMULTI)); | 2181 | IFF_ALLMULTI)); |
2180 | 2182 | ||
2181 | if (netif_running(dev) && netif_carrier_ok(dev)) | 2183 | if (netif_running(dev)) { |
2182 | flags |= IFF_RUNNING; | 2184 | if (netif_oper_up(dev)) |
2185 | flags |= IFF_RUNNING; | ||
2186 | if (netif_carrier_ok(dev)) | ||
2187 | flags |= IFF_LOWER_UP; | ||
2188 | if (netif_dormant(dev)) | ||
2189 | flags |= IFF_DORMANT; | ||
2190 | } | ||
2183 | 2191 | ||
2184 | return flags; | 2192 | return flags; |
2185 | } | 2193 | } |
@@ -2458,9 +2466,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg) | |||
2458 | */ | 2466 | */ |
2459 | 2467 | ||
2460 | if (cmd == SIOCGIFCONF) { | 2468 | if (cmd == SIOCGIFCONF) { |
2461 | rtnl_shlock(); | 2469 | rtnl_lock(); |
2462 | ret = dev_ifconf((char __user *) arg); | 2470 | ret = dev_ifconf((char __user *) arg); |
2463 | rtnl_shunlock(); | 2471 | rtnl_unlock(); |
2464 | return ret; | 2472 | return ret; |
2465 | } | 2473 | } |
2466 | if (cmd == SIOCGIFNAME) | 2474 | if (cmd == SIOCGIFNAME) |
@@ -2869,7 +2877,7 @@ static void netdev_wait_allrefs(struct net_device *dev) | |||
2869 | rebroadcast_time = warning_time = jiffies; | 2877 | rebroadcast_time = warning_time = jiffies; |
2870 | while (atomic_read(&dev->refcnt) != 0) { | 2878 | while (atomic_read(&dev->refcnt) != 0) { |
2871 | if (time_after(jiffies, rebroadcast_time + 1 * HZ)) { | 2879 | if (time_after(jiffies, rebroadcast_time + 1 * HZ)) { |
2872 | rtnl_shlock(); | 2880 | rtnl_lock(); |
2873 | 2881 | ||
2874 | /* Rebroadcast unregister notification */ | 2882 | /* Rebroadcast unregister notification */ |
2875 | notifier_call_chain(&netdev_chain, | 2883 | notifier_call_chain(&netdev_chain, |
@@ -2886,7 +2894,7 @@ static void netdev_wait_allrefs(struct net_device *dev) | |||
2886 | linkwatch_run_queue(); | 2894 | linkwatch_run_queue(); |
2887 | } | 2895 | } |
2888 | 2896 | ||
2889 | rtnl_shunlock(); | 2897 | __rtnl_unlock(); |
2890 | 2898 | ||
2891 | rebroadcast_time = jiffies; | 2899 | rebroadcast_time = jiffies; |
2892 | } | 2900 | } |
@@ -2924,7 +2932,7 @@ static void netdev_wait_allrefs(struct net_device *dev) | |||
2924 | * 2) Since we run with the RTNL semaphore not held, we can sleep | 2932 | * 2) Since we run with the RTNL semaphore not held, we can sleep |
2925 | * safely in order to wait for the netdev refcnt to drop to zero. | 2933 | * safely in order to wait for the netdev refcnt to drop to zero. |
2926 | */ | 2934 | */ |
2927 | static DECLARE_MUTEX(net_todo_run_mutex); | 2935 | static DEFINE_MUTEX(net_todo_run_mutex); |
2928 | void netdev_run_todo(void) | 2936 | void netdev_run_todo(void) |
2929 | { | 2937 | { |
2930 | struct list_head list = LIST_HEAD_INIT(list); | 2938 | struct list_head list = LIST_HEAD_INIT(list); |
@@ -2932,7 +2940,7 @@ void netdev_run_todo(void) | |||
2932 | 2940 | ||
2933 | 2941 | ||
2934 | /* Need to guard against multiple cpu's getting out of order. */ | 2942 | /* Need to guard against multiple cpu's getting out of order. */ |
2935 | down(&net_todo_run_mutex); | 2943 | mutex_lock(&net_todo_run_mutex); |
2936 | 2944 | ||
2937 | /* Not safe to do outside the semaphore. We must not return | 2945 | /* Not safe to do outside the semaphore. We must not return |
2938 | * until all unregister events invoked by the local processor | 2946 | * until all unregister events invoked by the local processor |
@@ -2989,7 +2997,7 @@ void netdev_run_todo(void) | |||
2989 | } | 2997 | } |
2990 | 2998 | ||
2991 | out: | 2999 | out: |
2992 | up(&net_todo_run_mutex); | 3000 | mutex_unlock(&net_todo_run_mutex); |
2993 | } | 3001 | } |
2994 | 3002 | ||
2995 | /** | 3003 | /** |
diff --git a/net/core/flow.c b/net/core/flow.c index c4f25385029f..55789f832eda 100644 --- a/net/core/flow.c +++ b/net/core/flow.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/notifier.h> | 20 | #include <linux/notifier.h> |
21 | #include <linux/cpu.h> | 21 | #include <linux/cpu.h> |
22 | #include <linux/cpumask.h> | 22 | #include <linux/cpumask.h> |
23 | #include <linux/mutex.h> | ||
23 | #include <net/flow.h> | 24 | #include <net/flow.h> |
24 | #include <asm/atomic.h> | 25 | #include <asm/atomic.h> |
25 | #include <asm/semaphore.h> | 26 | #include <asm/semaphore.h> |
@@ -287,11 +288,11 @@ static void flow_cache_flush_per_cpu(void *data) | |||
287 | void flow_cache_flush(void) | 288 | void flow_cache_flush(void) |
288 | { | 289 | { |
289 | struct flow_flush_info info; | 290 | struct flow_flush_info info; |
290 | static DECLARE_MUTEX(flow_flush_sem); | 291 | static DEFINE_MUTEX(flow_flush_sem); |
291 | 292 | ||
292 | /* Don't want cpus going down or up during this. */ | 293 | /* Don't want cpus going down or up during this. */ |
293 | lock_cpu_hotplug(); | 294 | lock_cpu_hotplug(); |
294 | down(&flow_flush_sem); | 295 | mutex_lock(&flow_flush_sem); |
295 | atomic_set(&info.cpuleft, num_online_cpus()); | 296 | atomic_set(&info.cpuleft, num_online_cpus()); |
296 | init_completion(&info.completion); | 297 | init_completion(&info.completion); |
297 | 298 | ||
@@ -301,7 +302,7 @@ void flow_cache_flush(void) | |||
301 | local_bh_enable(); | 302 | local_bh_enable(); |
302 | 303 | ||
303 | wait_for_completion(&info.completion); | 304 | wait_for_completion(&info.completion); |
304 | up(&flow_flush_sem); | 305 | mutex_unlock(&flow_flush_sem); |
305 | unlock_cpu_hotplug(); | 306 | unlock_cpu_hotplug(); |
306 | } | 307 | } |
307 | 308 | ||
diff --git a/net/core/link_watch.c b/net/core/link_watch.c index d43d1201275c..341de44c7ed1 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c | |||
@@ -49,6 +49,45 @@ struct lw_event { | |||
49 | /* Avoid kmalloc() for most systems */ | 49 | /* Avoid kmalloc() for most systems */ |
50 | static struct lw_event singleevent; | 50 | static struct lw_event singleevent; |
51 | 51 | ||
52 | static unsigned char default_operstate(const struct net_device *dev) | ||
53 | { | ||
54 | if (!netif_carrier_ok(dev)) | ||
55 | return (dev->ifindex != dev->iflink ? | ||
56 | IF_OPER_LOWERLAYERDOWN : IF_OPER_DOWN); | ||
57 | |||
58 | if (netif_dormant(dev)) | ||
59 | return IF_OPER_DORMANT; | ||
60 | |||
61 | return IF_OPER_UP; | ||
62 | } | ||
63 | |||
64 | |||
65 | static void rfc2863_policy(struct net_device *dev) | ||
66 | { | ||
67 | unsigned char operstate = default_operstate(dev); | ||
68 | |||
69 | if (operstate == dev->operstate) | ||
70 | return; | ||
71 | |||
72 | write_lock_bh(&dev_base_lock); | ||
73 | |||
74 | switch(dev->link_mode) { | ||
75 | case IF_LINK_MODE_DORMANT: | ||
76 | if (operstate == IF_OPER_UP) | ||
77 | operstate = IF_OPER_DORMANT; | ||
78 | break; | ||
79 | |||
80 | case IF_LINK_MODE_DEFAULT: | ||
81 | default: | ||
82 | break; | ||
83 | }; | ||
84 | |||
85 | dev->operstate = operstate; | ||
86 | |||
87 | write_unlock_bh(&dev_base_lock); | ||
88 | } | ||
89 | |||
90 | |||
52 | /* Must be called with the rtnl semaphore held */ | 91 | /* Must be called with the rtnl semaphore held */ |
53 | void linkwatch_run_queue(void) | 92 | void linkwatch_run_queue(void) |
54 | { | 93 | { |
@@ -74,6 +113,7 @@ void linkwatch_run_queue(void) | |||
74 | */ | 113 | */ |
75 | clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); | 114 | clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); |
76 | 115 | ||
116 | rfc2863_policy(dev); | ||
77 | if (dev->flags & IFF_UP) { | 117 | if (dev->flags & IFF_UP) { |
78 | if (netif_carrier_ok(dev)) { | 118 | if (netif_carrier_ok(dev)) { |
79 | WARN_ON(dev->qdisc_sleeping == &noop_qdisc); | 119 | WARN_ON(dev->qdisc_sleeping == &noop_qdisc); |
@@ -99,9 +139,9 @@ static void linkwatch_event(void *dummy) | |||
99 | linkwatch_nextevent = jiffies + HZ; | 139 | linkwatch_nextevent = jiffies + HZ; |
100 | clear_bit(LW_RUNNING, &linkwatch_flags); | 140 | clear_bit(LW_RUNNING, &linkwatch_flags); |
101 | 141 | ||
102 | rtnl_shlock(); | 142 | rtnl_lock(); |
103 | linkwatch_run_queue(); | 143 | linkwatch_run_queue(); |
104 | rtnl_shunlock(); | 144 | rtnl_unlock(); |
105 | } | 145 | } |
106 | 146 | ||
107 | 147 | ||
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index e68700f950a5..0c8666872d10 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -586,8 +586,8 @@ void neigh_destroy(struct neighbour *neigh) | |||
586 | kfree(hh); | 586 | kfree(hh); |
587 | } | 587 | } |
588 | 588 | ||
589 | if (neigh->ops && neigh->ops->destructor) | 589 | if (neigh->parms->neigh_destructor) |
590 | (neigh->ops->destructor)(neigh); | 590 | (neigh->parms->neigh_destructor)(neigh); |
591 | 591 | ||
592 | skb_queue_purge(&neigh->arp_queue); | 592 | skb_queue_purge(&neigh->arp_queue); |
593 | 593 | ||
@@ -750,11 +750,13 @@ static void neigh_timer_handler(unsigned long arg) | |||
750 | neigh->used + neigh->parms->delay_probe_time)) { | 750 | neigh->used + neigh->parms->delay_probe_time)) { |
751 | NEIGH_PRINTK2("neigh %p is delayed.\n", neigh); | 751 | NEIGH_PRINTK2("neigh %p is delayed.\n", neigh); |
752 | neigh->nud_state = NUD_DELAY; | 752 | neigh->nud_state = NUD_DELAY; |
753 | neigh->updated = jiffies; | ||
753 | neigh_suspect(neigh); | 754 | neigh_suspect(neigh); |
754 | next = now + neigh->parms->delay_probe_time; | 755 | next = now + neigh->parms->delay_probe_time; |
755 | } else { | 756 | } else { |
756 | NEIGH_PRINTK2("neigh %p is suspected.\n", neigh); | 757 | NEIGH_PRINTK2("neigh %p is suspected.\n", neigh); |
757 | neigh->nud_state = NUD_STALE; | 758 | neigh->nud_state = NUD_STALE; |
759 | neigh->updated = jiffies; | ||
758 | neigh_suspect(neigh); | 760 | neigh_suspect(neigh); |
759 | } | 761 | } |
760 | } else if (state & NUD_DELAY) { | 762 | } else if (state & NUD_DELAY) { |
@@ -762,11 +764,13 @@ static void neigh_timer_handler(unsigned long arg) | |||
762 | neigh->confirmed + neigh->parms->delay_probe_time)) { | 764 | neigh->confirmed + neigh->parms->delay_probe_time)) { |
763 | NEIGH_PRINTK2("neigh %p is now reachable.\n", neigh); | 765 | NEIGH_PRINTK2("neigh %p is now reachable.\n", neigh); |
764 | neigh->nud_state = NUD_REACHABLE; | 766 | neigh->nud_state = NUD_REACHABLE; |
767 | neigh->updated = jiffies; | ||
765 | neigh_connect(neigh); | 768 | neigh_connect(neigh); |
766 | next = neigh->confirmed + neigh->parms->reachable_time; | 769 | next = neigh->confirmed + neigh->parms->reachable_time; |
767 | } else { | 770 | } else { |
768 | NEIGH_PRINTK2("neigh %p is probed.\n", neigh); | 771 | NEIGH_PRINTK2("neigh %p is probed.\n", neigh); |
769 | neigh->nud_state = NUD_PROBE; | 772 | neigh->nud_state = NUD_PROBE; |
773 | neigh->updated = jiffies; | ||
770 | atomic_set(&neigh->probes, 0); | 774 | atomic_set(&neigh->probes, 0); |
771 | next = now + neigh->parms->retrans_time; | 775 | next = now + neigh->parms->retrans_time; |
772 | } | 776 | } |
@@ -780,6 +784,7 @@ static void neigh_timer_handler(unsigned long arg) | |||
780 | struct sk_buff *skb; | 784 | struct sk_buff *skb; |
781 | 785 | ||
782 | neigh->nud_state = NUD_FAILED; | 786 | neigh->nud_state = NUD_FAILED; |
787 | neigh->updated = jiffies; | ||
783 | notify = 1; | 788 | notify = 1; |
784 | NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); | 789 | NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); |
785 | NEIGH_PRINTK2("neigh %p is failed.\n", neigh); | 790 | NEIGH_PRINTK2("neigh %p is failed.\n", neigh); |
@@ -843,10 +848,12 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) | |||
843 | if (neigh->parms->mcast_probes + neigh->parms->app_probes) { | 848 | if (neigh->parms->mcast_probes + neigh->parms->app_probes) { |
844 | atomic_set(&neigh->probes, neigh->parms->ucast_probes); | 849 | atomic_set(&neigh->probes, neigh->parms->ucast_probes); |
845 | neigh->nud_state = NUD_INCOMPLETE; | 850 | neigh->nud_state = NUD_INCOMPLETE; |
851 | neigh->updated = jiffies; | ||
846 | neigh_hold(neigh); | 852 | neigh_hold(neigh); |
847 | neigh_add_timer(neigh, now + 1); | 853 | neigh_add_timer(neigh, now + 1); |
848 | } else { | 854 | } else { |
849 | neigh->nud_state = NUD_FAILED; | 855 | neigh->nud_state = NUD_FAILED; |
856 | neigh->updated = jiffies; | ||
850 | write_unlock_bh(&neigh->lock); | 857 | write_unlock_bh(&neigh->lock); |
851 | 858 | ||
852 | if (skb) | 859 | if (skb) |
@@ -857,6 +864,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) | |||
857 | NEIGH_PRINTK2("neigh %p is delayed.\n", neigh); | 864 | NEIGH_PRINTK2("neigh %p is delayed.\n", neigh); |
858 | neigh_hold(neigh); | 865 | neigh_hold(neigh); |
859 | neigh->nud_state = NUD_DELAY; | 866 | neigh->nud_state = NUD_DELAY; |
867 | neigh->updated = jiffies; | ||
860 | neigh_add_timer(neigh, | 868 | neigh_add_timer(neigh, |
861 | jiffies + neigh->parms->delay_probe_time); | 869 | jiffies + neigh->parms->delay_probe_time); |
862 | } | 870 | } |
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index e8b2acbc8ea2..21b68464cabb 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c | |||
@@ -91,6 +91,7 @@ NETDEVICE_SHOW(iflink, fmt_dec); | |||
91 | NETDEVICE_SHOW(ifindex, fmt_dec); | 91 | NETDEVICE_SHOW(ifindex, fmt_dec); |
92 | NETDEVICE_SHOW(features, fmt_long_hex); | 92 | NETDEVICE_SHOW(features, fmt_long_hex); |
93 | NETDEVICE_SHOW(type, fmt_dec); | 93 | NETDEVICE_SHOW(type, fmt_dec); |
94 | NETDEVICE_SHOW(link_mode, fmt_dec); | ||
94 | 95 | ||
95 | /* use same locking rules as GIFHWADDR ioctl's */ | 96 | /* use same locking rules as GIFHWADDR ioctl's */ |
96 | static ssize_t format_addr(char *buf, const unsigned char *addr, int len) | 97 | static ssize_t format_addr(char *buf, const unsigned char *addr, int len) |
@@ -133,6 +134,43 @@ static ssize_t show_carrier(struct class_device *dev, char *buf) | |||
133 | return -EINVAL; | 134 | return -EINVAL; |
134 | } | 135 | } |
135 | 136 | ||
137 | static ssize_t show_dormant(struct class_device *dev, char *buf) | ||
138 | { | ||
139 | struct net_device *netdev = to_net_dev(dev); | ||
140 | |||
141 | if (netif_running(netdev)) | ||
142 | return sprintf(buf, fmt_dec, !!netif_dormant(netdev)); | ||
143 | |||
144 | return -EINVAL; | ||
145 | } | ||
146 | |||
147 | static const char *operstates[] = { | ||
148 | "unknown", | ||
149 | "notpresent", /* currently unused */ | ||
150 | "down", | ||
151 | "lowerlayerdown", | ||
152 | "testing", /* currently unused */ | ||
153 | "dormant", | ||
154 | "up" | ||
155 | }; | ||
156 | |||
157 | static ssize_t show_operstate(struct class_device *dev, char *buf) | ||
158 | { | ||
159 | const struct net_device *netdev = to_net_dev(dev); | ||
160 | unsigned char operstate; | ||
161 | |||
162 | read_lock(&dev_base_lock); | ||
163 | operstate = netdev->operstate; | ||
164 | if (!netif_running(netdev)) | ||
165 | operstate = IF_OPER_DOWN; | ||
166 | read_unlock(&dev_base_lock); | ||
167 | |||
168 | if (operstate >= sizeof(operstates)) | ||
169 | return -EINVAL; /* should not happen */ | ||
170 | |||
171 | return sprintf(buf, "%s\n", operstates[operstate]); | ||
172 | } | ||
173 | |||
136 | /* read-write attributes */ | 174 | /* read-write attributes */ |
137 | NETDEVICE_SHOW(mtu, fmt_dec); | 175 | NETDEVICE_SHOW(mtu, fmt_dec); |
138 | 176 | ||
@@ -190,9 +228,12 @@ static struct class_device_attribute net_class_attributes[] = { | |||
190 | __ATTR(ifindex, S_IRUGO, show_ifindex, NULL), | 228 | __ATTR(ifindex, S_IRUGO, show_ifindex, NULL), |
191 | __ATTR(features, S_IRUGO, show_features, NULL), | 229 | __ATTR(features, S_IRUGO, show_features, NULL), |
192 | __ATTR(type, S_IRUGO, show_type, NULL), | 230 | __ATTR(type, S_IRUGO, show_type, NULL), |
231 | __ATTR(link_mode, S_IRUGO, show_link_mode, NULL), | ||
193 | __ATTR(address, S_IRUGO, show_address, NULL), | 232 | __ATTR(address, S_IRUGO, show_address, NULL), |
194 | __ATTR(broadcast, S_IRUGO, show_broadcast, NULL), | 233 | __ATTR(broadcast, S_IRUGO, show_broadcast, NULL), |
195 | __ATTR(carrier, S_IRUGO, show_carrier, NULL), | 234 | __ATTR(carrier, S_IRUGO, show_carrier, NULL), |
235 | __ATTR(dormant, S_IRUGO, show_dormant, NULL), | ||
236 | __ATTR(operstate, S_IRUGO, show_operstate, NULL), | ||
196 | __ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu), | 237 | __ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu), |
197 | __ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags), | 238 | __ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags), |
198 | __ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len, | 239 | __ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len, |
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index ea51f8d02eb8..e8e05cebd95a 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
@@ -669,14 +669,14 @@ int netpoll_setup(struct netpoll *np) | |||
669 | printk(KERN_INFO "%s: device %s not up yet, forcing it\n", | 669 | printk(KERN_INFO "%s: device %s not up yet, forcing it\n", |
670 | np->name, np->dev_name); | 670 | np->name, np->dev_name); |
671 | 671 | ||
672 | rtnl_shlock(); | 672 | rtnl_lock(); |
673 | if (dev_change_flags(ndev, ndev->flags | IFF_UP) < 0) { | 673 | if (dev_change_flags(ndev, ndev->flags | IFF_UP) < 0) { |
674 | printk(KERN_ERR "%s: failed to open %s\n", | 674 | printk(KERN_ERR "%s: failed to open %s\n", |
675 | np->name, np->dev_name); | 675 | np->name, np->dev_name); |
676 | rtnl_shunlock(); | 676 | rtnl_unlock(); |
677 | goto release; | 677 | goto release; |
678 | } | 678 | } |
679 | rtnl_shunlock(); | 679 | rtnl_unlock(); |
680 | 680 | ||
681 | atleast = jiffies + HZ/10; | 681 | atleast = jiffies + HZ/10; |
682 | atmost = jiffies + 4*HZ; | 682 | atmost = jiffies + 4*HZ; |
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index da16f8fd1494..c23e9c06ee23 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -106,6 +106,9 @@ | |||
106 | * | 106 | * |
107 | * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com> | 107 | * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com> |
108 | * 050103 | 108 | * 050103 |
109 | * | ||
110 | * MPLS support by Steven Whitehouse <steve@chygwyn.com> | ||
111 | * | ||
109 | */ | 112 | */ |
110 | #include <linux/sys.h> | 113 | #include <linux/sys.h> |
111 | #include <linux/types.h> | 114 | #include <linux/types.h> |
@@ -113,6 +116,7 @@ | |||
113 | #include <linux/moduleparam.h> | 116 | #include <linux/moduleparam.h> |
114 | #include <linux/kernel.h> | 117 | #include <linux/kernel.h> |
115 | #include <linux/smp_lock.h> | 118 | #include <linux/smp_lock.h> |
119 | #include <linux/mutex.h> | ||
116 | #include <linux/sched.h> | 120 | #include <linux/sched.h> |
117 | #include <linux/slab.h> | 121 | #include <linux/slab.h> |
118 | #include <linux/vmalloc.h> | 122 | #include <linux/vmalloc.h> |
@@ -125,6 +129,7 @@ | |||
125 | #include <linux/capability.h> | 129 | #include <linux/capability.h> |
126 | #include <linux/delay.h> | 130 | #include <linux/delay.h> |
127 | #include <linux/timer.h> | 131 | #include <linux/timer.h> |
132 | #include <linux/list.h> | ||
128 | #include <linux/init.h> | 133 | #include <linux/init.h> |
129 | #include <linux/skbuff.h> | 134 | #include <linux/skbuff.h> |
130 | #include <linux/netdevice.h> | 135 | #include <linux/netdevice.h> |
@@ -149,38 +154,37 @@ | |||
149 | #include <asm/io.h> | 154 | #include <asm/io.h> |
150 | #include <asm/dma.h> | 155 | #include <asm/dma.h> |
151 | #include <asm/uaccess.h> | 156 | #include <asm/uaccess.h> |
152 | #include <asm/div64.h> /* do_div */ | 157 | #include <asm/div64.h> /* do_div */ |
153 | #include <asm/timex.h> | 158 | #include <asm/timex.h> |
154 | 159 | ||
155 | 160 | #define VERSION "pktgen v2.67: Packet Generator for packet performance testing.\n" | |
156 | #define VERSION "pktgen v2.63: Packet Generator for packet performance testing.\n" | ||
157 | 161 | ||
158 | /* #define PG_DEBUG(a) a */ | 162 | /* #define PG_DEBUG(a) a */ |
159 | #define PG_DEBUG(a) | 163 | #define PG_DEBUG(a) |
160 | 164 | ||
161 | /* The buckets are exponential in 'width' */ | 165 | /* The buckets are exponential in 'width' */ |
162 | #define LAT_BUCKETS_MAX 32 | 166 | #define LAT_BUCKETS_MAX 32 |
163 | #define IP_NAME_SZ 32 | 167 | #define IP_NAME_SZ 32 |
168 | #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */ | ||
169 | #define MPLS_STACK_BOTTOM __constant_htonl(0x00000100) | ||
164 | 170 | ||
165 | /* Device flag bits */ | 171 | /* Device flag bits */ |
166 | #define F_IPSRC_RND (1<<0) /* IP-Src Random */ | 172 | #define F_IPSRC_RND (1<<0) /* IP-Src Random */ |
167 | #define F_IPDST_RND (1<<1) /* IP-Dst Random */ | 173 | #define F_IPDST_RND (1<<1) /* IP-Dst Random */ |
168 | #define F_UDPSRC_RND (1<<2) /* UDP-Src Random */ | 174 | #define F_UDPSRC_RND (1<<2) /* UDP-Src Random */ |
169 | #define F_UDPDST_RND (1<<3) /* UDP-Dst Random */ | 175 | #define F_UDPDST_RND (1<<3) /* UDP-Dst Random */ |
170 | #define F_MACSRC_RND (1<<4) /* MAC-Src Random */ | 176 | #define F_MACSRC_RND (1<<4) /* MAC-Src Random */ |
171 | #define F_MACDST_RND (1<<5) /* MAC-Dst Random */ | 177 | #define F_MACDST_RND (1<<5) /* MAC-Dst Random */ |
172 | #define F_TXSIZE_RND (1<<6) /* Transmit size is random */ | 178 | #define F_TXSIZE_RND (1<<6) /* Transmit size is random */ |
173 | #define F_IPV6 (1<<7) /* Interface in IPV6 Mode */ | 179 | #define F_IPV6 (1<<7) /* Interface in IPV6 Mode */ |
180 | #define F_MPLS_RND (1<<8) /* Random MPLS labels */ | ||
174 | 181 | ||
175 | /* Thread control flag bits */ | 182 | /* Thread control flag bits */ |
176 | #define T_TERMINATE (1<<0) | 183 | #define T_TERMINATE (1<<0) |
177 | #define T_STOP (1<<1) /* Stop run */ | 184 | #define T_STOP (1<<1) /* Stop run */ |
178 | #define T_RUN (1<<2) /* Start run */ | 185 | #define T_RUN (1<<2) /* Start run */ |
179 | #define T_REMDEV (1<<3) /* Remove all devs */ | 186 | #define T_REMDEVALL (1<<3) /* Remove all devs */ |
180 | 187 | #define T_REMDEV (1<<4) /* Remove one dev */ | |
181 | /* Locks */ | ||
182 | #define thread_lock() down(&pktgen_sem) | ||
183 | #define thread_unlock() up(&pktgen_sem) | ||
184 | 188 | ||
185 | /* If lock -- can be removed after some work */ | 189 | /* If lock -- can be removed after some work */ |
186 | #define if_lock(t) spin_lock(&(t->if_lock)); | 190 | #define if_lock(t) spin_lock(&(t->if_lock)); |
@@ -194,10 +198,9 @@ static struct proc_dir_entry *pg_proc_dir = NULL; | |||
194 | 198 | ||
195 | #define MAX_CFLOWS 65536 | 199 | #define MAX_CFLOWS 65536 |
196 | 200 | ||
197 | struct flow_state | 201 | struct flow_state { |
198 | { | 202 | __u32 cur_daddr; |
199 | __u32 cur_daddr; | 203 | int count; |
200 | int count; | ||
201 | }; | 204 | }; |
202 | 205 | ||
203 | struct pktgen_dev { | 206 | struct pktgen_dev { |
@@ -206,141 +209,148 @@ struct pktgen_dev { | |||
206 | * Try to keep frequent/infrequent used vars. separated. | 209 | * Try to keep frequent/infrequent used vars. separated. |
207 | */ | 210 | */ |
208 | 211 | ||
209 | char ifname[IFNAMSIZ]; | 212 | char ifname[IFNAMSIZ]; |
210 | char result[512]; | 213 | char result[512]; |
211 | 214 | ||
212 | struct pktgen_thread* pg_thread; /* the owner */ | 215 | struct pktgen_thread *pg_thread; /* the owner */ |
213 | struct pktgen_dev *next; /* Used for chaining in the thread's run-queue */ | 216 | struct list_head list; /* Used for chaining in the thread's run-queue */ |
214 | 217 | ||
215 | int running; /* if this changes to false, the test will stop */ | 218 | int running; /* if this changes to false, the test will stop */ |
216 | 219 | ||
217 | /* If min != max, then we will either do a linear iteration, or | 220 | /* If min != max, then we will either do a linear iteration, or |
218 | * we will do a random selection from within the range. | 221 | * we will do a random selection from within the range. |
219 | */ | 222 | */ |
220 | __u32 flags; | 223 | __u32 flags; |
221 | 224 | int removal_mark; /* non-zero => the device is marked for | |
222 | int min_pkt_size; /* = ETH_ZLEN; */ | 225 | * removal by worker thread */ |
223 | int max_pkt_size; /* = ETH_ZLEN; */ | 226 | |
224 | int nfrags; | 227 | int min_pkt_size; /* = ETH_ZLEN; */ |
225 | __u32 delay_us; /* Default delay */ | 228 | int max_pkt_size; /* = ETH_ZLEN; */ |
226 | __u32 delay_ns; | 229 | int nfrags; |
227 | __u64 count; /* Default No packets to send */ | 230 | __u32 delay_us; /* Default delay */ |
228 | __u64 sofar; /* How many pkts we've sent so far */ | 231 | __u32 delay_ns; |
229 | __u64 tx_bytes; /* How many bytes we've transmitted */ | 232 | __u64 count; /* Default No packets to send */ |
230 | __u64 errors; /* Errors when trying to transmit, pkts will be re-sent */ | 233 | __u64 sofar; /* How many pkts we've sent so far */ |
231 | 234 | __u64 tx_bytes; /* How many bytes we've transmitted */ | |
232 | /* runtime counters relating to clone_skb */ | 235 | __u64 errors; /* Errors when trying to transmit, pkts will be re-sent */ |
233 | __u64 next_tx_us; /* timestamp of when to tx next */ | 236 | |
234 | __u32 next_tx_ns; | 237 | /* runtime counters relating to clone_skb */ |
235 | 238 | __u64 next_tx_us; /* timestamp of when to tx next */ | |
236 | __u64 allocated_skbs; | 239 | __u32 next_tx_ns; |
237 | __u32 clone_count; | 240 | |
238 | int last_ok; /* Was last skb sent? | 241 | __u64 allocated_skbs; |
239 | * Or a failed transmit of some sort? This will keep | 242 | __u32 clone_count; |
240 | * sequence numbers in order, for example. | 243 | int last_ok; /* Was last skb sent? |
241 | */ | 244 | * Or a failed transmit of some sort? This will keep |
242 | __u64 started_at; /* micro-seconds */ | 245 | * sequence numbers in order, for example. |
243 | __u64 stopped_at; /* micro-seconds */ | 246 | */ |
244 | __u64 idle_acc; /* micro-seconds */ | 247 | __u64 started_at; /* micro-seconds */ |
245 | __u32 seq_num; | 248 | __u64 stopped_at; /* micro-seconds */ |
246 | 249 | __u64 idle_acc; /* micro-seconds */ | |
247 | int clone_skb; /* Use multiple SKBs during packet gen. If this number | 250 | __u32 seq_num; |
248 | * is greater than 1, then that many copies of the same | 251 | |
249 | * packet will be sent before a new packet is allocated. | 252 | int clone_skb; /* Use multiple SKBs during packet gen. If this number |
250 | * For instance, if you want to send 1024 identical packets | 253 | * is greater than 1, then that many copies of the same |
251 | * before creating a new packet, set clone_skb to 1024. | 254 | * packet will be sent before a new packet is allocated. |
252 | */ | 255 | * For instance, if you want to send 1024 identical packets |
253 | 256 | * before creating a new packet, set clone_skb to 1024. | |
254 | char dst_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ | 257 | */ |
255 | char dst_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ | 258 | |
256 | char src_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ | 259 | char dst_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ |
257 | char src_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ | 260 | char dst_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ |
258 | 261 | char src_min[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ | |
259 | struct in6_addr in6_saddr; | 262 | char src_max[IP_NAME_SZ]; /* IP, ie 1.2.3.4 */ |
260 | struct in6_addr in6_daddr; | 263 | |
261 | struct in6_addr cur_in6_daddr; | 264 | struct in6_addr in6_saddr; |
262 | struct in6_addr cur_in6_saddr; | 265 | struct in6_addr in6_daddr; |
266 | struct in6_addr cur_in6_daddr; | ||
267 | struct in6_addr cur_in6_saddr; | ||
263 | /* For ranges */ | 268 | /* For ranges */ |
264 | struct in6_addr min_in6_daddr; | 269 | struct in6_addr min_in6_daddr; |
265 | struct in6_addr max_in6_daddr; | 270 | struct in6_addr max_in6_daddr; |
266 | struct in6_addr min_in6_saddr; | 271 | struct in6_addr min_in6_saddr; |
267 | struct in6_addr max_in6_saddr; | 272 | struct in6_addr max_in6_saddr; |
268 | 273 | ||
269 | /* If we're doing ranges, random or incremental, then this | 274 | /* If we're doing ranges, random or incremental, then this |
270 | * defines the min/max for those ranges. | 275 | * defines the min/max for those ranges. |
271 | */ | 276 | */ |
272 | __u32 saddr_min; /* inclusive, source IP address */ | 277 | __u32 saddr_min; /* inclusive, source IP address */ |
273 | __u32 saddr_max; /* exclusive, source IP address */ | 278 | __u32 saddr_max; /* exclusive, source IP address */ |
274 | __u32 daddr_min; /* inclusive, dest IP address */ | 279 | __u32 daddr_min; /* inclusive, dest IP address */ |
275 | __u32 daddr_max; /* exclusive, dest IP address */ | 280 | __u32 daddr_max; /* exclusive, dest IP address */ |
276 | 281 | ||
277 | __u16 udp_src_min; /* inclusive, source UDP port */ | 282 | __u16 udp_src_min; /* inclusive, source UDP port */ |
278 | __u16 udp_src_max; /* exclusive, source UDP port */ | 283 | __u16 udp_src_max; /* exclusive, source UDP port */ |
279 | __u16 udp_dst_min; /* inclusive, dest UDP port */ | 284 | __u16 udp_dst_min; /* inclusive, dest UDP port */ |
280 | __u16 udp_dst_max; /* exclusive, dest UDP port */ | 285 | __u16 udp_dst_max; /* exclusive, dest UDP port */ |
281 | 286 | ||
282 | __u32 src_mac_count; /* How many MACs to iterate through */ | 287 | /* MPLS */ |
283 | __u32 dst_mac_count; /* How many MACs to iterate through */ | 288 | unsigned nr_labels; /* Depth of stack, 0 = no MPLS */ |
284 | 289 | __be32 labels[MAX_MPLS_LABELS]; | |
285 | unsigned char dst_mac[ETH_ALEN]; | 290 | |
286 | unsigned char src_mac[ETH_ALEN]; | 291 | __u32 src_mac_count; /* How many MACs to iterate through */ |
287 | 292 | __u32 dst_mac_count; /* How many MACs to iterate through */ | |
288 | __u32 cur_dst_mac_offset; | 293 | |
289 | __u32 cur_src_mac_offset; | 294 | unsigned char dst_mac[ETH_ALEN]; |
290 | __u32 cur_saddr; | 295 | unsigned char src_mac[ETH_ALEN]; |
291 | __u32 cur_daddr; | 296 | |
292 | __u16 cur_udp_dst; | 297 | __u32 cur_dst_mac_offset; |
293 | __u16 cur_udp_src; | 298 | __u32 cur_src_mac_offset; |
294 | __u32 cur_pkt_size; | 299 | __u32 cur_saddr; |
295 | 300 | __u32 cur_daddr; | |
296 | __u8 hh[14]; | 301 | __u16 cur_udp_dst; |
297 | /* = { | 302 | __u16 cur_udp_src; |
298 | 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, | 303 | __u32 cur_pkt_size; |
299 | 304 | ||
300 | We fill in SRC address later | 305 | __u8 hh[14]; |
301 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 306 | /* = { |
302 | 0x08, 0x00 | 307 | 0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, |
303 | }; | 308 | |
304 | */ | 309 | We fill in SRC address later |
305 | __u16 pad; /* pad out the hh struct to an even 16 bytes */ | 310 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
306 | 311 | 0x08, 0x00 | |
307 | struct sk_buff* skb; /* skb we are to transmit next, mainly used for when we | 312 | }; |
308 | * are transmitting the same one multiple times | 313 | */ |
309 | */ | 314 | __u16 pad; /* pad out the hh struct to an even 16 bytes */ |
310 | struct net_device* odev; /* The out-going device. Note that the device should | 315 | |
311 | * have it's pg_info pointer pointing back to this | 316 | struct sk_buff *skb; /* skb we are to transmit next, mainly used for when we |
312 | * device. This will be set when the user specifies | 317 | * are transmitting the same one multiple times |
313 | * the out-going device name (not when the inject is | 318 | */ |
314 | * started as it used to do.) | 319 | struct net_device *odev; /* The out-going device. Note that the device should |
315 | */ | 320 | * have it's pg_info pointer pointing back to this |
321 | * device. This will be set when the user specifies | ||
322 | * the out-going device name (not when the inject is | ||
323 | * started as it used to do.) | ||
324 | */ | ||
316 | struct flow_state *flows; | 325 | struct flow_state *flows; |
317 | unsigned cflows; /* Concurrent flows (config) */ | 326 | unsigned cflows; /* Concurrent flows (config) */ |
318 | unsigned lflow; /* Flow length (config) */ | 327 | unsigned lflow; /* Flow length (config) */ |
319 | unsigned nflows; /* accumulated flows (stats) */ | 328 | unsigned nflows; /* accumulated flows (stats) */ |
320 | }; | 329 | }; |
321 | 330 | ||
322 | struct pktgen_hdr { | 331 | struct pktgen_hdr { |
323 | __u32 pgh_magic; | 332 | __u32 pgh_magic; |
324 | __u32 seq_num; | 333 | __u32 seq_num; |
325 | __u32 tv_sec; | 334 | __u32 tv_sec; |
326 | __u32 tv_usec; | 335 | __u32 tv_usec; |
327 | }; | 336 | }; |
328 | 337 | ||
329 | struct pktgen_thread { | 338 | struct pktgen_thread { |
330 | spinlock_t if_lock; | 339 | spinlock_t if_lock; |
331 | struct pktgen_dev *if_list; /* All device here */ | 340 | struct list_head if_list; /* All device here */ |
332 | struct pktgen_thread* next; | 341 | struct list_head th_list; |
333 | char name[32]; | 342 | int removed; |
334 | char result[512]; | 343 | char name[32]; |
335 | u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */ | 344 | char result[512]; |
336 | 345 | u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */ | |
337 | /* Field for thread to receive "posted" events terminate, stop ifs etc.*/ | 346 | |
338 | 347 | /* Field for thread to receive "posted" events terminate, stop ifs etc. */ | |
339 | u32 control; | 348 | |
349 | u32 control; | ||
340 | int pid; | 350 | int pid; |
341 | int cpu; | 351 | int cpu; |
342 | 352 | ||
343 | wait_queue_head_t queue; | 353 | wait_queue_head_t queue; |
344 | }; | 354 | }; |
345 | 355 | ||
346 | #define REMOVE 1 | 356 | #define REMOVE 1 |
@@ -364,77 +374,76 @@ struct pktgen_thread { | |||
364 | */ | 374 | */ |
365 | static inline s64 divremdi3(s64 x, s64 y, int type) | 375 | static inline s64 divremdi3(s64 x, s64 y, int type) |
366 | { | 376 | { |
367 | u64 a = (x < 0) ? -x : x; | 377 | u64 a = (x < 0) ? -x : x; |
368 | u64 b = (y < 0) ? -y : y; | 378 | u64 b = (y < 0) ? -y : y; |
369 | u64 res = 0, d = 1; | 379 | u64 res = 0, d = 1; |
370 | 380 | ||
371 | if (b > 0) { | 381 | if (b > 0) { |
372 | while (b < a) { | 382 | while (b < a) { |
373 | b <<= 1; | 383 | b <<= 1; |
374 | d <<= 1; | 384 | d <<= 1; |
375 | } | 385 | } |
376 | } | 386 | } |
377 | 387 | ||
378 | do { | 388 | do { |
379 | if ( a >= b ) { | 389 | if (a >= b) { |
380 | a -= b; | 390 | a -= b; |
381 | res += d; | 391 | res += d; |
382 | } | 392 | } |
383 | b >>= 1; | 393 | b >>= 1; |
384 | d >>= 1; | 394 | d >>= 1; |
385 | } | 395 | } |
386 | while (d); | 396 | while (d); |
387 | 397 | ||
388 | if (PG_DIV == type) { | 398 | if (PG_DIV == type) { |
389 | return (((x ^ y) & (1ll<<63)) == 0) ? res : -(s64)res; | 399 | return (((x ^ y) & (1ll << 63)) == 0) ? res : -(s64) res; |
390 | } | 400 | } else { |
391 | else { | 401 | return ((x & (1ll << 63)) == 0) ? a : -(s64) a; |
392 | return ((x & (1ll<<63)) == 0) ? a : -(s64)a; | 402 | } |
393 | } | ||
394 | } | 403 | } |
395 | 404 | ||
396 | /* End of hacks to deal with 64-bit math on x86 */ | 405 | /* End of hacks to deal with 64-bit math on x86 */ |
397 | 406 | ||
398 | /** Convert to milliseconds */ | 407 | /** Convert to milliseconds */ |
399 | static inline __u64 tv_to_ms(const struct timeval* tv) | 408 | static inline __u64 tv_to_ms(const struct timeval *tv) |
400 | { | 409 | { |
401 | __u64 ms = tv->tv_usec / 1000; | 410 | __u64 ms = tv->tv_usec / 1000; |
402 | ms += (__u64)tv->tv_sec * (__u64)1000; | 411 | ms += (__u64) tv->tv_sec * (__u64) 1000; |
403 | return ms; | 412 | return ms; |
404 | } | 413 | } |
405 | 414 | ||
406 | |||
407 | /** Convert to micro-seconds */ | 415 | /** Convert to micro-seconds */ |
408 | static inline __u64 tv_to_us(const struct timeval* tv) | 416 | static inline __u64 tv_to_us(const struct timeval *tv) |
409 | { | 417 | { |
410 | __u64 us = tv->tv_usec; | 418 | __u64 us = tv->tv_usec; |
411 | us += (__u64)tv->tv_sec * (__u64)1000000; | 419 | us += (__u64) tv->tv_sec * (__u64) 1000000; |
412 | return us; | 420 | return us; |
413 | } | 421 | } |
414 | 422 | ||
415 | static inline __u64 pg_div(__u64 n, __u32 base) { | 423 | static inline __u64 pg_div(__u64 n, __u32 base) |
416 | __u64 tmp = n; | 424 | { |
417 | do_div(tmp, base); | 425 | __u64 tmp = n; |
418 | /* printk("pktgen: pg_div, n: %llu base: %d rv: %llu\n", | 426 | do_div(tmp, base); |
419 | n, base, tmp); */ | 427 | /* printk("pktgen: pg_div, n: %llu base: %d rv: %llu\n", |
420 | return tmp; | 428 | n, base, tmp); */ |
429 | return tmp; | ||
421 | } | 430 | } |
422 | 431 | ||
423 | static inline __u64 pg_div64(__u64 n, __u64 base) | 432 | static inline __u64 pg_div64(__u64 n, __u64 base) |
424 | { | 433 | { |
425 | __u64 tmp = n; | 434 | __u64 tmp = n; |
426 | /* | 435 | /* |
427 | * How do we know if the architecture we are running on | 436 | * How do we know if the architecture we are running on |
428 | * supports division with 64 bit base? | 437 | * supports division with 64 bit base? |
429 | * | 438 | * |
430 | */ | 439 | */ |
431 | #if defined(__sparc_v9__) || defined(__powerpc64__) || defined(__alpha__) || defined(__x86_64__) || defined(__ia64__) | 440 | #if defined(__sparc_v9__) || defined(__powerpc64__) || defined(__alpha__) || defined(__x86_64__) || defined(__ia64__) |
432 | 441 | ||
433 | do_div(tmp, base); | 442 | do_div(tmp, base); |
434 | #else | 443 | #else |
435 | tmp = divremdi3(n, base, PG_DIV); | 444 | tmp = divremdi3(n, base, PG_DIV); |
436 | #endif | 445 | #endif |
437 | return tmp; | 446 | return tmp; |
438 | } | 447 | } |
439 | 448 | ||
440 | static inline u32 pktgen_random(void) | 449 | static inline u32 pktgen_random(void) |
@@ -448,51 +457,51 @@ static inline u32 pktgen_random(void) | |||
448 | #endif | 457 | #endif |
449 | } | 458 | } |
450 | 459 | ||
451 | static inline __u64 getCurMs(void) | 460 | static inline __u64 getCurMs(void) |
452 | { | 461 | { |
453 | struct timeval tv; | 462 | struct timeval tv; |
454 | do_gettimeofday(&tv); | 463 | do_gettimeofday(&tv); |
455 | return tv_to_ms(&tv); | 464 | return tv_to_ms(&tv); |
456 | } | 465 | } |
457 | 466 | ||
458 | static inline __u64 getCurUs(void) | 467 | static inline __u64 getCurUs(void) |
459 | { | 468 | { |
460 | struct timeval tv; | 469 | struct timeval tv; |
461 | do_gettimeofday(&tv); | 470 | do_gettimeofday(&tv); |
462 | return tv_to_us(&tv); | 471 | return tv_to_us(&tv); |
463 | } | 472 | } |
464 | 473 | ||
465 | static inline __u64 tv_diff(const struct timeval* a, const struct timeval* b) | 474 | static inline __u64 tv_diff(const struct timeval *a, const struct timeval *b) |
466 | { | 475 | { |
467 | return tv_to_us(a) - tv_to_us(b); | 476 | return tv_to_us(a) - tv_to_us(b); |
468 | } | 477 | } |
469 | 478 | ||
470 | |||
471 | /* old include end */ | 479 | /* old include end */ |
472 | 480 | ||
473 | static char version[] __initdata = VERSION; | 481 | static char version[] __initdata = VERSION; |
474 | 482 | ||
475 | static int pktgen_remove_device(struct pktgen_thread* t, struct pktgen_dev *i); | 483 | static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i); |
476 | static int pktgen_add_device(struct pktgen_thread* t, const char* ifname); | 484 | static int pktgen_add_device(struct pktgen_thread *t, const char *ifname); |
477 | static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread* t, const char* ifname); | 485 | static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, |
486 | const char *ifname); | ||
478 | static int pktgen_device_event(struct notifier_block *, unsigned long, void *); | 487 | static int pktgen_device_event(struct notifier_block *, unsigned long, void *); |
479 | static void pktgen_run_all_threads(void); | 488 | static void pktgen_run_all_threads(void); |
480 | static void pktgen_stop_all_threads_ifs(void); | 489 | static void pktgen_stop_all_threads_ifs(void); |
481 | static int pktgen_stop_device(struct pktgen_dev *pkt_dev); | 490 | static int pktgen_stop_device(struct pktgen_dev *pkt_dev); |
482 | static void pktgen_stop(struct pktgen_thread* t); | 491 | static void pktgen_stop(struct pktgen_thread *t); |
483 | static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); | 492 | static void pktgen_clear_counters(struct pktgen_dev *pkt_dev); |
484 | static struct pktgen_dev *pktgen_NN_threads(const char* dev_name, int remove); | 493 | static int pktgen_mark_device(const char *ifname); |
485 | static unsigned int scan_ip6(const char *s,char ip[16]); | 494 | static unsigned int scan_ip6(const char *s, char ip[16]); |
486 | static unsigned int fmt_ip6(char *s,const char ip[16]); | 495 | static unsigned int fmt_ip6(char *s, const char ip[16]); |
487 | 496 | ||
488 | /* Module parameters, defaults. */ | 497 | /* Module parameters, defaults. */ |
489 | static int pg_count_d = 1000; /* 1000 pkts by default */ | 498 | static int pg_count_d = 1000; /* 1000 pkts by default */ |
490 | static int pg_delay_d; | 499 | static int pg_delay_d; |
491 | static int pg_clone_skb_d; | 500 | static int pg_clone_skb_d; |
492 | static int debug; | 501 | static int debug; |
493 | 502 | ||
494 | static DECLARE_MUTEX(pktgen_sem); | 503 | static DEFINE_MUTEX(pktgen_thread_lock); |
495 | static struct pktgen_thread *pktgen_threads = NULL; | 504 | static LIST_HEAD(pktgen_threads); |
496 | 505 | ||
497 | static struct notifier_block pktgen_notifier_block = { | 506 | static struct notifier_block pktgen_notifier_block = { |
498 | .notifier_call = pktgen_device_event, | 507 | .notifier_call = pktgen_device_event, |
@@ -504,21 +513,21 @@ static struct notifier_block pktgen_notifier_block = { | |||
504 | */ | 513 | */ |
505 | 514 | ||
506 | static int pgctrl_show(struct seq_file *seq, void *v) | 515 | static int pgctrl_show(struct seq_file *seq, void *v) |
507 | { | 516 | { |
508 | seq_puts(seq, VERSION); | 517 | seq_puts(seq, VERSION); |
509 | return 0; | 518 | return 0; |
510 | } | 519 | } |
511 | 520 | ||
512 | static ssize_t pgctrl_write(struct file* file,const char __user * buf, | 521 | static ssize_t pgctrl_write(struct file *file, const char __user * buf, |
513 | size_t count, loff_t *ppos) | 522 | size_t count, loff_t * ppos) |
514 | { | 523 | { |
515 | int err = 0; | 524 | int err = 0; |
516 | char data[128]; | 525 | char data[128]; |
517 | 526 | ||
518 | if (!capable(CAP_NET_ADMIN)){ | 527 | if (!capable(CAP_NET_ADMIN)) { |
519 | err = -EPERM; | 528 | err = -EPERM; |
520 | goto out; | 529 | goto out; |
521 | } | 530 | } |
522 | 531 | ||
523 | if (count > sizeof(data)) | 532 | if (count > sizeof(data)) |
524 | count = sizeof(data); | 533 | count = sizeof(data); |
@@ -526,22 +535,22 @@ static ssize_t pgctrl_write(struct file* file,const char __user * buf, | |||
526 | if (copy_from_user(data, buf, count)) { | 535 | if (copy_from_user(data, buf, count)) { |
527 | err = -EFAULT; | 536 | err = -EFAULT; |
528 | goto out; | 537 | goto out; |
529 | } | 538 | } |
530 | data[count-1] = 0; /* Make string */ | 539 | data[count - 1] = 0; /* Make string */ |
531 | 540 | ||
532 | if (!strcmp(data, "stop")) | 541 | if (!strcmp(data, "stop")) |
533 | pktgen_stop_all_threads_ifs(); | 542 | pktgen_stop_all_threads_ifs(); |
534 | 543 | ||
535 | else if (!strcmp(data, "start")) | 544 | else if (!strcmp(data, "start")) |
536 | pktgen_run_all_threads(); | 545 | pktgen_run_all_threads(); |
537 | 546 | ||
538 | else | 547 | else |
539 | printk("pktgen: Unknown command: %s\n", data); | 548 | printk("pktgen: Unknown command: %s\n", data); |
540 | 549 | ||
541 | err = count; | 550 | err = count; |
542 | 551 | ||
543 | out: | 552 | out: |
544 | return err; | 553 | return err; |
545 | } | 554 | } |
546 | 555 | ||
547 | static int pgctrl_open(struct inode *inode, struct file *file) | 556 | static int pgctrl_open(struct inode *inode, struct file *file) |
@@ -550,147 +559,194 @@ static int pgctrl_open(struct inode *inode, struct file *file) | |||
550 | } | 559 | } |
551 | 560 | ||
552 | static struct file_operations pktgen_fops = { | 561 | static struct file_operations pktgen_fops = { |
553 | .owner = THIS_MODULE, | 562 | .owner = THIS_MODULE, |
554 | .open = pgctrl_open, | 563 | .open = pgctrl_open, |
555 | .read = seq_read, | 564 | .read = seq_read, |
556 | .llseek = seq_lseek, | 565 | .llseek = seq_lseek, |
557 | .write = pgctrl_write, | 566 | .write = pgctrl_write, |
558 | .release = single_release, | 567 | .release = single_release, |
559 | }; | 568 | }; |
560 | 569 | ||
561 | static int pktgen_if_show(struct seq_file *seq, void *v) | 570 | static int pktgen_if_show(struct seq_file *seq, void *v) |
562 | { | 571 | { |
563 | int i; | 572 | int i; |
564 | struct pktgen_dev *pkt_dev = seq->private; | 573 | struct pktgen_dev *pkt_dev = seq->private; |
565 | __u64 sa; | 574 | __u64 sa; |
566 | __u64 stopped; | 575 | __u64 stopped; |
567 | __u64 now = getCurUs(); | 576 | __u64 now = getCurUs(); |
568 | 577 | ||
569 | seq_printf(seq, "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", | 578 | seq_printf(seq, |
570 | (unsigned long long) pkt_dev->count, | 579 | "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", |
571 | pkt_dev->min_pkt_size, pkt_dev->max_pkt_size); | 580 | (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size, |
581 | pkt_dev->max_pkt_size); | ||
582 | |||
583 | seq_printf(seq, | ||
584 | " frags: %d delay: %u clone_skb: %d ifname: %s\n", | ||
585 | pkt_dev->nfrags, | ||
586 | 1000 * pkt_dev->delay_us + pkt_dev->delay_ns, | ||
587 | pkt_dev->clone_skb, pkt_dev->ifname); | ||
588 | |||
589 | seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, | ||
590 | pkt_dev->lflow); | ||
591 | |||
592 | if (pkt_dev->flags & F_IPV6) { | ||
593 | char b1[128], b2[128], b3[128]; | ||
594 | fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr); | ||
595 | fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr); | ||
596 | fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr); | ||
597 | seq_printf(seq, | ||
598 | " saddr: %s min_saddr: %s max_saddr: %s\n", b1, | ||
599 | b2, b3); | ||
600 | |||
601 | fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr); | ||
602 | fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr); | ||
603 | fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr); | ||
604 | seq_printf(seq, | ||
605 | " daddr: %s min_daddr: %s max_daddr: %s\n", b1, | ||
606 | b2, b3); | ||
607 | |||
608 | } else | ||
609 | seq_printf(seq, | ||
610 | " dst_min: %s dst_max: %s\n src_min: %s src_max: %s\n", | ||
611 | pkt_dev->dst_min, pkt_dev->dst_max, pkt_dev->src_min, | ||
612 | pkt_dev->src_max); | ||
613 | |||
614 | seq_puts(seq, " src_mac: "); | ||
615 | |||
616 | if (is_zero_ether_addr(pkt_dev->src_mac)) | ||
617 | for (i = 0; i < 6; i++) | ||
618 | seq_printf(seq, "%02X%s", pkt_dev->odev->dev_addr[i], | ||
619 | i == 5 ? " " : ":"); | ||
620 | else | ||
621 | for (i = 0; i < 6; i++) | ||
622 | seq_printf(seq, "%02X%s", pkt_dev->src_mac[i], | ||
623 | i == 5 ? " " : ":"); | ||
624 | |||
625 | seq_printf(seq, "dst_mac: "); | ||
626 | for (i = 0; i < 6; i++) | ||
627 | seq_printf(seq, "%02X%s", pkt_dev->dst_mac[i], | ||
628 | i == 5 ? "\n" : ":"); | ||
629 | |||
630 | seq_printf(seq, | ||
631 | " udp_src_min: %d udp_src_max: %d udp_dst_min: %d udp_dst_max: %d\n", | ||
632 | pkt_dev->udp_src_min, pkt_dev->udp_src_max, | ||
633 | pkt_dev->udp_dst_min, pkt_dev->udp_dst_max); | ||
634 | |||
635 | seq_printf(seq, | ||
636 | " src_mac_count: %d dst_mac_count: %d\n", | ||
637 | pkt_dev->src_mac_count, pkt_dev->dst_mac_count); | ||
572 | 638 | ||
573 | seq_printf(seq, " frags: %d delay: %u clone_skb: %d ifname: %s\n", | 639 | if (pkt_dev->nr_labels) { |
574 | pkt_dev->nfrags, 1000*pkt_dev->delay_us+pkt_dev->delay_ns, pkt_dev->clone_skb, pkt_dev->ifname); | 640 | unsigned i; |
641 | seq_printf(seq, " mpls: "); | ||
642 | for(i = 0; i < pkt_dev->nr_labels; i++) | ||
643 | seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]), | ||
644 | i == pkt_dev->nr_labels-1 ? "\n" : ", "); | ||
645 | } | ||
575 | 646 | ||
576 | seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, pkt_dev->lflow); | 647 | seq_printf(seq, " Flags: "); |
577 | 648 | ||
649 | if (pkt_dev->flags & F_IPV6) | ||
650 | seq_printf(seq, "IPV6 "); | ||
578 | 651 | ||
579 | if(pkt_dev->flags & F_IPV6) { | 652 | if (pkt_dev->flags & F_IPSRC_RND) |
580 | char b1[128], b2[128], b3[128]; | 653 | seq_printf(seq, "IPSRC_RND "); |
581 | fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr); | ||
582 | fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr); | ||
583 | fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr); | ||
584 | seq_printf(seq, " saddr: %s min_saddr: %s max_saddr: %s\n", b1, b2, b3); | ||
585 | 654 | ||
586 | fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr); | 655 | if (pkt_dev->flags & F_IPDST_RND) |
587 | fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr); | 656 | seq_printf(seq, "IPDST_RND "); |
588 | fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr); | ||
589 | seq_printf(seq, " daddr: %s min_daddr: %s max_daddr: %s\n", b1, b2, b3); | ||
590 | 657 | ||
591 | } | 658 | if (pkt_dev->flags & F_TXSIZE_RND) |
592 | else | 659 | seq_printf(seq, "TXSIZE_RND "); |
593 | seq_printf(seq," dst_min: %s dst_max: %s\n src_min: %s src_max: %s\n", | ||
594 | pkt_dev->dst_min, pkt_dev->dst_max, pkt_dev->src_min, pkt_dev->src_max); | ||
595 | 660 | ||
596 | seq_puts(seq, " src_mac: "); | 661 | if (pkt_dev->flags & F_UDPSRC_RND) |
662 | seq_printf(seq, "UDPSRC_RND "); | ||
597 | 663 | ||
598 | if (is_zero_ether_addr(pkt_dev->src_mac)) | 664 | if (pkt_dev->flags & F_UDPDST_RND) |
599 | for (i = 0; i < 6; i++) | 665 | seq_printf(seq, "UDPDST_RND "); |
600 | seq_printf(seq, "%02X%s", pkt_dev->odev->dev_addr[i], i == 5 ? " " : ":"); | ||
601 | else | ||
602 | for (i = 0; i < 6; i++) | ||
603 | seq_printf(seq, "%02X%s", pkt_dev->src_mac[i], i == 5 ? " " : ":"); | ||
604 | 666 | ||
605 | seq_printf(seq, "dst_mac: "); | 667 | if (pkt_dev->flags & F_MPLS_RND) |
606 | for (i = 0; i < 6; i++) | 668 | seq_printf(seq, "MPLS_RND "); |
607 | seq_printf(seq, "%02X%s", pkt_dev->dst_mac[i], i == 5 ? "\n" : ":"); | ||
608 | 669 | ||
609 | seq_printf(seq, " udp_src_min: %d udp_src_max: %d udp_dst_min: %d udp_dst_max: %d\n", | 670 | if (pkt_dev->flags & F_MACSRC_RND) |
610 | pkt_dev->udp_src_min, pkt_dev->udp_src_max, pkt_dev->udp_dst_min, | 671 | seq_printf(seq, "MACSRC_RND "); |
611 | pkt_dev->udp_dst_max); | ||
612 | 672 | ||
613 | seq_printf(seq, " src_mac_count: %d dst_mac_count: %d \n Flags: ", | 673 | if (pkt_dev->flags & F_MACDST_RND) |
614 | pkt_dev->src_mac_count, pkt_dev->dst_mac_count); | 674 | seq_printf(seq, "MACDST_RND "); |
615 | 675 | ||
676 | seq_puts(seq, "\n"); | ||
616 | 677 | ||
617 | if (pkt_dev->flags & F_IPV6) | 678 | sa = pkt_dev->started_at; |
618 | seq_printf(seq, "IPV6 "); | 679 | stopped = pkt_dev->stopped_at; |
619 | 680 | if (pkt_dev->running) | |
620 | if (pkt_dev->flags & F_IPSRC_RND) | 681 | stopped = now; /* not really stopped, more like last-running-at */ |
621 | seq_printf(seq, "IPSRC_RND "); | 682 | |
622 | 683 | seq_printf(seq, | |
623 | if (pkt_dev->flags & F_IPDST_RND) | 684 | "Current:\n pkts-sofar: %llu errors: %llu\n started: %lluus stopped: %lluus idle: %lluus\n", |
624 | seq_printf(seq, "IPDST_RND "); | 685 | (unsigned long long)pkt_dev->sofar, |
625 | 686 | (unsigned long long)pkt_dev->errors, (unsigned long long)sa, | |
626 | if (pkt_dev->flags & F_TXSIZE_RND) | 687 | (unsigned long long)stopped, |
627 | seq_printf(seq, "TXSIZE_RND "); | 688 | (unsigned long long)pkt_dev->idle_acc); |
628 | 689 | ||
629 | if (pkt_dev->flags & F_UDPSRC_RND) | 690 | seq_printf(seq, |
630 | seq_printf(seq, "UDPSRC_RND "); | 691 | " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", |
631 | |||
632 | if (pkt_dev->flags & F_UDPDST_RND) | ||
633 | seq_printf(seq, "UDPDST_RND "); | ||
634 | |||
635 | if (pkt_dev->flags & F_MACSRC_RND) | ||
636 | seq_printf(seq, "MACSRC_RND "); | ||
637 | |||
638 | if (pkt_dev->flags & F_MACDST_RND) | ||
639 | seq_printf(seq, "MACDST_RND "); | ||
640 | |||
641 | |||
642 | seq_puts(seq, "\n"); | ||
643 | |||
644 | sa = pkt_dev->started_at; | ||
645 | stopped = pkt_dev->stopped_at; | ||
646 | if (pkt_dev->running) | ||
647 | stopped = now; /* not really stopped, more like last-running-at */ | ||
648 | |||
649 | seq_printf(seq, "Current:\n pkts-sofar: %llu errors: %llu\n started: %lluus stopped: %lluus idle: %lluus\n", | ||
650 | (unsigned long long) pkt_dev->sofar, | ||
651 | (unsigned long long) pkt_dev->errors, | ||
652 | (unsigned long long) sa, | ||
653 | (unsigned long long) stopped, | ||
654 | (unsigned long long) pkt_dev->idle_acc); | ||
655 | |||
656 | seq_printf(seq, " seq_num: %d cur_dst_mac_offset: %d cur_src_mac_offset: %d\n", | ||
657 | pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset, | 692 | pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset, |
658 | pkt_dev->cur_src_mac_offset); | 693 | pkt_dev->cur_src_mac_offset); |
659 | 694 | ||
660 | if(pkt_dev->flags & F_IPV6) { | 695 | if (pkt_dev->flags & F_IPV6) { |
661 | char b1[128], b2[128]; | 696 | char b1[128], b2[128]; |
662 | fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr); | 697 | fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr); |
663 | fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr); | 698 | fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr); |
664 | seq_printf(seq, " cur_saddr: %s cur_daddr: %s\n", b2, b1); | 699 | seq_printf(seq, " cur_saddr: %s cur_daddr: %s\n", b2, b1); |
665 | } | 700 | } else |
666 | else | 701 | seq_printf(seq, " cur_saddr: 0x%x cur_daddr: 0x%x\n", |
667 | seq_printf(seq, " cur_saddr: 0x%x cur_daddr: 0x%x\n", | ||
668 | pkt_dev->cur_saddr, pkt_dev->cur_daddr); | 702 | pkt_dev->cur_saddr, pkt_dev->cur_daddr); |
669 | 703 | ||
670 | 704 | seq_printf(seq, " cur_udp_dst: %d cur_udp_src: %d\n", | |
671 | seq_printf(seq, " cur_udp_dst: %d cur_udp_src: %d\n", | ||
672 | pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); | 705 | pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src); |
673 | 706 | ||
674 | seq_printf(seq, " flows: %u\n", pkt_dev->nflows); | 707 | seq_printf(seq, " flows: %u\n", pkt_dev->nflows); |
675 | 708 | ||
676 | if (pkt_dev->result[0]) | 709 | if (pkt_dev->result[0]) |
677 | seq_printf(seq, "Result: %s\n", pkt_dev->result); | 710 | seq_printf(seq, "Result: %s\n", pkt_dev->result); |
678 | else | 711 | else |
679 | seq_printf(seq, "Result: Idle\n"); | 712 | seq_printf(seq, "Result: Idle\n"); |
680 | 713 | ||
681 | return 0; | 714 | return 0; |
682 | } | 715 | } |
683 | 716 | ||
684 | 717 | ||
685 | static int count_trail_chars(const char __user *user_buffer, unsigned int maxlen) | 718 | static int hex32_arg(const char __user *user_buffer, __u32 *num) |
719 | { | ||
720 | int i = 0; | ||
721 | *num = 0; | ||
722 | |||
723 | for(; i < 8; i++) { | ||
724 | char c; | ||
725 | *num <<= 4; | ||
726 | if (get_user(c, &user_buffer[i])) | ||
727 | return -EFAULT; | ||
728 | if ((c >= '0') && (c <= '9')) | ||
729 | *num |= c - '0'; | ||
730 | else if ((c >= 'a') && (c <= 'f')) | ||
731 | *num |= c - 'a' + 10; | ||
732 | else if ((c >= 'A') && (c <= 'F')) | ||
733 | *num |= c - 'A' + 10; | ||
734 | else | ||
735 | break; | ||
736 | } | ||
737 | return i; | ||
738 | } | ||
739 | |||
740 | static int count_trail_chars(const char __user * user_buffer, | ||
741 | unsigned int maxlen) | ||
686 | { | 742 | { |
687 | int i; | 743 | int i; |
688 | 744 | ||
689 | for (i = 0; i < maxlen; i++) { | 745 | for (i = 0; i < maxlen; i++) { |
690 | char c; | 746 | char c; |
691 | if (get_user(c, &user_buffer[i])) | 747 | if (get_user(c, &user_buffer[i])) |
692 | return -EFAULT; | 748 | return -EFAULT; |
693 | switch (c) { | 749 | switch (c) { |
694 | case '\"': | 750 | case '\"': |
695 | case '\n': | 751 | case '\n': |
696 | case '\r': | 752 | case '\r': |
@@ -706,34 +762,34 @@ done: | |||
706 | return i; | 762 | return i; |
707 | } | 763 | } |
708 | 764 | ||
709 | static unsigned long num_arg(const char __user *user_buffer, unsigned long maxlen, | 765 | static unsigned long num_arg(const char __user * user_buffer, |
710 | unsigned long *num) | 766 | unsigned long maxlen, unsigned long *num) |
711 | { | 767 | { |
712 | int i = 0; | 768 | int i = 0; |
713 | *num = 0; | 769 | *num = 0; |
714 | 770 | ||
715 | for(; i < maxlen; i++) { | 771 | for (; i < maxlen; i++) { |
716 | char c; | 772 | char c; |
717 | if (get_user(c, &user_buffer[i])) | 773 | if (get_user(c, &user_buffer[i])) |
718 | return -EFAULT; | 774 | return -EFAULT; |
719 | if ((c >= '0') && (c <= '9')) { | 775 | if ((c >= '0') && (c <= '9')) { |
720 | *num *= 10; | 776 | *num *= 10; |
721 | *num += c -'0'; | 777 | *num += c - '0'; |
722 | } else | 778 | } else |
723 | break; | 779 | break; |
724 | } | 780 | } |
725 | return i; | 781 | return i; |
726 | } | 782 | } |
727 | 783 | ||
728 | static int strn_len(const char __user *user_buffer, unsigned int maxlen) | 784 | static int strn_len(const char __user * user_buffer, unsigned int maxlen) |
729 | { | 785 | { |
730 | int i = 0; | 786 | int i = 0; |
731 | 787 | ||
732 | for(; i < maxlen; i++) { | 788 | for (; i < maxlen; i++) { |
733 | char c; | 789 | char c; |
734 | if (get_user(c, &user_buffer[i])) | 790 | if (get_user(c, &user_buffer[i])) |
735 | return -EFAULT; | 791 | return -EFAULT; |
736 | switch (c) { | 792 | switch (c) { |
737 | case '\"': | 793 | case '\"': |
738 | case '\n': | 794 | case '\n': |
739 | case '\r': | 795 | case '\r': |
@@ -746,119 +802,162 @@ static int strn_len(const char __user *user_buffer, unsigned int maxlen) | |||
746 | }; | 802 | }; |
747 | } | 803 | } |
748 | done_str: | 804 | done_str: |
805 | return i; | ||
806 | } | ||
807 | |||
808 | static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev) | ||
809 | { | ||
810 | unsigned n = 0; | ||
811 | char c; | ||
812 | ssize_t i = 0; | ||
813 | int len; | ||
814 | |||
815 | pkt_dev->nr_labels = 0; | ||
816 | do { | ||
817 | __u32 tmp; | ||
818 | len = hex32_arg(&buffer[i], &tmp); | ||
819 | if (len <= 0) | ||
820 | return len; | ||
821 | pkt_dev->labels[n] = htonl(tmp); | ||
822 | if (pkt_dev->labels[n] & MPLS_STACK_BOTTOM) | ||
823 | pkt_dev->flags |= F_MPLS_RND; | ||
824 | i += len; | ||
825 | if (get_user(c, &buffer[i])) | ||
826 | return -EFAULT; | ||
827 | i++; | ||
828 | n++; | ||
829 | if (n >= MAX_MPLS_LABELS) | ||
830 | return -E2BIG; | ||
831 | } while(c == ','); | ||
749 | 832 | ||
833 | pkt_dev->nr_labels = n; | ||
750 | return i; | 834 | return i; |
751 | } | 835 | } |
752 | 836 | ||
753 | static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer, | 837 | static ssize_t pktgen_if_write(struct file *file, |
754 | size_t count, loff_t *offset) | 838 | const char __user * user_buffer, size_t count, |
839 | loff_t * offset) | ||
755 | { | 840 | { |
756 | struct seq_file *seq = (struct seq_file *) file->private_data; | 841 | struct seq_file *seq = (struct seq_file *)file->private_data; |
757 | struct pktgen_dev *pkt_dev = seq->private; | 842 | struct pktgen_dev *pkt_dev = seq->private; |
758 | int i = 0, max, len; | 843 | int i = 0, max, len; |
759 | char name[16], valstr[32]; | 844 | char name[16], valstr[32]; |
760 | unsigned long value = 0; | 845 | unsigned long value = 0; |
761 | char* pg_result = NULL; | 846 | char *pg_result = NULL; |
762 | int tmp = 0; | 847 | int tmp = 0; |
763 | char buf[128]; | 848 | char buf[128]; |
764 | 849 | ||
765 | pg_result = &(pkt_dev->result[0]); | 850 | pg_result = &(pkt_dev->result[0]); |
766 | 851 | ||
767 | if (count < 1) { | 852 | if (count < 1) { |
768 | printk("pktgen: wrong command format\n"); | 853 | printk("pktgen: wrong command format\n"); |
769 | return -EINVAL; | 854 | return -EINVAL; |
770 | } | 855 | } |
771 | 856 | ||
772 | max = count - i; | 857 | max = count - i; |
773 | tmp = count_trail_chars(&user_buffer[i], max); | 858 | tmp = count_trail_chars(&user_buffer[i], max); |
774 | if (tmp < 0) { | 859 | if (tmp < 0) { |
775 | printk("pktgen: illegal format\n"); | 860 | printk("pktgen: illegal format\n"); |
776 | return tmp; | 861 | return tmp; |
777 | } | 862 | } |
778 | i += tmp; | 863 | i += tmp; |
779 | 864 | ||
780 | /* Read variable name */ | 865 | /* Read variable name */ |
781 | 866 | ||
782 | len = strn_len(&user_buffer[i], sizeof(name) - 1); | 867 | len = strn_len(&user_buffer[i], sizeof(name) - 1); |
783 | if (len < 0) { return len; } | 868 | if (len < 0) { |
869 | return len; | ||
870 | } | ||
784 | memset(name, 0, sizeof(name)); | 871 | memset(name, 0, sizeof(name)); |
785 | if (copy_from_user(name, &user_buffer[i], len) ) | 872 | if (copy_from_user(name, &user_buffer[i], len)) |
786 | return -EFAULT; | 873 | return -EFAULT; |
787 | i += len; | 874 | i += len; |
788 | 875 | ||
789 | max = count -i; | 876 | max = count - i; |
790 | len = count_trail_chars(&user_buffer[i], max); | 877 | len = count_trail_chars(&user_buffer[i], max); |
791 | if (len < 0) | 878 | if (len < 0) |
792 | return len; | 879 | return len; |
793 | 880 | ||
794 | i += len; | 881 | i += len; |
795 | 882 | ||
796 | if (debug) { | 883 | if (debug) { |
797 | char tb[count + 1]; | 884 | char tb[count + 1]; |
798 | if (copy_from_user(tb, user_buffer, count)) | 885 | if (copy_from_user(tb, user_buffer, count)) |
799 | return -EFAULT; | 886 | return -EFAULT; |
800 | tb[count] = 0; | 887 | tb[count] = 0; |
801 | printk("pktgen: %s,%lu buffer -:%s:-\n", name, | 888 | printk("pktgen: %s,%lu buffer -:%s:-\n", name, |
802 | (unsigned long) count, tb); | 889 | (unsigned long)count, tb); |
803 | } | 890 | } |
804 | 891 | ||
805 | if (!strcmp(name, "min_pkt_size")) { | 892 | if (!strcmp(name, "min_pkt_size")) { |
806 | len = num_arg(&user_buffer[i], 10, &value); | 893 | len = num_arg(&user_buffer[i], 10, &value); |
807 | if (len < 0) { return len; } | 894 | if (len < 0) { |
895 | return len; | ||
896 | } | ||
808 | i += len; | 897 | i += len; |
809 | if (value < 14+20+8) | 898 | if (value < 14 + 20 + 8) |
810 | value = 14+20+8; | 899 | value = 14 + 20 + 8; |
811 | if (value != pkt_dev->min_pkt_size) { | 900 | if (value != pkt_dev->min_pkt_size) { |
812 | pkt_dev->min_pkt_size = value; | 901 | pkt_dev->min_pkt_size = value; |
813 | pkt_dev->cur_pkt_size = value; | 902 | pkt_dev->cur_pkt_size = value; |
814 | } | 903 | } |
815 | sprintf(pg_result, "OK: min_pkt_size=%u", pkt_dev->min_pkt_size); | 904 | sprintf(pg_result, "OK: min_pkt_size=%u", |
905 | pkt_dev->min_pkt_size); | ||
816 | return count; | 906 | return count; |
817 | } | 907 | } |
818 | 908 | ||
819 | if (!strcmp(name, "max_pkt_size")) { | 909 | if (!strcmp(name, "max_pkt_size")) { |
820 | len = num_arg(&user_buffer[i], 10, &value); | 910 | len = num_arg(&user_buffer[i], 10, &value); |
821 | if (len < 0) { return len; } | 911 | if (len < 0) { |
912 | return len; | ||
913 | } | ||
822 | i += len; | 914 | i += len; |
823 | if (value < 14+20+8) | 915 | if (value < 14 + 20 + 8) |
824 | value = 14+20+8; | 916 | value = 14 + 20 + 8; |
825 | if (value != pkt_dev->max_pkt_size) { | 917 | if (value != pkt_dev->max_pkt_size) { |
826 | pkt_dev->max_pkt_size = value; | 918 | pkt_dev->max_pkt_size = value; |
827 | pkt_dev->cur_pkt_size = value; | 919 | pkt_dev->cur_pkt_size = value; |
828 | } | 920 | } |
829 | sprintf(pg_result, "OK: max_pkt_size=%u", pkt_dev->max_pkt_size); | 921 | sprintf(pg_result, "OK: max_pkt_size=%u", |
922 | pkt_dev->max_pkt_size); | ||
830 | return count; | 923 | return count; |
831 | } | 924 | } |
832 | 925 | ||
833 | /* Shortcut for min = max */ | 926 | /* Shortcut for min = max */ |
834 | 927 | ||
835 | if (!strcmp(name, "pkt_size")) { | 928 | if (!strcmp(name, "pkt_size")) { |
836 | len = num_arg(&user_buffer[i], 10, &value); | 929 | len = num_arg(&user_buffer[i], 10, &value); |
837 | if (len < 0) { return len; } | 930 | if (len < 0) { |
931 | return len; | ||
932 | } | ||
838 | i += len; | 933 | i += len; |
839 | if (value < 14+20+8) | 934 | if (value < 14 + 20 + 8) |
840 | value = 14+20+8; | 935 | value = 14 + 20 + 8; |
841 | if (value != pkt_dev->min_pkt_size) { | 936 | if (value != pkt_dev->min_pkt_size) { |
842 | pkt_dev->min_pkt_size = value; | 937 | pkt_dev->min_pkt_size = value; |
843 | pkt_dev->max_pkt_size = value; | 938 | pkt_dev->max_pkt_size = value; |
844 | pkt_dev->cur_pkt_size = value; | 939 | pkt_dev->cur_pkt_size = value; |
845 | } | 940 | } |
846 | sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size); | 941 | sprintf(pg_result, "OK: pkt_size=%u", pkt_dev->min_pkt_size); |
847 | return count; | 942 | return count; |
848 | } | 943 | } |
849 | 944 | ||
850 | if (!strcmp(name, "debug")) { | 945 | if (!strcmp(name, "debug")) { |
851 | len = num_arg(&user_buffer[i], 10, &value); | 946 | len = num_arg(&user_buffer[i], 10, &value); |
852 | if (len < 0) { return len; } | 947 | if (len < 0) { |
948 | return len; | ||
949 | } | ||
853 | i += len; | 950 | i += len; |
854 | debug = value; | 951 | debug = value; |
855 | sprintf(pg_result, "OK: debug=%u", debug); | 952 | sprintf(pg_result, "OK: debug=%u", debug); |
856 | return count; | 953 | return count; |
857 | } | 954 | } |
858 | 955 | ||
859 | if (!strcmp(name, "frags")) { | 956 | if (!strcmp(name, "frags")) { |
860 | len = num_arg(&user_buffer[i], 10, &value); | 957 | len = num_arg(&user_buffer[i], 10, &value); |
861 | if (len < 0) { return len; } | 958 | if (len < 0) { |
959 | return len; | ||
960 | } | ||
862 | i += len; | 961 | i += len; |
863 | pkt_dev->nfrags = value; | 962 | pkt_dev->nfrags = value; |
864 | sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags); | 963 | sprintf(pg_result, "OK: frags=%u", pkt_dev->nfrags); |
@@ -866,7 +965,9 @@ static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer | |||
866 | } | 965 | } |
867 | if (!strcmp(name, "delay")) { | 966 | if (!strcmp(name, "delay")) { |
868 | len = num_arg(&user_buffer[i], 10, &value); | 967 | len = num_arg(&user_buffer[i], 10, &value); |
869 | if (len < 0) { return len; } | 968 | if (len < 0) { |
969 | return len; | ||
970 | } | ||
870 | i += len; | 971 | i += len; |
871 | if (value == 0x7FFFFFFF) { | 972 | if (value == 0x7FFFFFFF) { |
872 | pkt_dev->delay_us = 0x7FFFFFFF; | 973 | pkt_dev->delay_us = 0x7FFFFFFF; |
@@ -875,308 +976,353 @@ static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer | |||
875 | pkt_dev->delay_us = value / 1000; | 976 | pkt_dev->delay_us = value / 1000; |
876 | pkt_dev->delay_ns = value % 1000; | 977 | pkt_dev->delay_ns = value % 1000; |
877 | } | 978 | } |
878 | sprintf(pg_result, "OK: delay=%u", 1000*pkt_dev->delay_us+pkt_dev->delay_ns); | 979 | sprintf(pg_result, "OK: delay=%u", |
980 | 1000 * pkt_dev->delay_us + pkt_dev->delay_ns); | ||
879 | return count; | 981 | return count; |
880 | } | 982 | } |
881 | if (!strcmp(name, "udp_src_min")) { | 983 | if (!strcmp(name, "udp_src_min")) { |
882 | len = num_arg(&user_buffer[i], 10, &value); | 984 | len = num_arg(&user_buffer[i], 10, &value); |
883 | if (len < 0) { return len; } | 985 | if (len < 0) { |
986 | return len; | ||
987 | } | ||
884 | i += len; | 988 | i += len; |
885 | if (value != pkt_dev->udp_src_min) { | 989 | if (value != pkt_dev->udp_src_min) { |
886 | pkt_dev->udp_src_min = value; | 990 | pkt_dev->udp_src_min = value; |
887 | pkt_dev->cur_udp_src = value; | 991 | pkt_dev->cur_udp_src = value; |
888 | } | 992 | } |
889 | sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min); | 993 | sprintf(pg_result, "OK: udp_src_min=%u", pkt_dev->udp_src_min); |
890 | return count; | 994 | return count; |
891 | } | 995 | } |
892 | if (!strcmp(name, "udp_dst_min")) { | 996 | if (!strcmp(name, "udp_dst_min")) { |
893 | len = num_arg(&user_buffer[i], 10, &value); | 997 | len = num_arg(&user_buffer[i], 10, &value); |
894 | if (len < 0) { return len; } | 998 | if (len < 0) { |
999 | return len; | ||
1000 | } | ||
895 | i += len; | 1001 | i += len; |
896 | if (value != pkt_dev->udp_dst_min) { | 1002 | if (value != pkt_dev->udp_dst_min) { |
897 | pkt_dev->udp_dst_min = value; | 1003 | pkt_dev->udp_dst_min = value; |
898 | pkt_dev->cur_udp_dst = value; | 1004 | pkt_dev->cur_udp_dst = value; |
899 | } | 1005 | } |
900 | sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min); | 1006 | sprintf(pg_result, "OK: udp_dst_min=%u", pkt_dev->udp_dst_min); |
901 | return count; | 1007 | return count; |
902 | } | 1008 | } |
903 | if (!strcmp(name, "udp_src_max")) { | 1009 | if (!strcmp(name, "udp_src_max")) { |
904 | len = num_arg(&user_buffer[i], 10, &value); | 1010 | len = num_arg(&user_buffer[i], 10, &value); |
905 | if (len < 0) { return len; } | 1011 | if (len < 0) { |
1012 | return len; | ||
1013 | } | ||
906 | i += len; | 1014 | i += len; |
907 | if (value != pkt_dev->udp_src_max) { | 1015 | if (value != pkt_dev->udp_src_max) { |
908 | pkt_dev->udp_src_max = value; | 1016 | pkt_dev->udp_src_max = value; |
909 | pkt_dev->cur_udp_src = value; | 1017 | pkt_dev->cur_udp_src = value; |
910 | } | 1018 | } |
911 | sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max); | 1019 | sprintf(pg_result, "OK: udp_src_max=%u", pkt_dev->udp_src_max); |
912 | return count; | 1020 | return count; |
913 | } | 1021 | } |
914 | if (!strcmp(name, "udp_dst_max")) { | 1022 | if (!strcmp(name, "udp_dst_max")) { |
915 | len = num_arg(&user_buffer[i], 10, &value); | 1023 | len = num_arg(&user_buffer[i], 10, &value); |
916 | if (len < 0) { return len; } | 1024 | if (len < 0) { |
1025 | return len; | ||
1026 | } | ||
917 | i += len; | 1027 | i += len; |
918 | if (value != pkt_dev->udp_dst_max) { | 1028 | if (value != pkt_dev->udp_dst_max) { |
919 | pkt_dev->udp_dst_max = value; | 1029 | pkt_dev->udp_dst_max = value; |
920 | pkt_dev->cur_udp_dst = value; | 1030 | pkt_dev->cur_udp_dst = value; |
921 | } | 1031 | } |
922 | sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max); | 1032 | sprintf(pg_result, "OK: udp_dst_max=%u", pkt_dev->udp_dst_max); |
923 | return count; | 1033 | return count; |
924 | } | 1034 | } |
925 | if (!strcmp(name, "clone_skb")) { | 1035 | if (!strcmp(name, "clone_skb")) { |
926 | len = num_arg(&user_buffer[i], 10, &value); | 1036 | len = num_arg(&user_buffer[i], 10, &value); |
927 | if (len < 0) { return len; } | 1037 | if (len < 0) { |
1038 | return len; | ||
1039 | } | ||
928 | i += len; | 1040 | i += len; |
929 | pkt_dev->clone_skb = value; | 1041 | pkt_dev->clone_skb = value; |
930 | 1042 | ||
931 | sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb); | 1043 | sprintf(pg_result, "OK: clone_skb=%d", pkt_dev->clone_skb); |
932 | return count; | 1044 | return count; |
933 | } | 1045 | } |
934 | if (!strcmp(name, "count")) { | 1046 | if (!strcmp(name, "count")) { |
935 | len = num_arg(&user_buffer[i], 10, &value); | 1047 | len = num_arg(&user_buffer[i], 10, &value); |
936 | if (len < 0) { return len; } | 1048 | if (len < 0) { |
1049 | return len; | ||
1050 | } | ||
937 | i += len; | 1051 | i += len; |
938 | pkt_dev->count = value; | 1052 | pkt_dev->count = value; |
939 | sprintf(pg_result, "OK: count=%llu", | 1053 | sprintf(pg_result, "OK: count=%llu", |
940 | (unsigned long long) pkt_dev->count); | 1054 | (unsigned long long)pkt_dev->count); |
941 | return count; | 1055 | return count; |
942 | } | 1056 | } |
943 | if (!strcmp(name, "src_mac_count")) { | 1057 | if (!strcmp(name, "src_mac_count")) { |
944 | len = num_arg(&user_buffer[i], 10, &value); | 1058 | len = num_arg(&user_buffer[i], 10, &value); |
945 | if (len < 0) { return len; } | 1059 | if (len < 0) { |
1060 | return len; | ||
1061 | } | ||
946 | i += len; | 1062 | i += len; |
947 | if (pkt_dev->src_mac_count != value) { | 1063 | if (pkt_dev->src_mac_count != value) { |
948 | pkt_dev->src_mac_count = value; | 1064 | pkt_dev->src_mac_count = value; |
949 | pkt_dev->cur_src_mac_offset = 0; | 1065 | pkt_dev->cur_src_mac_offset = 0; |
950 | } | 1066 | } |
951 | sprintf(pg_result, "OK: src_mac_count=%d", pkt_dev->src_mac_count); | 1067 | sprintf(pg_result, "OK: src_mac_count=%d", |
1068 | pkt_dev->src_mac_count); | ||
952 | return count; | 1069 | return count; |
953 | } | 1070 | } |
954 | if (!strcmp(name, "dst_mac_count")) { | 1071 | if (!strcmp(name, "dst_mac_count")) { |
955 | len = num_arg(&user_buffer[i], 10, &value); | 1072 | len = num_arg(&user_buffer[i], 10, &value); |
956 | if (len < 0) { return len; } | 1073 | if (len < 0) { |
1074 | return len; | ||
1075 | } | ||
957 | i += len; | 1076 | i += len; |
958 | if (pkt_dev->dst_mac_count != value) { | 1077 | if (pkt_dev->dst_mac_count != value) { |
959 | pkt_dev->dst_mac_count = value; | 1078 | pkt_dev->dst_mac_count = value; |
960 | pkt_dev->cur_dst_mac_offset = 0; | 1079 | pkt_dev->cur_dst_mac_offset = 0; |
961 | } | 1080 | } |
962 | sprintf(pg_result, "OK: dst_mac_count=%d", pkt_dev->dst_mac_count); | 1081 | sprintf(pg_result, "OK: dst_mac_count=%d", |
1082 | pkt_dev->dst_mac_count); | ||
963 | return count; | 1083 | return count; |
964 | } | 1084 | } |
965 | if (!strcmp(name, "flag")) { | 1085 | if (!strcmp(name, "flag")) { |
966 | char f[32]; | 1086 | char f[32]; |
967 | memset(f, 0, 32); | 1087 | memset(f, 0, 32); |
968 | len = strn_len(&user_buffer[i], sizeof(f) - 1); | 1088 | len = strn_len(&user_buffer[i], sizeof(f) - 1); |
969 | if (len < 0) { return len; } | 1089 | if (len < 0) { |
1090 | return len; | ||
1091 | } | ||
970 | if (copy_from_user(f, &user_buffer[i], len)) | 1092 | if (copy_from_user(f, &user_buffer[i], len)) |
971 | return -EFAULT; | 1093 | return -EFAULT; |
972 | i += len; | 1094 | i += len; |
973 | if (strcmp(f, "IPSRC_RND") == 0) | 1095 | if (strcmp(f, "IPSRC_RND") == 0) |
974 | pkt_dev->flags |= F_IPSRC_RND; | 1096 | pkt_dev->flags |= F_IPSRC_RND; |
975 | 1097 | ||
976 | else if (strcmp(f, "!IPSRC_RND") == 0) | 1098 | else if (strcmp(f, "!IPSRC_RND") == 0) |
977 | pkt_dev->flags &= ~F_IPSRC_RND; | 1099 | pkt_dev->flags &= ~F_IPSRC_RND; |
978 | 1100 | ||
979 | else if (strcmp(f, "TXSIZE_RND") == 0) | 1101 | else if (strcmp(f, "TXSIZE_RND") == 0) |
980 | pkt_dev->flags |= F_TXSIZE_RND; | 1102 | pkt_dev->flags |= F_TXSIZE_RND; |
981 | 1103 | ||
982 | else if (strcmp(f, "!TXSIZE_RND") == 0) | 1104 | else if (strcmp(f, "!TXSIZE_RND") == 0) |
983 | pkt_dev->flags &= ~F_TXSIZE_RND; | 1105 | pkt_dev->flags &= ~F_TXSIZE_RND; |
984 | 1106 | ||
985 | else if (strcmp(f, "IPDST_RND") == 0) | 1107 | else if (strcmp(f, "IPDST_RND") == 0) |
986 | pkt_dev->flags |= F_IPDST_RND; | 1108 | pkt_dev->flags |= F_IPDST_RND; |
987 | 1109 | ||
988 | else if (strcmp(f, "!IPDST_RND") == 0) | 1110 | else if (strcmp(f, "!IPDST_RND") == 0) |
989 | pkt_dev->flags &= ~F_IPDST_RND; | 1111 | pkt_dev->flags &= ~F_IPDST_RND; |
990 | 1112 | ||
991 | else if (strcmp(f, "UDPSRC_RND") == 0) | 1113 | else if (strcmp(f, "UDPSRC_RND") == 0) |
992 | pkt_dev->flags |= F_UDPSRC_RND; | 1114 | pkt_dev->flags |= F_UDPSRC_RND; |
993 | 1115 | ||
994 | else if (strcmp(f, "!UDPSRC_RND") == 0) | 1116 | else if (strcmp(f, "!UDPSRC_RND") == 0) |
995 | pkt_dev->flags &= ~F_UDPSRC_RND; | 1117 | pkt_dev->flags &= ~F_UDPSRC_RND; |
996 | 1118 | ||
997 | else if (strcmp(f, "UDPDST_RND") == 0) | 1119 | else if (strcmp(f, "UDPDST_RND") == 0) |
998 | pkt_dev->flags |= F_UDPDST_RND; | 1120 | pkt_dev->flags |= F_UDPDST_RND; |
999 | 1121 | ||
1000 | else if (strcmp(f, "!UDPDST_RND") == 0) | 1122 | else if (strcmp(f, "!UDPDST_RND") == 0) |
1001 | pkt_dev->flags &= ~F_UDPDST_RND; | 1123 | pkt_dev->flags &= ~F_UDPDST_RND; |
1002 | 1124 | ||
1003 | else if (strcmp(f, "MACSRC_RND") == 0) | 1125 | else if (strcmp(f, "MACSRC_RND") == 0) |
1004 | pkt_dev->flags |= F_MACSRC_RND; | 1126 | pkt_dev->flags |= F_MACSRC_RND; |
1005 | 1127 | ||
1006 | else if (strcmp(f, "!MACSRC_RND") == 0) | 1128 | else if (strcmp(f, "!MACSRC_RND") == 0) |
1007 | pkt_dev->flags &= ~F_MACSRC_RND; | 1129 | pkt_dev->flags &= ~F_MACSRC_RND; |
1008 | 1130 | ||
1009 | else if (strcmp(f, "MACDST_RND") == 0) | 1131 | else if (strcmp(f, "MACDST_RND") == 0) |
1010 | pkt_dev->flags |= F_MACDST_RND; | 1132 | pkt_dev->flags |= F_MACDST_RND; |
1011 | 1133 | ||
1012 | else if (strcmp(f, "!MACDST_RND") == 0) | 1134 | else if (strcmp(f, "!MACDST_RND") == 0) |
1013 | pkt_dev->flags &= ~F_MACDST_RND; | 1135 | pkt_dev->flags &= ~F_MACDST_RND; |
1014 | 1136 | ||
1015 | else { | 1137 | else if (strcmp(f, "MPLS_RND") == 0) |
1016 | sprintf(pg_result, "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", | 1138 | pkt_dev->flags |= F_MPLS_RND; |
1017 | f, | 1139 | |
1018 | "IPSRC_RND, IPDST_RND, TXSIZE_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n"); | 1140 | else if (strcmp(f, "!MPLS_RND") == 0) |
1019 | return count; | 1141 | pkt_dev->flags &= ~F_MPLS_RND; |
1020 | } | 1142 | |
1143 | else { | ||
1144 | sprintf(pg_result, | ||
1145 | "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s", | ||
1146 | f, | ||
1147 | "IPSRC_RND, IPDST_RND, TXSIZE_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n"); | ||
1148 | return count; | ||
1149 | } | ||
1021 | sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); | 1150 | sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags); |
1022 | return count; | 1151 | return count; |
1023 | } | 1152 | } |
1024 | if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { | 1153 | if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { |
1025 | len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); | 1154 | len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); |
1026 | if (len < 0) { return len; } | 1155 | if (len < 0) { |
1156 | return len; | ||
1157 | } | ||
1027 | 1158 | ||
1028 | if (copy_from_user(buf, &user_buffer[i], len)) | 1159 | if (copy_from_user(buf, &user_buffer[i], len)) |
1029 | return -EFAULT; | 1160 | return -EFAULT; |
1030 | buf[len] = 0; | 1161 | buf[len] = 0; |
1031 | if (strcmp(buf, pkt_dev->dst_min) != 0) { | 1162 | if (strcmp(buf, pkt_dev->dst_min) != 0) { |
1032 | memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min)); | 1163 | memset(pkt_dev->dst_min, 0, sizeof(pkt_dev->dst_min)); |
1033 | strncpy(pkt_dev->dst_min, buf, len); | 1164 | strncpy(pkt_dev->dst_min, buf, len); |
1034 | pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); | 1165 | pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); |
1035 | pkt_dev->cur_daddr = pkt_dev->daddr_min; | 1166 | pkt_dev->cur_daddr = pkt_dev->daddr_min; |
1036 | } | 1167 | } |
1037 | if(debug) | 1168 | if (debug) |
1038 | printk("pktgen: dst_min set to: %s\n", pkt_dev->dst_min); | 1169 | printk("pktgen: dst_min set to: %s\n", |
1039 | i += len; | 1170 | pkt_dev->dst_min); |
1171 | i += len; | ||
1040 | sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min); | 1172 | sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min); |
1041 | return count; | 1173 | return count; |
1042 | } | 1174 | } |
1043 | if (!strcmp(name, "dst_max")) { | 1175 | if (!strcmp(name, "dst_max")) { |
1044 | len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); | 1176 | len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); |
1045 | if (len < 0) { return len; } | 1177 | if (len < 0) { |
1178 | return len; | ||
1179 | } | ||
1046 | 1180 | ||
1047 | if (copy_from_user(buf, &user_buffer[i], len)) | 1181 | if (copy_from_user(buf, &user_buffer[i], len)) |
1048 | return -EFAULT; | 1182 | return -EFAULT; |
1049 | 1183 | ||
1050 | buf[len] = 0; | 1184 | buf[len] = 0; |
1051 | if (strcmp(buf, pkt_dev->dst_max) != 0) { | 1185 | if (strcmp(buf, pkt_dev->dst_max) != 0) { |
1052 | memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max)); | 1186 | memset(pkt_dev->dst_max, 0, sizeof(pkt_dev->dst_max)); |
1053 | strncpy(pkt_dev->dst_max, buf, len); | 1187 | strncpy(pkt_dev->dst_max, buf, len); |
1054 | pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); | 1188 | pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); |
1055 | pkt_dev->cur_daddr = pkt_dev->daddr_max; | 1189 | pkt_dev->cur_daddr = pkt_dev->daddr_max; |
1056 | } | 1190 | } |
1057 | if(debug) | 1191 | if (debug) |
1058 | printk("pktgen: dst_max set to: %s\n", pkt_dev->dst_max); | 1192 | printk("pktgen: dst_max set to: %s\n", |
1193 | pkt_dev->dst_max); | ||
1059 | i += len; | 1194 | i += len; |
1060 | sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max); | 1195 | sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max); |
1061 | return count; | 1196 | return count; |
1062 | } | 1197 | } |
1063 | if (!strcmp(name, "dst6")) { | 1198 | if (!strcmp(name, "dst6")) { |
1064 | len = strn_len(&user_buffer[i], sizeof(buf) - 1); | 1199 | len = strn_len(&user_buffer[i], sizeof(buf) - 1); |
1065 | if (len < 0) return len; | 1200 | if (len < 0) |
1201 | return len; | ||
1066 | 1202 | ||
1067 | pkt_dev->flags |= F_IPV6; | 1203 | pkt_dev->flags |= F_IPV6; |
1068 | 1204 | ||
1069 | if (copy_from_user(buf, &user_buffer[i], len)) | 1205 | if (copy_from_user(buf, &user_buffer[i], len)) |
1070 | return -EFAULT; | 1206 | return -EFAULT; |
1071 | buf[len] = 0; | 1207 | buf[len] = 0; |
1072 | 1208 | ||
1073 | scan_ip6(buf, pkt_dev->in6_daddr.s6_addr); | 1209 | scan_ip6(buf, pkt_dev->in6_daddr.s6_addr); |
1074 | fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr); | 1210 | fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr); |
1075 | 1211 | ||
1076 | ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr); | 1212 | ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr); |
1077 | 1213 | ||
1078 | if(debug) | 1214 | if (debug) |
1079 | printk("pktgen: dst6 set to: %s\n", buf); | 1215 | printk("pktgen: dst6 set to: %s\n", buf); |
1080 | 1216 | ||
1081 | i += len; | 1217 | i += len; |
1082 | sprintf(pg_result, "OK: dst6=%s", buf); | 1218 | sprintf(pg_result, "OK: dst6=%s", buf); |
1083 | return count; | 1219 | return count; |
1084 | } | 1220 | } |
1085 | if (!strcmp(name, "dst6_min")) { | 1221 | if (!strcmp(name, "dst6_min")) { |
1086 | len = strn_len(&user_buffer[i], sizeof(buf) - 1); | 1222 | len = strn_len(&user_buffer[i], sizeof(buf) - 1); |
1087 | if (len < 0) return len; | 1223 | if (len < 0) |
1224 | return len; | ||
1088 | 1225 | ||
1089 | pkt_dev->flags |= F_IPV6; | 1226 | pkt_dev->flags |= F_IPV6; |
1090 | 1227 | ||
1091 | if (copy_from_user(buf, &user_buffer[i], len)) | 1228 | if (copy_from_user(buf, &user_buffer[i], len)) |
1092 | return -EFAULT; | 1229 | return -EFAULT; |
1093 | buf[len] = 0; | 1230 | buf[len] = 0; |
1094 | 1231 | ||
1095 | scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); | 1232 | scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); |
1096 | fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); | 1233 | fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); |
1097 | 1234 | ||
1098 | ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->min_in6_daddr); | 1235 | ipv6_addr_copy(&pkt_dev->cur_in6_daddr, |
1099 | if(debug) | 1236 | &pkt_dev->min_in6_daddr); |
1237 | if (debug) | ||
1100 | printk("pktgen: dst6_min set to: %s\n", buf); | 1238 | printk("pktgen: dst6_min set to: %s\n", buf); |
1101 | 1239 | ||
1102 | i += len; | 1240 | i += len; |
1103 | sprintf(pg_result, "OK: dst6_min=%s", buf); | 1241 | sprintf(pg_result, "OK: dst6_min=%s", buf); |
1104 | return count; | 1242 | return count; |
1105 | } | 1243 | } |
1106 | if (!strcmp(name, "dst6_max")) { | 1244 | if (!strcmp(name, "dst6_max")) { |
1107 | len = strn_len(&user_buffer[i], sizeof(buf) - 1); | 1245 | len = strn_len(&user_buffer[i], sizeof(buf) - 1); |
1108 | if (len < 0) return len; | 1246 | if (len < 0) |
1247 | return len; | ||
1109 | 1248 | ||
1110 | pkt_dev->flags |= F_IPV6; | 1249 | pkt_dev->flags |= F_IPV6; |
1111 | 1250 | ||
1112 | if (copy_from_user(buf, &user_buffer[i], len)) | 1251 | if (copy_from_user(buf, &user_buffer[i], len)) |
1113 | return -EFAULT; | 1252 | return -EFAULT; |
1114 | buf[len] = 0; | 1253 | buf[len] = 0; |
1115 | 1254 | ||
1116 | scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); | 1255 | scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); |
1117 | fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); | 1256 | fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); |
1118 | 1257 | ||
1119 | if(debug) | 1258 | if (debug) |
1120 | printk("pktgen: dst6_max set to: %s\n", buf); | 1259 | printk("pktgen: dst6_max set to: %s\n", buf); |
1121 | 1260 | ||
1122 | i += len; | 1261 | i += len; |
1123 | sprintf(pg_result, "OK: dst6_max=%s", buf); | 1262 | sprintf(pg_result, "OK: dst6_max=%s", buf); |
1124 | return count; | 1263 | return count; |
1125 | } | 1264 | } |
1126 | if (!strcmp(name, "src6")) { | 1265 | if (!strcmp(name, "src6")) { |
1127 | len = strn_len(&user_buffer[i], sizeof(buf) - 1); | 1266 | len = strn_len(&user_buffer[i], sizeof(buf) - 1); |
1128 | if (len < 0) return len; | 1267 | if (len < 0) |
1268 | return len; | ||
1129 | 1269 | ||
1130 | pkt_dev->flags |= F_IPV6; | 1270 | pkt_dev->flags |= F_IPV6; |
1131 | 1271 | ||
1132 | if (copy_from_user(buf, &user_buffer[i], len)) | 1272 | if (copy_from_user(buf, &user_buffer[i], len)) |
1133 | return -EFAULT; | 1273 | return -EFAULT; |
1134 | buf[len] = 0; | 1274 | buf[len] = 0; |
1135 | 1275 | ||
1136 | scan_ip6(buf, pkt_dev->in6_saddr.s6_addr); | 1276 | scan_ip6(buf, pkt_dev->in6_saddr.s6_addr); |
1137 | fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr); | 1277 | fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr); |
1138 | 1278 | ||
1139 | ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr); | 1279 | ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr); |
1140 | 1280 | ||
1141 | if(debug) | 1281 | if (debug) |
1142 | printk("pktgen: src6 set to: %s\n", buf); | 1282 | printk("pktgen: src6 set to: %s\n", buf); |
1143 | 1283 | ||
1144 | i += len; | 1284 | i += len; |
1145 | sprintf(pg_result, "OK: src6=%s", buf); | 1285 | sprintf(pg_result, "OK: src6=%s", buf); |
1146 | return count; | 1286 | return count; |
1147 | } | 1287 | } |
1148 | if (!strcmp(name, "src_min")) { | 1288 | if (!strcmp(name, "src_min")) { |
1149 | len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); | 1289 | len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); |
1150 | if (len < 0) { return len; } | 1290 | if (len < 0) { |
1151 | if (copy_from_user(buf, &user_buffer[i], len)) | 1291 | return len; |
1292 | } | ||
1293 | if (copy_from_user(buf, &user_buffer[i], len)) | ||
1152 | return -EFAULT; | 1294 | return -EFAULT; |
1153 | buf[len] = 0; | 1295 | buf[len] = 0; |
1154 | if (strcmp(buf, pkt_dev->src_min) != 0) { | 1296 | if (strcmp(buf, pkt_dev->src_min) != 0) { |
1155 | memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min)); | 1297 | memset(pkt_dev->src_min, 0, sizeof(pkt_dev->src_min)); |
1156 | strncpy(pkt_dev->src_min, buf, len); | 1298 | strncpy(pkt_dev->src_min, buf, len); |
1157 | pkt_dev->saddr_min = in_aton(pkt_dev->src_min); | 1299 | pkt_dev->saddr_min = in_aton(pkt_dev->src_min); |
1158 | pkt_dev->cur_saddr = pkt_dev->saddr_min; | 1300 | pkt_dev->cur_saddr = pkt_dev->saddr_min; |
1159 | } | 1301 | } |
1160 | if(debug) | 1302 | if (debug) |
1161 | printk("pktgen: src_min set to: %s\n", pkt_dev->src_min); | 1303 | printk("pktgen: src_min set to: %s\n", |
1304 | pkt_dev->src_min); | ||
1162 | i += len; | 1305 | i += len; |
1163 | sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min); | 1306 | sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min); |
1164 | return count; | 1307 | return count; |
1165 | } | 1308 | } |
1166 | if (!strcmp(name, "src_max")) { | 1309 | if (!strcmp(name, "src_max")) { |
1167 | len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); | 1310 | len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); |
1168 | if (len < 0) { return len; } | 1311 | if (len < 0) { |
1169 | if (copy_from_user(buf, &user_buffer[i], len)) | 1312 | return len; |
1313 | } | ||
1314 | if (copy_from_user(buf, &user_buffer[i], len)) | ||
1170 | return -EFAULT; | 1315 | return -EFAULT; |
1171 | buf[len] = 0; | 1316 | buf[len] = 0; |
1172 | if (strcmp(buf, pkt_dev->src_max) != 0) { | 1317 | if (strcmp(buf, pkt_dev->src_max) != 0) { |
1173 | memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max)); | 1318 | memset(pkt_dev->src_max, 0, sizeof(pkt_dev->src_max)); |
1174 | strncpy(pkt_dev->src_max, buf, len); | 1319 | strncpy(pkt_dev->src_max, buf, len); |
1175 | pkt_dev->saddr_max = in_aton(pkt_dev->src_max); | 1320 | pkt_dev->saddr_max = in_aton(pkt_dev->src_max); |
1176 | pkt_dev->cur_saddr = pkt_dev->saddr_max; | 1321 | pkt_dev->cur_saddr = pkt_dev->saddr_max; |
1177 | } | 1322 | } |
1178 | if(debug) | 1323 | if (debug) |
1179 | printk("pktgen: src_max set to: %s\n", pkt_dev->src_max); | 1324 | printk("pktgen: src_max set to: %s\n", |
1325 | pkt_dev->src_max); | ||
1180 | i += len; | 1326 | i += len; |
1181 | sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max); | 1327 | sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max); |
1182 | return count; | 1328 | return count; |
@@ -1186,15 +1332,17 @@ static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer | |||
1186 | unsigned char old_dmac[ETH_ALEN]; | 1332 | unsigned char old_dmac[ETH_ALEN]; |
1187 | unsigned char *m = pkt_dev->dst_mac; | 1333 | unsigned char *m = pkt_dev->dst_mac; |
1188 | memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN); | 1334 | memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN); |
1189 | 1335 | ||
1190 | len = strn_len(&user_buffer[i], sizeof(valstr) - 1); | 1336 | len = strn_len(&user_buffer[i], sizeof(valstr) - 1); |
1191 | if (len < 0) { return len; } | 1337 | if (len < 0) { |
1338 | return len; | ||
1339 | } | ||
1192 | memset(valstr, 0, sizeof(valstr)); | 1340 | memset(valstr, 0, sizeof(valstr)); |
1193 | if( copy_from_user(valstr, &user_buffer[i], len)) | 1341 | if (copy_from_user(valstr, &user_buffer[i], len)) |
1194 | return -EFAULT; | 1342 | return -EFAULT; |
1195 | i += len; | 1343 | i += len; |
1196 | 1344 | ||
1197 | for(*m = 0;*v && m < pkt_dev->dst_mac + 6; v++) { | 1345 | for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) { |
1198 | if (*v >= '0' && *v <= '9') { | 1346 | if (*v >= '0' && *v <= '9') { |
1199 | *m *= 16; | 1347 | *m *= 16; |
1200 | *m += *v - '0'; | 1348 | *m += *v - '0'; |
@@ -1216,7 +1364,7 @@ static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer | |||
1216 | /* Set up Dest MAC */ | 1364 | /* Set up Dest MAC */ |
1217 | if (compare_ether_addr(old_dmac, pkt_dev->dst_mac)) | 1365 | if (compare_ether_addr(old_dmac, pkt_dev->dst_mac)) |
1218 | memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); | 1366 | memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); |
1219 | 1367 | ||
1220 | sprintf(pg_result, "OK: dstmac"); | 1368 | sprintf(pg_result, "OK: dstmac"); |
1221 | return count; | 1369 | return count; |
1222 | } | 1370 | } |
@@ -1225,13 +1373,15 @@ static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer | |||
1225 | unsigned char *m = pkt_dev->src_mac; | 1373 | unsigned char *m = pkt_dev->src_mac; |
1226 | 1374 | ||
1227 | len = strn_len(&user_buffer[i], sizeof(valstr) - 1); | 1375 | len = strn_len(&user_buffer[i], sizeof(valstr) - 1); |
1228 | if (len < 0) { return len; } | 1376 | if (len < 0) { |
1377 | return len; | ||
1378 | } | ||
1229 | memset(valstr, 0, sizeof(valstr)); | 1379 | memset(valstr, 0, sizeof(valstr)); |
1230 | if( copy_from_user(valstr, &user_buffer[i], len)) | 1380 | if (copy_from_user(valstr, &user_buffer[i], len)) |
1231 | return -EFAULT; | 1381 | return -EFAULT; |
1232 | i += len; | 1382 | i += len; |
1233 | 1383 | ||
1234 | for(*m = 0;*v && m < pkt_dev->src_mac + 6; v++) { | 1384 | for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) { |
1235 | if (*v >= '0' && *v <= '9') { | 1385 | if (*v >= '0' && *v <= '9') { |
1236 | *m *= 16; | 1386 | *m *= 16; |
1237 | *m += *v - '0'; | 1387 | *m += *v - '0'; |
@@ -1248,21 +1398,23 @@ static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer | |||
1248 | m++; | 1398 | m++; |
1249 | *m = 0; | 1399 | *m = 0; |
1250 | } | 1400 | } |
1251 | } | 1401 | } |
1252 | 1402 | ||
1253 | sprintf(pg_result, "OK: srcmac"); | 1403 | sprintf(pg_result, "OK: srcmac"); |
1254 | return count; | 1404 | return count; |
1255 | } | 1405 | } |
1256 | 1406 | ||
1257 | if (!strcmp(name, "clear_counters")) { | 1407 | if (!strcmp(name, "clear_counters")) { |
1258 | pktgen_clear_counters(pkt_dev); | 1408 | pktgen_clear_counters(pkt_dev); |
1259 | sprintf(pg_result, "OK: Clearing counters.\n"); | 1409 | sprintf(pg_result, "OK: Clearing counters.\n"); |
1260 | return count; | 1410 | return count; |
1261 | } | 1411 | } |
1262 | 1412 | ||
1263 | if (!strcmp(name, "flows")) { | 1413 | if (!strcmp(name, "flows")) { |
1264 | len = num_arg(&user_buffer[i], 10, &value); | 1414 | len = num_arg(&user_buffer[i], 10, &value); |
1265 | if (len < 0) { return len; } | 1415 | if (len < 0) { |
1416 | return len; | ||
1417 | } | ||
1266 | i += len; | 1418 | i += len; |
1267 | if (value > MAX_CFLOWS) | 1419 | if (value > MAX_CFLOWS) |
1268 | value = MAX_CFLOWS; | 1420 | value = MAX_CFLOWS; |
@@ -1274,13 +1426,28 @@ static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer | |||
1274 | 1426 | ||
1275 | if (!strcmp(name, "flowlen")) { | 1427 | if (!strcmp(name, "flowlen")) { |
1276 | len = num_arg(&user_buffer[i], 10, &value); | 1428 | len = num_arg(&user_buffer[i], 10, &value); |
1277 | if (len < 0) { return len; } | 1429 | if (len < 0) { |
1430 | return len; | ||
1431 | } | ||
1278 | i += len; | 1432 | i += len; |
1279 | pkt_dev->lflow = value; | 1433 | pkt_dev->lflow = value; |
1280 | sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow); | 1434 | sprintf(pg_result, "OK: flowlen=%u", pkt_dev->lflow); |
1281 | return count; | 1435 | return count; |
1282 | } | 1436 | } |
1283 | 1437 | ||
1438 | if (!strcmp(name, "mpls")) { | ||
1439 | unsigned n, offset; | ||
1440 | len = get_labels(&user_buffer[i], pkt_dev); | ||
1441 | if (len < 0) { return len; } | ||
1442 | i += len; | ||
1443 | offset = sprintf(pg_result, "OK: mpls="); | ||
1444 | for(n = 0; n < pkt_dev->nr_labels; n++) | ||
1445 | offset += sprintf(pg_result + offset, | ||
1446 | "%08x%s", ntohl(pkt_dev->labels[n]), | ||
1447 | n == pkt_dev->nr_labels-1 ? "" : ","); | ||
1448 | return count; | ||
1449 | } | ||
1450 | |||
1284 | sprintf(pkt_dev->result, "No such parameter \"%s\"", name); | 1451 | sprintf(pkt_dev->result, "No such parameter \"%s\"", name); |
1285 | return -EINVAL; | 1452 | return -EINVAL; |
1286 | } | 1453 | } |
@@ -1291,35 +1458,35 @@ static int pktgen_if_open(struct inode *inode, struct file *file) | |||
1291 | } | 1458 | } |
1292 | 1459 | ||
1293 | static struct file_operations pktgen_if_fops = { | 1460 | static struct file_operations pktgen_if_fops = { |
1294 | .owner = THIS_MODULE, | 1461 | .owner = THIS_MODULE, |
1295 | .open = pktgen_if_open, | 1462 | .open = pktgen_if_open, |
1296 | .read = seq_read, | 1463 | .read = seq_read, |
1297 | .llseek = seq_lseek, | 1464 | .llseek = seq_lseek, |
1298 | .write = pktgen_if_write, | 1465 | .write = pktgen_if_write, |
1299 | .release = single_release, | 1466 | .release = single_release, |
1300 | }; | 1467 | }; |
1301 | 1468 | ||
1302 | static int pktgen_thread_show(struct seq_file *seq, void *v) | 1469 | static int pktgen_thread_show(struct seq_file *seq, void *v) |
1303 | { | 1470 | { |
1304 | struct pktgen_thread *t = seq->private; | 1471 | struct pktgen_thread *t = seq->private; |
1305 | struct pktgen_dev *pkt_dev = NULL; | 1472 | struct pktgen_dev *pkt_dev; |
1306 | 1473 | ||
1307 | BUG_ON(!t); | 1474 | BUG_ON(!t); |
1308 | 1475 | ||
1309 | seq_printf(seq, "Name: %s max_before_softirq: %d\n", | 1476 | seq_printf(seq, "Name: %s max_before_softirq: %d\n", |
1310 | t->name, t->max_before_softirq); | 1477 | t->name, t->max_before_softirq); |
1478 | |||
1479 | seq_printf(seq, "Running: "); | ||
1311 | 1480 | ||
1312 | seq_printf(seq, "Running: "); | 1481 | if_lock(t); |
1313 | 1482 | list_for_each_entry(pkt_dev, &t->if_list, list) | |
1314 | if_lock(t); | 1483 | if (pkt_dev->running) |
1315 | for(pkt_dev = t->if_list;pkt_dev; pkt_dev = pkt_dev->next) | ||
1316 | if(pkt_dev->running) | ||
1317 | seq_printf(seq, "%s ", pkt_dev->ifname); | 1484 | seq_printf(seq, "%s ", pkt_dev->ifname); |
1318 | |||
1319 | seq_printf(seq, "\nStopped: "); | ||
1320 | 1485 | ||
1321 | for(pkt_dev = t->if_list;pkt_dev; pkt_dev = pkt_dev->next) | 1486 | seq_printf(seq, "\nStopped: "); |
1322 | if(!pkt_dev->running) | 1487 | |
1488 | list_for_each_entry(pkt_dev, &t->if_list, list) | ||
1489 | if (!pkt_dev->running) | ||
1323 | seq_printf(seq, "%s ", pkt_dev->ifname); | 1490 | seq_printf(seq, "%s ", pkt_dev->ifname); |
1324 | 1491 | ||
1325 | if (t->result[0]) | 1492 | if (t->result[0]) |
@@ -1327,30 +1494,30 @@ static int pktgen_thread_show(struct seq_file *seq, void *v) | |||
1327 | else | 1494 | else |
1328 | seq_printf(seq, "\nResult: NA\n"); | 1495 | seq_printf(seq, "\nResult: NA\n"); |
1329 | 1496 | ||
1330 | if_unlock(t); | 1497 | if_unlock(t); |
1331 | 1498 | ||
1332 | return 0; | 1499 | return 0; |
1333 | } | 1500 | } |
1334 | 1501 | ||
1335 | static ssize_t pktgen_thread_write(struct file *file, | 1502 | static ssize_t pktgen_thread_write(struct file *file, |
1336 | const char __user *user_buffer, | 1503 | const char __user * user_buffer, |
1337 | size_t count, loff_t *offset) | 1504 | size_t count, loff_t * offset) |
1338 | { | 1505 | { |
1339 | struct seq_file *seq = (struct seq_file *) file->private_data; | 1506 | struct seq_file *seq = (struct seq_file *)file->private_data; |
1340 | struct pktgen_thread *t = seq->private; | 1507 | struct pktgen_thread *t = seq->private; |
1341 | int i = 0, max, len, ret; | 1508 | int i = 0, max, len, ret; |
1342 | char name[40]; | 1509 | char name[40]; |
1343 | char *pg_result; | 1510 | char *pg_result; |
1344 | unsigned long value = 0; | 1511 | unsigned long value = 0; |
1345 | 1512 | ||
1346 | if (count < 1) { | 1513 | if (count < 1) { |
1347 | // sprintf(pg_result, "Wrong command format"); | 1514 | // sprintf(pg_result, "Wrong command format"); |
1348 | return -EINVAL; | 1515 | return -EINVAL; |
1349 | } | 1516 | } |
1350 | 1517 | ||
1351 | max = count - i; | 1518 | max = count - i; |
1352 | len = count_trail_chars(&user_buffer[i], max); | 1519 | len = count_trail_chars(&user_buffer[i], max); |
1353 | if (len < 0) | 1520 | if (len < 0) |
1354 | return len; | 1521 | return len; |
1355 | 1522 | ||
1356 | i += len; | 1523 | i += len; |
@@ -1358,26 +1525,25 @@ static ssize_t pktgen_thread_write(struct file *file, | |||
1358 | /* Read variable name */ | 1525 | /* Read variable name */ |
1359 | 1526 | ||
1360 | len = strn_len(&user_buffer[i], sizeof(name) - 1); | 1527 | len = strn_len(&user_buffer[i], sizeof(name) - 1); |
1361 | if (len < 0) | 1528 | if (len < 0) |
1362 | return len; | 1529 | return len; |
1363 | 1530 | ||
1364 | memset(name, 0, sizeof(name)); | 1531 | memset(name, 0, sizeof(name)); |
1365 | if (copy_from_user(name, &user_buffer[i], len)) | 1532 | if (copy_from_user(name, &user_buffer[i], len)) |
1366 | return -EFAULT; | 1533 | return -EFAULT; |
1367 | i += len; | 1534 | i += len; |
1368 | 1535 | ||
1369 | max = count -i; | 1536 | max = count - i; |
1370 | len = count_trail_chars(&user_buffer[i], max); | 1537 | len = count_trail_chars(&user_buffer[i], max); |
1371 | if (len < 0) | 1538 | if (len < 0) |
1372 | return len; | 1539 | return len; |
1373 | 1540 | ||
1374 | i += len; | 1541 | i += len; |
1375 | 1542 | ||
1376 | if (debug) | 1543 | if (debug) |
1377 | printk("pktgen: t=%s, count=%lu\n", name, | 1544 | printk("pktgen: t=%s, count=%lu\n", name, (unsigned long)count); |
1378 | (unsigned long) count); | ||
1379 | 1545 | ||
1380 | if(!t) { | 1546 | if (!t) { |
1381 | printk("pktgen: ERROR: No thread\n"); | 1547 | printk("pktgen: ERROR: No thread\n"); |
1382 | ret = -EINVAL; | 1548 | ret = -EINVAL; |
1383 | goto out; | 1549 | goto out; |
@@ -1385,48 +1551,47 @@ static ssize_t pktgen_thread_write(struct file *file, | |||
1385 | 1551 | ||
1386 | pg_result = &(t->result[0]); | 1552 | pg_result = &(t->result[0]); |
1387 | 1553 | ||
1388 | if (!strcmp(name, "add_device")) { | 1554 | if (!strcmp(name, "add_device")) { |
1389 | char f[32]; | 1555 | char f[32]; |
1390 | memset(f, 0, 32); | 1556 | memset(f, 0, 32); |
1391 | len = strn_len(&user_buffer[i], sizeof(f) - 1); | 1557 | len = strn_len(&user_buffer[i], sizeof(f) - 1); |
1392 | if (len < 0) { | 1558 | if (len < 0) { |
1393 | ret = len; | 1559 | ret = len; |
1394 | goto out; | 1560 | goto out; |
1395 | } | 1561 | } |
1396 | if( copy_from_user(f, &user_buffer[i], len) ) | 1562 | if (copy_from_user(f, &user_buffer[i], len)) |
1397 | return -EFAULT; | 1563 | return -EFAULT; |
1398 | i += len; | 1564 | i += len; |
1399 | thread_lock(); | 1565 | mutex_lock(&pktgen_thread_lock); |
1400 | pktgen_add_device(t, f); | 1566 | pktgen_add_device(t, f); |
1401 | thread_unlock(); | 1567 | mutex_unlock(&pktgen_thread_lock); |
1402 | ret = count; | 1568 | ret = count; |
1403 | sprintf(pg_result, "OK: add_device=%s", f); | 1569 | sprintf(pg_result, "OK: add_device=%s", f); |
1404 | goto out; | 1570 | goto out; |
1405 | } | 1571 | } |
1406 | 1572 | ||
1407 | if (!strcmp(name, "rem_device_all")) { | 1573 | if (!strcmp(name, "rem_device_all")) { |
1408 | thread_lock(); | 1574 | mutex_lock(&pktgen_thread_lock); |
1409 | t->control |= T_REMDEV; | 1575 | t->control |= T_REMDEVALL; |
1410 | thread_unlock(); | 1576 | mutex_unlock(&pktgen_thread_lock); |
1411 | schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ | 1577 | schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ |
1412 | ret = count; | 1578 | ret = count; |
1413 | sprintf(pg_result, "OK: rem_device_all"); | 1579 | sprintf(pg_result, "OK: rem_device_all"); |
1414 | goto out; | 1580 | goto out; |
1415 | } | 1581 | } |
1416 | 1582 | ||
1417 | if (!strcmp(name, "max_before_softirq")) { | 1583 | if (!strcmp(name, "max_before_softirq")) { |
1418 | len = num_arg(&user_buffer[i], 10, &value); | 1584 | len = num_arg(&user_buffer[i], 10, &value); |
1419 | thread_lock(); | 1585 | mutex_lock(&pktgen_thread_lock); |
1420 | t->max_before_softirq = value; | 1586 | t->max_before_softirq = value; |
1421 | thread_unlock(); | 1587 | mutex_unlock(&pktgen_thread_lock); |
1422 | ret = count; | 1588 | ret = count; |
1423 | sprintf(pg_result, "OK: max_before_softirq=%lu", value); | 1589 | sprintf(pg_result, "OK: max_before_softirq=%lu", value); |
1424 | goto out; | 1590 | goto out; |
1425 | } | 1591 | } |
1426 | 1592 | ||
1427 | ret = -EINVAL; | 1593 | ret = -EINVAL; |
1428 | out: | 1594 | out: |
1429 | |||
1430 | return ret; | 1595 | return ret; |
1431 | } | 1596 | } |
1432 | 1597 | ||
@@ -1436,47 +1601,78 @@ static int pktgen_thread_open(struct inode *inode, struct file *file) | |||
1436 | } | 1601 | } |
1437 | 1602 | ||
1438 | static struct file_operations pktgen_thread_fops = { | 1603 | static struct file_operations pktgen_thread_fops = { |
1439 | .owner = THIS_MODULE, | 1604 | .owner = THIS_MODULE, |
1440 | .open = pktgen_thread_open, | 1605 | .open = pktgen_thread_open, |
1441 | .read = seq_read, | 1606 | .read = seq_read, |
1442 | .llseek = seq_lseek, | 1607 | .llseek = seq_lseek, |
1443 | .write = pktgen_thread_write, | 1608 | .write = pktgen_thread_write, |
1444 | .release = single_release, | 1609 | .release = single_release, |
1445 | }; | 1610 | }; |
1446 | 1611 | ||
1447 | /* Think find or remove for NN */ | 1612 | /* Think find or remove for NN */ |
1448 | static struct pktgen_dev *__pktgen_NN_threads(const char* ifname, int remove) | 1613 | static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove) |
1449 | { | 1614 | { |
1450 | struct pktgen_thread *t; | 1615 | struct pktgen_thread *t; |
1451 | struct pktgen_dev *pkt_dev = NULL; | 1616 | struct pktgen_dev *pkt_dev = NULL; |
1452 | 1617 | ||
1453 | t = pktgen_threads; | 1618 | list_for_each_entry(t, &pktgen_threads, th_list) { |
1454 | |||
1455 | while (t) { | ||
1456 | pkt_dev = pktgen_find_dev(t, ifname); | 1619 | pkt_dev = pktgen_find_dev(t, ifname); |
1457 | if (pkt_dev) { | 1620 | if (pkt_dev) { |
1458 | if(remove) { | 1621 | if (remove) { |
1459 | if_lock(t); | 1622 | if_lock(t); |
1460 | pktgen_remove_device(t, pkt_dev); | 1623 | pkt_dev->removal_mark = 1; |
1461 | if_unlock(t); | 1624 | t->control |= T_REMDEV; |
1462 | } | 1625 | if_unlock(t); |
1626 | } | ||
1463 | break; | 1627 | break; |
1464 | } | 1628 | } |
1465 | t = t->next; | ||
1466 | } | 1629 | } |
1467 | return pkt_dev; | 1630 | return pkt_dev; |
1468 | } | 1631 | } |
1469 | 1632 | ||
1470 | static struct pktgen_dev *pktgen_NN_threads(const char* ifname, int remove) | 1633 | /* |
1634 | * mark a device for removal | ||
1635 | */ | ||
1636 | static int pktgen_mark_device(const char *ifname) | ||
1471 | { | 1637 | { |
1472 | struct pktgen_dev *pkt_dev = NULL; | 1638 | struct pktgen_dev *pkt_dev = NULL; |
1473 | thread_lock(); | 1639 | const int max_tries = 10, msec_per_try = 125; |
1474 | pkt_dev = __pktgen_NN_threads(ifname, remove); | 1640 | int i = 0; |
1475 | thread_unlock(); | 1641 | int ret = 0; |
1476 | return pkt_dev; | 1642 | |
1643 | mutex_lock(&pktgen_thread_lock); | ||
1644 | PG_DEBUG(printk("pktgen: pktgen_mark_device marking %s for removal\n", | ||
1645 | ifname)); | ||
1646 | |||
1647 | while (1) { | ||
1648 | |||
1649 | pkt_dev = __pktgen_NN_threads(ifname, REMOVE); | ||
1650 | if (pkt_dev == NULL) | ||
1651 | break; /* success */ | ||
1652 | |||
1653 | mutex_unlock(&pktgen_thread_lock); | ||
1654 | PG_DEBUG(printk("pktgen: pktgen_mark_device waiting for %s " | ||
1655 | "to disappear....\n", ifname)); | ||
1656 | schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try)); | ||
1657 | mutex_lock(&pktgen_thread_lock); | ||
1658 | |||
1659 | if (++i >= max_tries) { | ||
1660 | printk("pktgen_mark_device: timed out after waiting " | ||
1661 | "%d msec for device %s to be removed\n", | ||
1662 | msec_per_try * i, ifname); | ||
1663 | ret = 1; | ||
1664 | break; | ||
1665 | } | ||
1666 | |||
1667 | } | ||
1668 | |||
1669 | mutex_unlock(&pktgen_thread_lock); | ||
1670 | |||
1671 | return ret; | ||
1477 | } | 1672 | } |
1478 | 1673 | ||
1479 | static int pktgen_device_event(struct notifier_block *unused, unsigned long event, void *ptr) | 1674 | static int pktgen_device_event(struct notifier_block *unused, |
1675 | unsigned long event, void *ptr) | ||
1480 | { | 1676 | { |
1481 | struct net_device *dev = (struct net_device *)(ptr); | 1677 | struct net_device *dev = (struct net_device *)(ptr); |
1482 | 1678 | ||
@@ -1491,9 +1687,9 @@ static int pktgen_device_event(struct notifier_block *unused, unsigned long even | |||
1491 | case NETDEV_UP: | 1687 | case NETDEV_UP: |
1492 | /* Ignore for now */ | 1688 | /* Ignore for now */ |
1493 | break; | 1689 | break; |
1494 | 1690 | ||
1495 | case NETDEV_UNREGISTER: | 1691 | case NETDEV_UNREGISTER: |
1496 | pktgen_NN_threads(dev->name, REMOVE); | 1692 | pktgen_mark_device(dev->name); |
1497 | break; | 1693 | break; |
1498 | }; | 1694 | }; |
1499 | 1695 | ||
@@ -1502,15 +1698,16 @@ static int pktgen_device_event(struct notifier_block *unused, unsigned long even | |||
1502 | 1698 | ||
1503 | /* Associate pktgen_dev with a device. */ | 1699 | /* Associate pktgen_dev with a device. */ |
1504 | 1700 | ||
1505 | static struct net_device* pktgen_setup_dev(struct pktgen_dev *pkt_dev) { | 1701 | static struct net_device *pktgen_setup_dev(struct pktgen_dev *pkt_dev) |
1702 | { | ||
1506 | struct net_device *odev; | 1703 | struct net_device *odev; |
1507 | 1704 | ||
1508 | /* Clean old setups */ | 1705 | /* Clean old setups */ |
1509 | 1706 | ||
1510 | if (pkt_dev->odev) { | 1707 | if (pkt_dev->odev) { |
1511 | dev_put(pkt_dev->odev); | 1708 | dev_put(pkt_dev->odev); |
1512 | pkt_dev->odev = NULL; | 1709 | pkt_dev->odev = NULL; |
1513 | } | 1710 | } |
1514 | 1711 | ||
1515 | odev = dev_get_by_name(pkt_dev->ifname); | 1712 | odev = dev_get_by_name(pkt_dev->ifname); |
1516 | 1713 | ||
@@ -1519,7 +1716,8 @@ static struct net_device* pktgen_setup_dev(struct pktgen_dev *pkt_dev) { | |||
1519 | goto out; | 1716 | goto out; |
1520 | } | 1717 | } |
1521 | if (odev->type != ARPHRD_ETHER) { | 1718 | if (odev->type != ARPHRD_ETHER) { |
1522 | printk("pktgen: not an ethernet device: \"%s\"\n", pkt_dev->ifname); | 1719 | printk("pktgen: not an ethernet device: \"%s\"\n", |
1720 | pkt_dev->ifname); | ||
1523 | goto out_put; | 1721 | goto out_put; |
1524 | } | 1722 | } |
1525 | if (!netif_running(odev)) { | 1723 | if (!netif_running(odev)) { |
@@ -1527,13 +1725,13 @@ static struct net_device* pktgen_setup_dev(struct pktgen_dev *pkt_dev) { | |||
1527 | goto out_put; | 1725 | goto out_put; |
1528 | } | 1726 | } |
1529 | pkt_dev->odev = odev; | 1727 | pkt_dev->odev = odev; |
1530 | 1728 | ||
1531 | return pkt_dev->odev; | 1729 | return pkt_dev->odev; |
1532 | 1730 | ||
1533 | out_put: | 1731 | out_put: |
1534 | dev_put(odev); | 1732 | dev_put(odev); |
1535 | out: | 1733 | out: |
1536 | return NULL; | 1734 | return NULL; |
1537 | 1735 | ||
1538 | } | 1736 | } |
1539 | 1737 | ||
@@ -1543,59 +1741,64 @@ out: | |||
1543 | static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) | 1741 | static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) |
1544 | { | 1742 | { |
1545 | /* Try once more, just in case it works now. */ | 1743 | /* Try once more, just in case it works now. */ |
1546 | if (!pkt_dev->odev) | 1744 | if (!pkt_dev->odev) |
1547 | pktgen_setup_dev(pkt_dev); | 1745 | pktgen_setup_dev(pkt_dev); |
1548 | 1746 | ||
1549 | if (!pkt_dev->odev) { | 1747 | if (!pkt_dev->odev) { |
1550 | printk("pktgen: ERROR: pkt_dev->odev == NULL in setup_inject.\n"); | 1748 | printk("pktgen: ERROR: pkt_dev->odev == NULL in setup_inject.\n"); |
1551 | sprintf(pkt_dev->result, "ERROR: pkt_dev->odev == NULL in setup_inject.\n"); | 1749 | sprintf(pkt_dev->result, |
1552 | return; | 1750 | "ERROR: pkt_dev->odev == NULL in setup_inject.\n"); |
1553 | } | 1751 | return; |
1554 | 1752 | } | |
1555 | /* Default to the interface's mac if not explicitly set. */ | 1753 | |
1754 | /* Default to the interface's mac if not explicitly set. */ | ||
1556 | 1755 | ||
1557 | if (is_zero_ether_addr(pkt_dev->src_mac)) | 1756 | if (is_zero_ether_addr(pkt_dev->src_mac)) |
1558 | memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN); | 1757 | memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN); |
1559 | 1758 | ||
1560 | /* Set up Dest MAC */ | 1759 | /* Set up Dest MAC */ |
1561 | memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); | 1760 | memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); |
1562 | 1761 | ||
1563 | /* Set up pkt size */ | 1762 | /* Set up pkt size */ |
1564 | pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; | 1763 | pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; |
1565 | 1764 | ||
1566 | if(pkt_dev->flags & F_IPV6) { | 1765 | if (pkt_dev->flags & F_IPV6) { |
1567 | /* | 1766 | /* |
1568 | * Skip this automatic address setting until locks or functions | 1767 | * Skip this automatic address setting until locks or functions |
1569 | * gets exported | 1768 | * gets exported |
1570 | */ | 1769 | */ |
1571 | 1770 | ||
1572 | #ifdef NOTNOW | 1771 | #ifdef NOTNOW |
1573 | int i, set = 0, err=1; | 1772 | int i, set = 0, err = 1; |
1574 | struct inet6_dev *idev; | 1773 | struct inet6_dev *idev; |
1575 | 1774 | ||
1576 | for(i=0; i< IN6_ADDR_HSIZE; i++) | 1775 | for (i = 0; i < IN6_ADDR_HSIZE; i++) |
1577 | if(pkt_dev->cur_in6_saddr.s6_addr[i]) { | 1776 | if (pkt_dev->cur_in6_saddr.s6_addr[i]) { |
1578 | set = 1; | 1777 | set = 1; |
1579 | break; | 1778 | break; |
1580 | } | 1779 | } |
1581 | 1780 | ||
1582 | if(!set) { | 1781 | if (!set) { |
1583 | 1782 | ||
1584 | /* | 1783 | /* |
1585 | * Use linklevel address if unconfigured. | 1784 | * Use linklevel address if unconfigured. |
1586 | * | 1785 | * |
1587 | * use ipv6_get_lladdr if/when it's get exported | 1786 | * use ipv6_get_lladdr if/when it's get exported |
1588 | */ | 1787 | */ |
1589 | 1788 | ||
1590 | |||
1591 | read_lock(&addrconf_lock); | 1789 | read_lock(&addrconf_lock); |
1592 | if ((idev = __in6_dev_get(pkt_dev->odev)) != NULL) { | 1790 | if ((idev = __in6_dev_get(pkt_dev->odev)) != NULL) { |
1593 | struct inet6_ifaddr *ifp; | 1791 | struct inet6_ifaddr *ifp; |
1594 | 1792 | ||
1595 | read_lock_bh(&idev->lock); | 1793 | read_lock_bh(&idev->lock); |
1596 | for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { | 1794 | for (ifp = idev->addr_list; ifp; |
1597 | if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { | 1795 | ifp = ifp->if_next) { |
1598 | ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &ifp->addr); | 1796 | if (ifp->scope == IFA_LINK |
1797 | && !(ifp-> | ||
1798 | flags & IFA_F_TENTATIVE)) { | ||
1799 | ipv6_addr_copy(&pkt_dev-> | ||
1800 | cur_in6_saddr, | ||
1801 | &ifp->addr); | ||
1599 | err = 0; | 1802 | err = 0; |
1600 | break; | 1803 | break; |
1601 | } | 1804 | } |
@@ -1603,28 +1806,28 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) | |||
1603 | read_unlock_bh(&idev->lock); | 1806 | read_unlock_bh(&idev->lock); |
1604 | } | 1807 | } |
1605 | read_unlock(&addrconf_lock); | 1808 | read_unlock(&addrconf_lock); |
1606 | if(err) printk("pktgen: ERROR: IPv6 link address not availble.\n"); | 1809 | if (err) |
1810 | printk("pktgen: ERROR: IPv6 link address not availble.\n"); | ||
1607 | } | 1811 | } |
1608 | #endif | 1812 | #endif |
1609 | } | 1813 | } else { |
1610 | else { | ||
1611 | pkt_dev->saddr_min = 0; | 1814 | pkt_dev->saddr_min = 0; |
1612 | pkt_dev->saddr_max = 0; | 1815 | pkt_dev->saddr_max = 0; |
1613 | if (strlen(pkt_dev->src_min) == 0) { | 1816 | if (strlen(pkt_dev->src_min) == 0) { |
1614 | 1817 | ||
1615 | struct in_device *in_dev; | 1818 | struct in_device *in_dev; |
1616 | 1819 | ||
1617 | rcu_read_lock(); | 1820 | rcu_read_lock(); |
1618 | in_dev = __in_dev_get_rcu(pkt_dev->odev); | 1821 | in_dev = __in_dev_get_rcu(pkt_dev->odev); |
1619 | if (in_dev) { | 1822 | if (in_dev) { |
1620 | if (in_dev->ifa_list) { | 1823 | if (in_dev->ifa_list) { |
1621 | pkt_dev->saddr_min = in_dev->ifa_list->ifa_address; | 1824 | pkt_dev->saddr_min = |
1825 | in_dev->ifa_list->ifa_address; | ||
1622 | pkt_dev->saddr_max = pkt_dev->saddr_min; | 1826 | pkt_dev->saddr_max = pkt_dev->saddr_min; |
1623 | } | 1827 | } |
1624 | } | 1828 | } |
1625 | rcu_read_unlock(); | 1829 | rcu_read_unlock(); |
1626 | } | 1830 | } else { |
1627 | else { | ||
1628 | pkt_dev->saddr_min = in_aton(pkt_dev->src_min); | 1831 | pkt_dev->saddr_min = in_aton(pkt_dev->src_min); |
1629 | pkt_dev->saddr_max = in_aton(pkt_dev->src_max); | 1832 | pkt_dev->saddr_max = in_aton(pkt_dev->src_max); |
1630 | } | 1833 | } |
@@ -1632,13 +1835,13 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) | |||
1632 | pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); | 1835 | pkt_dev->daddr_min = in_aton(pkt_dev->dst_min); |
1633 | pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); | 1836 | pkt_dev->daddr_max = in_aton(pkt_dev->dst_max); |
1634 | } | 1837 | } |
1635 | /* Initialize current values. */ | 1838 | /* Initialize current values. */ |
1636 | pkt_dev->cur_dst_mac_offset = 0; | 1839 | pkt_dev->cur_dst_mac_offset = 0; |
1637 | pkt_dev->cur_src_mac_offset = 0; | 1840 | pkt_dev->cur_src_mac_offset = 0; |
1638 | pkt_dev->cur_saddr = pkt_dev->saddr_min; | 1841 | pkt_dev->cur_saddr = pkt_dev->saddr_min; |
1639 | pkt_dev->cur_daddr = pkt_dev->daddr_min; | 1842 | pkt_dev->cur_daddr = pkt_dev->daddr_min; |
1640 | pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; | 1843 | pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; |
1641 | pkt_dev->cur_udp_src = pkt_dev->udp_src_min; | 1844 | pkt_dev->cur_udp_src = pkt_dev->udp_src_min; |
1642 | pkt_dev->nflows = 0; | 1845 | pkt_dev->nflows = 0; |
1643 | } | 1846 | } |
1644 | 1847 | ||
@@ -1651,7 +1854,7 @@ static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us) | |||
1651 | printk(KERN_INFO "sleeping for %d\n", (int)(spin_until_us - now)); | 1854 | printk(KERN_INFO "sleeping for %d\n", (int)(spin_until_us - now)); |
1652 | while (now < spin_until_us) { | 1855 | while (now < spin_until_us) { |
1653 | /* TODO: optimize sleeping behavior */ | 1856 | /* TODO: optimize sleeping behavior */ |
1654 | if (spin_until_us - now > jiffies_to_usecs(1)+1) | 1857 | if (spin_until_us - now > jiffies_to_usecs(1) + 1) |
1655 | schedule_timeout_interruptible(1); | 1858 | schedule_timeout_interruptible(1); |
1656 | else if (spin_until_us - now > 100) { | 1859 | else if (spin_until_us - now > 100) { |
1657 | do_softirq(); | 1860 | do_softirq(); |
@@ -1667,102 +1870,119 @@ static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us) | |||
1667 | pkt_dev->idle_acc += now - start; | 1870 | pkt_dev->idle_acc += now - start; |
1668 | } | 1871 | } |
1669 | 1872 | ||
1670 | |||
1671 | /* Increment/randomize headers according to flags and current values | 1873 | /* Increment/randomize headers according to flags and current values |
1672 | * for IP src/dest, UDP src/dst port, MAC-Addr src/dst | 1874 | * for IP src/dest, UDP src/dst port, MAC-Addr src/dst |
1673 | */ | 1875 | */ |
1674 | static void mod_cur_headers(struct pktgen_dev *pkt_dev) { | 1876 | static void mod_cur_headers(struct pktgen_dev *pkt_dev) |
1675 | __u32 imn; | 1877 | { |
1676 | __u32 imx; | 1878 | __u32 imn; |
1677 | int flow = 0; | 1879 | __u32 imx; |
1880 | int flow = 0; | ||
1678 | 1881 | ||
1679 | if(pkt_dev->cflows) { | 1882 | if (pkt_dev->cflows) { |
1680 | flow = pktgen_random() % pkt_dev->cflows; | 1883 | flow = pktgen_random() % pkt_dev->cflows; |
1681 | 1884 | ||
1682 | if (pkt_dev->flows[flow].count > pkt_dev->lflow) | 1885 | if (pkt_dev->flows[flow].count > pkt_dev->lflow) |
1683 | pkt_dev->flows[flow].count = 0; | 1886 | pkt_dev->flows[flow].count = 0; |
1684 | } | 1887 | } |
1685 | |||
1686 | 1888 | ||
1687 | /* Deal with source MAC */ | 1889 | /* Deal with source MAC */ |
1688 | if (pkt_dev->src_mac_count > 1) { | 1890 | if (pkt_dev->src_mac_count > 1) { |
1689 | __u32 mc; | 1891 | __u32 mc; |
1690 | __u32 tmp; | 1892 | __u32 tmp; |
1691 | 1893 | ||
1692 | if (pkt_dev->flags & F_MACSRC_RND) | 1894 | if (pkt_dev->flags & F_MACSRC_RND) |
1693 | mc = pktgen_random() % (pkt_dev->src_mac_count); | 1895 | mc = pktgen_random() % (pkt_dev->src_mac_count); |
1694 | else { | 1896 | else { |
1695 | mc = pkt_dev->cur_src_mac_offset++; | 1897 | mc = pkt_dev->cur_src_mac_offset++; |
1696 | if (pkt_dev->cur_src_mac_offset > pkt_dev->src_mac_count) | 1898 | if (pkt_dev->cur_src_mac_offset > |
1697 | pkt_dev->cur_src_mac_offset = 0; | 1899 | pkt_dev->src_mac_count) |
1698 | } | 1900 | pkt_dev->cur_src_mac_offset = 0; |
1699 | 1901 | } | |
1700 | tmp = pkt_dev->src_mac[5] + (mc & 0xFF); | 1902 | |
1701 | pkt_dev->hh[11] = tmp; | 1903 | tmp = pkt_dev->src_mac[5] + (mc & 0xFF); |
1702 | tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); | 1904 | pkt_dev->hh[11] = tmp; |
1703 | pkt_dev->hh[10] = tmp; | 1905 | tmp = (pkt_dev->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); |
1704 | tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); | 1906 | pkt_dev->hh[10] = tmp; |
1705 | pkt_dev->hh[9] = tmp; | 1907 | tmp = (pkt_dev->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); |
1706 | tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); | 1908 | pkt_dev->hh[9] = tmp; |
1707 | pkt_dev->hh[8] = tmp; | 1909 | tmp = (pkt_dev->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); |
1708 | tmp = (pkt_dev->src_mac[1] + (tmp >> 8)); | 1910 | pkt_dev->hh[8] = tmp; |
1709 | pkt_dev->hh[7] = tmp; | 1911 | tmp = (pkt_dev->src_mac[1] + (tmp >> 8)); |
1710 | } | 1912 | pkt_dev->hh[7] = tmp; |
1711 | 1913 | } | |
1712 | /* Deal with Destination MAC */ | 1914 | |
1713 | if (pkt_dev->dst_mac_count > 1) { | 1915 | /* Deal with Destination MAC */ |
1714 | __u32 mc; | 1916 | if (pkt_dev->dst_mac_count > 1) { |
1715 | __u32 tmp; | 1917 | __u32 mc; |
1716 | 1918 | __u32 tmp; | |
1717 | if (pkt_dev->flags & F_MACDST_RND) | 1919 | |
1718 | mc = pktgen_random() % (pkt_dev->dst_mac_count); | 1920 | if (pkt_dev->flags & F_MACDST_RND) |
1719 | 1921 | mc = pktgen_random() % (pkt_dev->dst_mac_count); | |
1720 | else { | 1922 | |
1721 | mc = pkt_dev->cur_dst_mac_offset++; | 1923 | else { |
1722 | if (pkt_dev->cur_dst_mac_offset > pkt_dev->dst_mac_count) { | 1924 | mc = pkt_dev->cur_dst_mac_offset++; |
1723 | pkt_dev->cur_dst_mac_offset = 0; | 1925 | if (pkt_dev->cur_dst_mac_offset > |
1724 | } | 1926 | pkt_dev->dst_mac_count) { |
1725 | } | 1927 | pkt_dev->cur_dst_mac_offset = 0; |
1726 | 1928 | } | |
1727 | tmp = pkt_dev->dst_mac[5] + (mc & 0xFF); | 1929 | } |
1728 | pkt_dev->hh[5] = tmp; | 1930 | |
1729 | tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); | 1931 | tmp = pkt_dev->dst_mac[5] + (mc & 0xFF); |
1730 | pkt_dev->hh[4] = tmp; | 1932 | pkt_dev->hh[5] = tmp; |
1731 | tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); | 1933 | tmp = (pkt_dev->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8)); |
1732 | pkt_dev->hh[3] = tmp; | 1934 | pkt_dev->hh[4] = tmp; |
1733 | tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); | 1935 | tmp = (pkt_dev->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8)); |
1734 | pkt_dev->hh[2] = tmp; | 1936 | pkt_dev->hh[3] = tmp; |
1735 | tmp = (pkt_dev->dst_mac[1] + (tmp >> 8)); | 1937 | tmp = (pkt_dev->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8)); |
1736 | pkt_dev->hh[1] = tmp; | 1938 | pkt_dev->hh[2] = tmp; |
1737 | } | 1939 | tmp = (pkt_dev->dst_mac[1] + (tmp >> 8)); |
1738 | 1940 | pkt_dev->hh[1] = tmp; | |
1739 | if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { | 1941 | } |
1740 | if (pkt_dev->flags & F_UDPSRC_RND) | 1942 | |
1741 | pkt_dev->cur_udp_src = ((pktgen_random() % (pkt_dev->udp_src_max - pkt_dev->udp_src_min)) + pkt_dev->udp_src_min); | 1943 | if (pkt_dev->flags & F_MPLS_RND) { |
1742 | 1944 | unsigned i; | |
1743 | else { | 1945 | for(i = 0; i < pkt_dev->nr_labels; i++) |
1946 | if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM) | ||
1947 | pkt_dev->labels[i] = MPLS_STACK_BOTTOM | | ||
1948 | (pktgen_random() & | ||
1949 | htonl(0x000fffff)); | ||
1950 | } | ||
1951 | |||
1952 | if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) { | ||
1953 | if (pkt_dev->flags & F_UDPSRC_RND) | ||
1954 | pkt_dev->cur_udp_src = | ||
1955 | ((pktgen_random() % | ||
1956 | (pkt_dev->udp_src_max - pkt_dev->udp_src_min)) + | ||
1957 | pkt_dev->udp_src_min); | ||
1958 | |||
1959 | else { | ||
1744 | pkt_dev->cur_udp_src++; | 1960 | pkt_dev->cur_udp_src++; |
1745 | if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max) | 1961 | if (pkt_dev->cur_udp_src >= pkt_dev->udp_src_max) |
1746 | pkt_dev->cur_udp_src = pkt_dev->udp_src_min; | 1962 | pkt_dev->cur_udp_src = pkt_dev->udp_src_min; |
1747 | } | 1963 | } |
1748 | } | 1964 | } |
1749 | 1965 | ||
1750 | if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) { | 1966 | if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) { |
1751 | if (pkt_dev->flags & F_UDPDST_RND) { | 1967 | if (pkt_dev->flags & F_UDPDST_RND) { |
1752 | pkt_dev->cur_udp_dst = ((pktgen_random() % (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)) + pkt_dev->udp_dst_min); | 1968 | pkt_dev->cur_udp_dst = |
1753 | } | 1969 | ((pktgen_random() % |
1754 | else { | 1970 | (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)) + |
1971 | pkt_dev->udp_dst_min); | ||
1972 | } else { | ||
1755 | pkt_dev->cur_udp_dst++; | 1973 | pkt_dev->cur_udp_dst++; |
1756 | if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max) | 1974 | if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max) |
1757 | pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; | 1975 | pkt_dev->cur_udp_dst = pkt_dev->udp_dst_min; |
1758 | } | 1976 | } |
1759 | } | 1977 | } |
1760 | 1978 | ||
1761 | if (!(pkt_dev->flags & F_IPV6)) { | 1979 | if (!(pkt_dev->flags & F_IPV6)) { |
1762 | 1980 | ||
1763 | if ((imn = ntohl(pkt_dev->saddr_min)) < (imx = ntohl(pkt_dev->saddr_max))) { | 1981 | if ((imn = ntohl(pkt_dev->saddr_min)) < (imx = |
1982 | ntohl(pkt_dev-> | ||
1983 | saddr_max))) { | ||
1764 | __u32 t; | 1984 | __u32 t; |
1765 | if (pkt_dev->flags & F_IPSRC_RND) | 1985 | if (pkt_dev->flags & F_IPSRC_RND) |
1766 | t = ((pktgen_random() % (imx - imn)) + imn); | 1986 | t = ((pktgen_random() % (imx - imn)) + imn); |
1767 | else { | 1987 | else { |
1768 | t = ntohl(pkt_dev->cur_saddr); | 1988 | t = ntohl(pkt_dev->cur_saddr); |
@@ -1773,25 +1993,32 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) { | |||
1773 | } | 1993 | } |
1774 | pkt_dev->cur_saddr = htonl(t); | 1994 | pkt_dev->cur_saddr = htonl(t); |
1775 | } | 1995 | } |
1776 | 1996 | ||
1777 | if (pkt_dev->cflows && pkt_dev->flows[flow].count != 0) { | 1997 | if (pkt_dev->cflows && pkt_dev->flows[flow].count != 0) { |
1778 | pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr; | 1998 | pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr; |
1779 | } else { | 1999 | } else { |
1780 | 2000 | ||
1781 | if ((imn = ntohl(pkt_dev->daddr_min)) < (imx = ntohl(pkt_dev->daddr_max))) { | 2001 | if ((imn = ntohl(pkt_dev->daddr_min)) < (imx = |
2002 | ntohl(pkt_dev-> | ||
2003 | daddr_max))) | ||
2004 | { | ||
1782 | __u32 t; | 2005 | __u32 t; |
1783 | if (pkt_dev->flags & F_IPDST_RND) { | 2006 | if (pkt_dev->flags & F_IPDST_RND) { |
1784 | 2007 | ||
1785 | t = ((pktgen_random() % (imx - imn)) + imn); | 2008 | t = ((pktgen_random() % (imx - imn)) + |
2009 | imn); | ||
1786 | t = htonl(t); | 2010 | t = htonl(t); |
1787 | 2011 | ||
1788 | while( LOOPBACK(t) || MULTICAST(t) || BADCLASS(t) || ZERONET(t) || LOCAL_MCAST(t) ) { | 2012 | while (LOOPBACK(t) || MULTICAST(t) |
1789 | t = ((pktgen_random() % (imx - imn)) + imn); | 2013 | || BADCLASS(t) || ZERONET(t) |
2014 | || LOCAL_MCAST(t)) { | ||
2015 | t = ((pktgen_random() % | ||
2016 | (imx - imn)) + imn); | ||
1790 | t = htonl(t); | 2017 | t = htonl(t); |
1791 | } | 2018 | } |
1792 | pkt_dev->cur_daddr = t; | 2019 | pkt_dev->cur_daddr = t; |
1793 | } | 2020 | } |
1794 | 2021 | ||
1795 | else { | 2022 | else { |
1796 | t = ntohl(pkt_dev->cur_daddr); | 2023 | t = ntohl(pkt_dev->cur_daddr); |
1797 | t++; | 2024 | t++; |
@@ -1801,67 +2028,82 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev) { | |||
1801 | pkt_dev->cur_daddr = htonl(t); | 2028 | pkt_dev->cur_daddr = htonl(t); |
1802 | } | 2029 | } |
1803 | } | 2030 | } |
1804 | if(pkt_dev->cflows) { | 2031 | if (pkt_dev->cflows) { |
1805 | pkt_dev->flows[flow].cur_daddr = pkt_dev->cur_daddr; | 2032 | pkt_dev->flows[flow].cur_daddr = |
2033 | pkt_dev->cur_daddr; | ||
1806 | pkt_dev->nflows++; | 2034 | pkt_dev->nflows++; |
1807 | } | 2035 | } |
1808 | } | 2036 | } |
1809 | } | 2037 | } else { /* IPV6 * */ |
1810 | else /* IPV6 * */ | 2038 | |
1811 | { | 2039 | if (pkt_dev->min_in6_daddr.s6_addr32[0] == 0 && |
1812 | if(pkt_dev->min_in6_daddr.s6_addr32[0] == 0 && | 2040 | pkt_dev->min_in6_daddr.s6_addr32[1] == 0 && |
1813 | pkt_dev->min_in6_daddr.s6_addr32[1] == 0 && | 2041 | pkt_dev->min_in6_daddr.s6_addr32[2] == 0 && |
1814 | pkt_dev->min_in6_daddr.s6_addr32[2] == 0 && | 2042 | pkt_dev->min_in6_daddr.s6_addr32[3] == 0) ; |
1815 | pkt_dev->min_in6_daddr.s6_addr32[3] == 0); | ||
1816 | else { | 2043 | else { |
1817 | int i; | 2044 | int i; |
1818 | 2045 | ||
1819 | /* Only random destinations yet */ | 2046 | /* Only random destinations yet */ |
1820 | 2047 | ||
1821 | for(i=0; i < 4; i++) { | 2048 | for (i = 0; i < 4; i++) { |
1822 | pkt_dev->cur_in6_daddr.s6_addr32[i] = | 2049 | pkt_dev->cur_in6_daddr.s6_addr32[i] = |
1823 | ((pktgen_random() | | 2050 | ((pktgen_random() | |
1824 | pkt_dev->min_in6_daddr.s6_addr32[i]) & | 2051 | pkt_dev->min_in6_daddr.s6_addr32[i]) & |
1825 | pkt_dev->max_in6_daddr.s6_addr32[i]); | 2052 | pkt_dev->max_in6_daddr.s6_addr32[i]); |
1826 | } | 2053 | } |
1827 | } | 2054 | } |
1828 | } | 2055 | } |
1829 | 2056 | ||
1830 | if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) { | 2057 | if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) { |
1831 | __u32 t; | 2058 | __u32 t; |
1832 | if (pkt_dev->flags & F_TXSIZE_RND) { | 2059 | if (pkt_dev->flags & F_TXSIZE_RND) { |
1833 | t = ((pktgen_random() % (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size)) | 2060 | t = ((pktgen_random() % |
1834 | + pkt_dev->min_pkt_size); | 2061 | (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size)) |
1835 | } | 2062 | + pkt_dev->min_pkt_size); |
1836 | else { | 2063 | } else { |
1837 | t = pkt_dev->cur_pkt_size + 1; | 2064 | t = pkt_dev->cur_pkt_size + 1; |
1838 | if (t > pkt_dev->max_pkt_size) | 2065 | if (t > pkt_dev->max_pkt_size) |
1839 | t = pkt_dev->min_pkt_size; | 2066 | t = pkt_dev->min_pkt_size; |
1840 | } | 2067 | } |
1841 | pkt_dev->cur_pkt_size = t; | 2068 | pkt_dev->cur_pkt_size = t; |
1842 | } | 2069 | } |
1843 | 2070 | ||
1844 | pkt_dev->flows[flow].count++; | 2071 | pkt_dev->flows[flow].count++; |
1845 | } | 2072 | } |
1846 | 2073 | ||
2074 | static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev) | ||
2075 | { | ||
2076 | unsigned i; | ||
2077 | for(i = 0; i < pkt_dev->nr_labels; i++) { | ||
2078 | *mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM; | ||
2079 | } | ||
2080 | mpls--; | ||
2081 | *mpls |= MPLS_STACK_BOTTOM; | ||
2082 | } | ||
1847 | 2083 | ||
1848 | static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | 2084 | static struct sk_buff *fill_packet_ipv4(struct net_device *odev, |
1849 | struct pktgen_dev *pkt_dev) | 2085 | struct pktgen_dev *pkt_dev) |
1850 | { | 2086 | { |
1851 | struct sk_buff *skb = NULL; | 2087 | struct sk_buff *skb = NULL; |
1852 | __u8 *eth; | 2088 | __u8 *eth; |
1853 | struct udphdr *udph; | 2089 | struct udphdr *udph; |
1854 | int datalen, iplen; | 2090 | int datalen, iplen; |
1855 | struct iphdr *iph; | 2091 | struct iphdr *iph; |
1856 | struct pktgen_hdr *pgh = NULL; | 2092 | struct pktgen_hdr *pgh = NULL; |
1857 | 2093 | __be16 protocol = __constant_htons(ETH_P_IP); | |
2094 | __be32 *mpls; | ||
2095 | |||
2096 | if (pkt_dev->nr_labels) | ||
2097 | protocol = __constant_htons(ETH_P_MPLS_UC); | ||
2098 | |||
1858 | /* Update any of the values, used when we're incrementing various | 2099 | /* Update any of the values, used when we're incrementing various |
1859 | * fields. | 2100 | * fields. |
1860 | */ | 2101 | */ |
1861 | mod_cur_headers(pkt_dev); | 2102 | mod_cur_headers(pkt_dev); |
1862 | 2103 | ||
1863 | datalen = (odev->hard_header_len + 16) & ~0xf; | 2104 | datalen = (odev->hard_header_len + 16) & ~0xf; |
1864 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen, GFP_ATOMIC); | 2105 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen + |
2106 | pkt_dev->nr_labels*sizeof(u32), GFP_ATOMIC); | ||
1865 | if (!skb) { | 2107 | if (!skb) { |
1866 | sprintf(pkt_dev->result, "No memory"); | 2108 | sprintf(pkt_dev->result, "No memory"); |
1867 | return NULL; | 2109 | return NULL; |
@@ -1871,51 +2113,56 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
1871 | 2113 | ||
1872 | /* Reserve for ethernet and IP header */ | 2114 | /* Reserve for ethernet and IP header */ |
1873 | eth = (__u8 *) skb_push(skb, 14); | 2115 | eth = (__u8 *) skb_push(skb, 14); |
2116 | mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); | ||
2117 | if (pkt_dev->nr_labels) | ||
2118 | mpls_push(mpls, pkt_dev); | ||
1874 | iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)); | 2119 | iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)); |
1875 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); | 2120 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); |
1876 | 2121 | ||
1877 | memcpy(eth, pkt_dev->hh, 12); | 2122 | memcpy(eth, pkt_dev->hh, 12); |
1878 | *(u16*)ð[12] = __constant_htons(ETH_P_IP); | 2123 | *(u16 *) & eth[12] = protocol; |
1879 | 2124 | ||
1880 | datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */ | 2125 | /* Eth + IPh + UDPh + mpls */ |
1881 | if (datalen < sizeof(struct pktgen_hdr)) | 2126 | datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 - |
2127 | pkt_dev->nr_labels*sizeof(u32); | ||
2128 | if (datalen < sizeof(struct pktgen_hdr)) | ||
1882 | datalen = sizeof(struct pktgen_hdr); | 2129 | datalen = sizeof(struct pktgen_hdr); |
1883 | 2130 | ||
1884 | udph->source = htons(pkt_dev->cur_udp_src); | 2131 | udph->source = htons(pkt_dev->cur_udp_src); |
1885 | udph->dest = htons(pkt_dev->cur_udp_dst); | 2132 | udph->dest = htons(pkt_dev->cur_udp_dst); |
1886 | udph->len = htons(datalen + 8); /* DATA + udphdr */ | 2133 | udph->len = htons(datalen + 8); /* DATA + udphdr */ |
1887 | udph->check = 0; /* No checksum */ | 2134 | udph->check = 0; /* No checksum */ |
1888 | 2135 | ||
1889 | iph->ihl = 5; | 2136 | iph->ihl = 5; |
1890 | iph->version = 4; | 2137 | iph->version = 4; |
1891 | iph->ttl = 32; | 2138 | iph->ttl = 32; |
1892 | iph->tos = 0; | 2139 | iph->tos = 0; |
1893 | iph->protocol = IPPROTO_UDP; /* UDP */ | 2140 | iph->protocol = IPPROTO_UDP; /* UDP */ |
1894 | iph->saddr = pkt_dev->cur_saddr; | 2141 | iph->saddr = pkt_dev->cur_saddr; |
1895 | iph->daddr = pkt_dev->cur_daddr; | 2142 | iph->daddr = pkt_dev->cur_daddr; |
1896 | iph->frag_off = 0; | 2143 | iph->frag_off = 0; |
1897 | iplen = 20 + 8 + datalen; | 2144 | iplen = 20 + 8 + datalen; |
1898 | iph->tot_len = htons(iplen); | 2145 | iph->tot_len = htons(iplen); |
1899 | iph->check = 0; | 2146 | iph->check = 0; |
1900 | iph->check = ip_fast_csum((void *) iph, iph->ihl); | 2147 | iph->check = ip_fast_csum((void *)iph, iph->ihl); |
1901 | skb->protocol = __constant_htons(ETH_P_IP); | 2148 | skb->protocol = protocol; |
1902 | skb->mac.raw = ((u8 *)iph) - 14; | 2149 | skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32); |
1903 | skb->dev = odev; | 2150 | skb->dev = odev; |
1904 | skb->pkt_type = PACKET_HOST; | 2151 | skb->pkt_type = PACKET_HOST; |
1905 | 2152 | ||
1906 | if (pkt_dev->nfrags <= 0) | 2153 | if (pkt_dev->nfrags <= 0) |
1907 | pgh = (struct pktgen_hdr *)skb_put(skb, datalen); | 2154 | pgh = (struct pktgen_hdr *)skb_put(skb, datalen); |
1908 | else { | 2155 | else { |
1909 | int frags = pkt_dev->nfrags; | 2156 | int frags = pkt_dev->nfrags; |
1910 | int i; | 2157 | int i; |
1911 | 2158 | ||
1912 | pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8); | 2159 | pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8); |
1913 | 2160 | ||
1914 | if (frags > MAX_SKB_FRAGS) | 2161 | if (frags > MAX_SKB_FRAGS) |
1915 | frags = MAX_SKB_FRAGS; | 2162 | frags = MAX_SKB_FRAGS; |
1916 | if (datalen > frags*PAGE_SIZE) { | 2163 | if (datalen > frags * PAGE_SIZE) { |
1917 | skb_put(skb, datalen-frags*PAGE_SIZE); | 2164 | skb_put(skb, datalen - frags * PAGE_SIZE); |
1918 | datalen = frags*PAGE_SIZE; | 2165 | datalen = frags * PAGE_SIZE; |
1919 | } | 2166 | } |
1920 | 2167 | ||
1921 | i = 0; | 2168 | i = 0; |
@@ -1924,7 +2171,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
1924 | skb_shinfo(skb)->frags[i].page = page; | 2171 | skb_shinfo(skb)->frags[i].page = page; |
1925 | skb_shinfo(skb)->frags[i].page_offset = 0; | 2172 | skb_shinfo(skb)->frags[i].page_offset = 0; |
1926 | skb_shinfo(skb)->frags[i].size = | 2173 | skb_shinfo(skb)->frags[i].size = |
1927 | (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); | 2174 | (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); |
1928 | datalen -= skb_shinfo(skb)->frags[i].size; | 2175 | datalen -= skb_shinfo(skb)->frags[i].size; |
1929 | skb->len += skb_shinfo(skb)->frags[i].size; | 2176 | skb->len += skb_shinfo(skb)->frags[i].size; |
1930 | skb->data_len += skb_shinfo(skb)->frags[i].size; | 2177 | skb->data_len += skb_shinfo(skb)->frags[i].size; |
@@ -1944,30 +2191,33 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
1944 | 2191 | ||
1945 | skb_shinfo(skb)->frags[i - 1].size -= rem; | 2192 | skb_shinfo(skb)->frags[i - 1].size -= rem; |
1946 | 2193 | ||
1947 | skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i - 1]; | 2194 | skb_shinfo(skb)->frags[i] = |
2195 | skb_shinfo(skb)->frags[i - 1]; | ||
1948 | get_page(skb_shinfo(skb)->frags[i].page); | 2196 | get_page(skb_shinfo(skb)->frags[i].page); |
1949 | skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i - 1].page; | 2197 | skb_shinfo(skb)->frags[i].page = |
1950 | skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i - 1].size; | 2198 | skb_shinfo(skb)->frags[i - 1].page; |
2199 | skb_shinfo(skb)->frags[i].page_offset += | ||
2200 | skb_shinfo(skb)->frags[i - 1].size; | ||
1951 | skb_shinfo(skb)->frags[i].size = rem; | 2201 | skb_shinfo(skb)->frags[i].size = rem; |
1952 | i++; | 2202 | i++; |
1953 | skb_shinfo(skb)->nr_frags = i; | 2203 | skb_shinfo(skb)->nr_frags = i; |
1954 | } | 2204 | } |
1955 | } | 2205 | } |
1956 | 2206 | ||
1957 | /* Stamp the time, and sequence number, convert them to network byte order */ | 2207 | /* Stamp the time, and sequence number, convert them to network byte order */ |
2208 | |||
2209 | if (pgh) { | ||
2210 | struct timeval timestamp; | ||
2211 | |||
2212 | pgh->pgh_magic = htonl(PKTGEN_MAGIC); | ||
2213 | pgh->seq_num = htonl(pkt_dev->seq_num); | ||
2214 | |||
2215 | do_gettimeofday(×tamp); | ||
2216 | pgh->tv_sec = htonl(timestamp.tv_sec); | ||
2217 | pgh->tv_usec = htonl(timestamp.tv_usec); | ||
2218 | } | ||
2219 | pkt_dev->seq_num++; | ||
1958 | 2220 | ||
1959 | if (pgh) { | ||
1960 | struct timeval timestamp; | ||
1961 | |||
1962 | pgh->pgh_magic = htonl(PKTGEN_MAGIC); | ||
1963 | pgh->seq_num = htonl(pkt_dev->seq_num); | ||
1964 | |||
1965 | do_gettimeofday(×tamp); | ||
1966 | pgh->tv_sec = htonl(timestamp.tv_sec); | ||
1967 | pgh->tv_usec = htonl(timestamp.tv_usec); | ||
1968 | } | ||
1969 | pkt_dev->seq_num++; | ||
1970 | |||
1971 | return skb; | 2221 | return skb; |
1972 | } | 2222 | } |
1973 | 2223 | ||
@@ -1980,23 +2230,24 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, | |||
1980 | * --ro | 2230 | * --ro |
1981 | */ | 2231 | */ |
1982 | 2232 | ||
1983 | static unsigned int scan_ip6(const char *s,char ip[16]) | 2233 | static unsigned int scan_ip6(const char *s, char ip[16]) |
1984 | { | 2234 | { |
1985 | unsigned int i; | 2235 | unsigned int i; |
1986 | unsigned int len=0; | 2236 | unsigned int len = 0; |
1987 | unsigned long u; | 2237 | unsigned long u; |
1988 | char suffix[16]; | 2238 | char suffix[16]; |
1989 | unsigned int prefixlen=0; | 2239 | unsigned int prefixlen = 0; |
1990 | unsigned int suffixlen=0; | 2240 | unsigned int suffixlen = 0; |
1991 | __u32 tmp; | 2241 | __u32 tmp; |
1992 | 2242 | ||
1993 | for (i=0; i<16; i++) ip[i]=0; | 2243 | for (i = 0; i < 16; i++) |
2244 | ip[i] = 0; | ||
1994 | 2245 | ||
1995 | for (;;) { | 2246 | for (;;) { |
1996 | if (*s == ':') { | 2247 | if (*s == ':') { |
1997 | len++; | 2248 | len++; |
1998 | if (s[1] == ':') { /* Found "::", skip to part 2 */ | 2249 | if (s[1] == ':') { /* Found "::", skip to part 2 */ |
1999 | s+=2; | 2250 | s += 2; |
2000 | len++; | 2251 | len++; |
2001 | break; | 2252 | break; |
2002 | } | 2253 | } |
@@ -2004,136 +2255,162 @@ static unsigned int scan_ip6(const char *s,char ip[16]) | |||
2004 | } | 2255 | } |
2005 | { | 2256 | { |
2006 | char *tmp; | 2257 | char *tmp; |
2007 | u=simple_strtoul(s,&tmp,16); | 2258 | u = simple_strtoul(s, &tmp, 16); |
2008 | i=tmp-s; | 2259 | i = tmp - s; |
2009 | } | 2260 | } |
2010 | 2261 | ||
2011 | if (!i) return 0; | 2262 | if (!i) |
2012 | if (prefixlen==12 && s[i]=='.') { | 2263 | return 0; |
2264 | if (prefixlen == 12 && s[i] == '.') { | ||
2013 | 2265 | ||
2014 | /* the last 4 bytes may be written as IPv4 address */ | 2266 | /* the last 4 bytes may be written as IPv4 address */ |
2015 | 2267 | ||
2016 | tmp = in_aton(s); | 2268 | tmp = in_aton(s); |
2017 | memcpy((struct in_addr*)(ip+12), &tmp, sizeof(tmp)); | 2269 | memcpy((struct in_addr *)(ip + 12), &tmp, sizeof(tmp)); |
2018 | return i+len; | 2270 | return i + len; |
2019 | } | 2271 | } |
2020 | ip[prefixlen++] = (u >> 8); | 2272 | ip[prefixlen++] = (u >> 8); |
2021 | ip[prefixlen++] = (u & 255); | 2273 | ip[prefixlen++] = (u & 255); |
2022 | s += i; len += i; | 2274 | s += i; |
2023 | if (prefixlen==16) | 2275 | len += i; |
2276 | if (prefixlen == 16) | ||
2024 | return len; | 2277 | return len; |
2025 | } | 2278 | } |
2026 | 2279 | ||
2027 | /* part 2, after "::" */ | 2280 | /* part 2, after "::" */ |
2028 | for (;;) { | 2281 | for (;;) { |
2029 | if (*s == ':') { | 2282 | if (*s == ':') { |
2030 | if (suffixlen==0) | 2283 | if (suffixlen == 0) |
2031 | break; | 2284 | break; |
2032 | s++; | 2285 | s++; |
2033 | len++; | 2286 | len++; |
2034 | } else if (suffixlen!=0) | 2287 | } else if (suffixlen != 0) |
2035 | break; | 2288 | break; |
2036 | { | 2289 | { |
2037 | char *tmp; | 2290 | char *tmp; |
2038 | u=simple_strtol(s,&tmp,16); | 2291 | u = simple_strtol(s, &tmp, 16); |
2039 | i=tmp-s; | 2292 | i = tmp - s; |
2040 | } | 2293 | } |
2041 | if (!i) { | 2294 | if (!i) { |
2042 | if (*s) len--; | 2295 | if (*s) |
2296 | len--; | ||
2043 | break; | 2297 | break; |
2044 | } | 2298 | } |
2045 | if (suffixlen+prefixlen<=12 && s[i]=='.') { | 2299 | if (suffixlen + prefixlen <= 12 && s[i] == '.') { |
2046 | tmp = in_aton(s); | 2300 | tmp = in_aton(s); |
2047 | memcpy((struct in_addr*)(suffix+suffixlen), &tmp, sizeof(tmp)); | 2301 | memcpy((struct in_addr *)(suffix + suffixlen), &tmp, |
2048 | suffixlen+=4; | 2302 | sizeof(tmp)); |
2049 | len+=strlen(s); | 2303 | suffixlen += 4; |
2304 | len += strlen(s); | ||
2050 | break; | 2305 | break; |
2051 | } | 2306 | } |
2052 | suffix[suffixlen++] = (u >> 8); | 2307 | suffix[suffixlen++] = (u >> 8); |
2053 | suffix[suffixlen++] = (u & 255); | 2308 | suffix[suffixlen++] = (u & 255); |
2054 | s += i; len += i; | 2309 | s += i; |
2055 | if (prefixlen+suffixlen==16) | 2310 | len += i; |
2311 | if (prefixlen + suffixlen == 16) | ||
2056 | break; | 2312 | break; |
2057 | } | 2313 | } |
2058 | for (i=0; i<suffixlen; i++) | 2314 | for (i = 0; i < suffixlen; i++) |
2059 | ip[16-suffixlen+i] = suffix[i]; | 2315 | ip[16 - suffixlen + i] = suffix[i]; |
2060 | return len; | 2316 | return len; |
2061 | } | 2317 | } |
2062 | 2318 | ||
2063 | static char tohex(char hexdigit) { | 2319 | static char tohex(char hexdigit) |
2064 | return hexdigit>9?hexdigit+'a'-10:hexdigit+'0'; | 2320 | { |
2321 | return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0'; | ||
2065 | } | 2322 | } |
2066 | 2323 | ||
2067 | static int fmt_xlong(char* s,unsigned int i) { | 2324 | static int fmt_xlong(char *s, unsigned int i) |
2068 | char* bak=s; | 2325 | { |
2069 | *s=tohex((i>>12)&0xf); if (s!=bak || *s!='0') ++s; | 2326 | char *bak = s; |
2070 | *s=tohex((i>>8)&0xf); if (s!=bak || *s!='0') ++s; | 2327 | *s = tohex((i >> 12) & 0xf); |
2071 | *s=tohex((i>>4)&0xf); if (s!=bak || *s!='0') ++s; | 2328 | if (s != bak || *s != '0') |
2072 | *s=tohex(i&0xf); | 2329 | ++s; |
2073 | return s-bak+1; | 2330 | *s = tohex((i >> 8) & 0xf); |
2331 | if (s != bak || *s != '0') | ||
2332 | ++s; | ||
2333 | *s = tohex((i >> 4) & 0xf); | ||
2334 | if (s != bak || *s != '0') | ||
2335 | ++s; | ||
2336 | *s = tohex(i & 0xf); | ||
2337 | return s - bak + 1; | ||
2074 | } | 2338 | } |
2075 | 2339 | ||
2076 | static unsigned int fmt_ip6(char *s,const char ip[16]) { | 2340 | static unsigned int fmt_ip6(char *s, const char ip[16]) |
2341 | { | ||
2077 | unsigned int len; | 2342 | unsigned int len; |
2078 | unsigned int i; | 2343 | unsigned int i; |
2079 | unsigned int temp; | 2344 | unsigned int temp; |
2080 | unsigned int compressing; | 2345 | unsigned int compressing; |
2081 | int j; | 2346 | int j; |
2082 | 2347 | ||
2083 | len = 0; compressing = 0; | 2348 | len = 0; |
2084 | for (j=0; j<16; j+=2) { | 2349 | compressing = 0; |
2350 | for (j = 0; j < 16; j += 2) { | ||
2085 | 2351 | ||
2086 | #ifdef V4MAPPEDPREFIX | 2352 | #ifdef V4MAPPEDPREFIX |
2087 | if (j==12 && !memcmp(ip,V4mappedprefix,12)) { | 2353 | if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) { |
2088 | inet_ntoa_r(*(struct in_addr*)(ip+12),s); | 2354 | inet_ntoa_r(*(struct in_addr *)(ip + 12), s); |
2089 | temp=strlen(s); | 2355 | temp = strlen(s); |
2090 | return len+temp; | 2356 | return len + temp; |
2091 | } | 2357 | } |
2092 | #endif | 2358 | #endif |
2093 | temp = ((unsigned long) (unsigned char) ip[j] << 8) + | 2359 | temp = ((unsigned long)(unsigned char)ip[j] << 8) + |
2094 | (unsigned long) (unsigned char) ip[j+1]; | 2360 | (unsigned long)(unsigned char)ip[j + 1]; |
2095 | if (temp == 0) { | 2361 | if (temp == 0) { |
2096 | if (!compressing) { | 2362 | if (!compressing) { |
2097 | compressing=1; | 2363 | compressing = 1; |
2098 | if (j==0) { | 2364 | if (j == 0) { |
2099 | *s++=':'; ++len; | 2365 | *s++ = ':'; |
2366 | ++len; | ||
2100 | } | 2367 | } |
2101 | } | 2368 | } |
2102 | } else { | 2369 | } else { |
2103 | if (compressing) { | 2370 | if (compressing) { |
2104 | compressing=0; | 2371 | compressing = 0; |
2105 | *s++=':'; ++len; | 2372 | *s++ = ':'; |
2373 | ++len; | ||
2106 | } | 2374 | } |
2107 | i = fmt_xlong(s,temp); len += i; s += i; | 2375 | i = fmt_xlong(s, temp); |
2108 | if (j<14) { | 2376 | len += i; |
2377 | s += i; | ||
2378 | if (j < 14) { | ||
2109 | *s++ = ':'; | 2379 | *s++ = ':'; |
2110 | ++len; | 2380 | ++len; |
2111 | } | 2381 | } |
2112 | } | 2382 | } |
2113 | } | 2383 | } |
2114 | if (compressing) { | 2384 | if (compressing) { |
2115 | *s++=':'; ++len; | 2385 | *s++ = ':'; |
2386 | ++len; | ||
2116 | } | 2387 | } |
2117 | *s=0; | 2388 | *s = 0; |
2118 | return len; | 2389 | return len; |
2119 | } | 2390 | } |
2120 | 2391 | ||
2121 | static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | 2392 | static struct sk_buff *fill_packet_ipv6(struct net_device *odev, |
2122 | struct pktgen_dev *pkt_dev) | 2393 | struct pktgen_dev *pkt_dev) |
2123 | { | 2394 | { |
2124 | struct sk_buff *skb = NULL; | 2395 | struct sk_buff *skb = NULL; |
2125 | __u8 *eth; | 2396 | __u8 *eth; |
2126 | struct udphdr *udph; | 2397 | struct udphdr *udph; |
2127 | int datalen; | 2398 | int datalen; |
2128 | struct ipv6hdr *iph; | 2399 | struct ipv6hdr *iph; |
2129 | struct pktgen_hdr *pgh = NULL; | 2400 | struct pktgen_hdr *pgh = NULL; |
2401 | __be16 protocol = __constant_htons(ETH_P_IPV6); | ||
2402 | __be32 *mpls; | ||
2403 | |||
2404 | if (pkt_dev->nr_labels) | ||
2405 | protocol = __constant_htons(ETH_P_MPLS_UC); | ||
2130 | 2406 | ||
2131 | /* Update any of the values, used when we're incrementing various | 2407 | /* Update any of the values, used when we're incrementing various |
2132 | * fields. | 2408 | * fields. |
2133 | */ | 2409 | */ |
2134 | mod_cur_headers(pkt_dev); | 2410 | mod_cur_headers(pkt_dev); |
2135 | 2411 | ||
2136 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16, GFP_ATOMIC); | 2412 | skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 + |
2413 | pkt_dev->nr_labels*sizeof(u32), GFP_ATOMIC); | ||
2137 | if (!skb) { | 2414 | if (!skb) { |
2138 | sprintf(pkt_dev->result, "No memory"); | 2415 | sprintf(pkt_dev->result, "No memory"); |
2139 | return NULL; | 2416 | return NULL; |
@@ -2143,27 +2420,33 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
2143 | 2420 | ||
2144 | /* Reserve for ethernet and IP header */ | 2421 | /* Reserve for ethernet and IP header */ |
2145 | eth = (__u8 *) skb_push(skb, 14); | 2422 | eth = (__u8 *) skb_push(skb, 14); |
2423 | mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32)); | ||
2424 | if (pkt_dev->nr_labels) | ||
2425 | mpls_push(mpls, pkt_dev); | ||
2146 | iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr)); | 2426 | iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr)); |
2147 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); | 2427 | udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr)); |
2148 | 2428 | ||
2149 | memcpy(eth, pkt_dev->hh, 12); | 2429 | memcpy(eth, pkt_dev->hh, 12); |
2150 | *(u16*)ð[12] = __constant_htons(ETH_P_IPV6); | 2430 | *(u16 *) & eth[12] = __constant_htons(ETH_P_IPV6); |
2151 | 2431 | ||
2152 | datalen = pkt_dev->cur_pkt_size-14- | 2432 | /* Eth + IPh + UDPh + mpls */ |
2153 | sizeof(struct ipv6hdr)-sizeof(struct udphdr); /* Eth + IPh + UDPh */ | 2433 | datalen = pkt_dev->cur_pkt_size - 14 - |
2434 | sizeof(struct ipv6hdr) - sizeof(struct udphdr) - | ||
2435 | pkt_dev->nr_labels*sizeof(u32); | ||
2154 | 2436 | ||
2155 | if (datalen < sizeof(struct pktgen_hdr)) { | 2437 | if (datalen < sizeof(struct pktgen_hdr)) { |
2156 | datalen = sizeof(struct pktgen_hdr); | 2438 | datalen = sizeof(struct pktgen_hdr); |
2157 | if (net_ratelimit()) | 2439 | if (net_ratelimit()) |
2158 | printk(KERN_INFO "pktgen: increased datalen to %d\n", datalen); | 2440 | printk(KERN_INFO "pktgen: increased datalen to %d\n", |
2441 | datalen); | ||
2159 | } | 2442 | } |
2160 | 2443 | ||
2161 | udph->source = htons(pkt_dev->cur_udp_src); | 2444 | udph->source = htons(pkt_dev->cur_udp_src); |
2162 | udph->dest = htons(pkt_dev->cur_udp_dst); | 2445 | udph->dest = htons(pkt_dev->cur_udp_dst); |
2163 | udph->len = htons(datalen + sizeof(struct udphdr)); | 2446 | udph->len = htons(datalen + sizeof(struct udphdr)); |
2164 | udph->check = 0; /* No checksum */ | 2447 | udph->check = 0; /* No checksum */ |
2165 | 2448 | ||
2166 | *(u32*)iph = __constant_htonl(0x60000000); /* Version + flow */ | 2449 | *(u32 *) iph = __constant_htonl(0x60000000); /* Version + flow */ |
2167 | 2450 | ||
2168 | iph->hop_limit = 32; | 2451 | iph->hop_limit = 32; |
2169 | 2452 | ||
@@ -2173,24 +2456,24 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
2173 | ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr); | 2456 | ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr); |
2174 | ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr); | 2457 | ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr); |
2175 | 2458 | ||
2176 | skb->mac.raw = ((u8 *)iph) - 14; | 2459 | skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32); |
2177 | skb->protocol = __constant_htons(ETH_P_IPV6); | 2460 | skb->protocol = protocol; |
2178 | skb->dev = odev; | 2461 | skb->dev = odev; |
2179 | skb->pkt_type = PACKET_HOST; | 2462 | skb->pkt_type = PACKET_HOST; |
2180 | 2463 | ||
2181 | if (pkt_dev->nfrags <= 0) | 2464 | if (pkt_dev->nfrags <= 0) |
2182 | pgh = (struct pktgen_hdr *)skb_put(skb, datalen); | 2465 | pgh = (struct pktgen_hdr *)skb_put(skb, datalen); |
2183 | else { | 2466 | else { |
2184 | int frags = pkt_dev->nfrags; | 2467 | int frags = pkt_dev->nfrags; |
2185 | int i; | 2468 | int i; |
2186 | 2469 | ||
2187 | pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8); | 2470 | pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8); |
2188 | 2471 | ||
2189 | if (frags > MAX_SKB_FRAGS) | 2472 | if (frags > MAX_SKB_FRAGS) |
2190 | frags = MAX_SKB_FRAGS; | 2473 | frags = MAX_SKB_FRAGS; |
2191 | if (datalen > frags*PAGE_SIZE) { | 2474 | if (datalen > frags * PAGE_SIZE) { |
2192 | skb_put(skb, datalen-frags*PAGE_SIZE); | 2475 | skb_put(skb, datalen - frags * PAGE_SIZE); |
2193 | datalen = frags*PAGE_SIZE; | 2476 | datalen = frags * PAGE_SIZE; |
2194 | } | 2477 | } |
2195 | 2478 | ||
2196 | i = 0; | 2479 | i = 0; |
@@ -2199,7 +2482,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
2199 | skb_shinfo(skb)->frags[i].page = page; | 2482 | skb_shinfo(skb)->frags[i].page = page; |
2200 | skb_shinfo(skb)->frags[i].page_offset = 0; | 2483 | skb_shinfo(skb)->frags[i].page_offset = 0; |
2201 | skb_shinfo(skb)->frags[i].size = | 2484 | skb_shinfo(skb)->frags[i].size = |
2202 | (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); | 2485 | (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); |
2203 | datalen -= skb_shinfo(skb)->frags[i].size; | 2486 | datalen -= skb_shinfo(skb)->frags[i].size; |
2204 | skb->len += skb_shinfo(skb)->frags[i].size; | 2487 | skb->len += skb_shinfo(skb)->frags[i].size; |
2205 | skb->data_len += skb_shinfo(skb)->frags[i].size; | 2488 | skb->data_len += skb_shinfo(skb)->frags[i].size; |
@@ -2219,305 +2502,333 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev, | |||
2219 | 2502 | ||
2220 | skb_shinfo(skb)->frags[i - 1].size -= rem; | 2503 | skb_shinfo(skb)->frags[i - 1].size -= rem; |
2221 | 2504 | ||
2222 | skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i - 1]; | 2505 | skb_shinfo(skb)->frags[i] = |
2506 | skb_shinfo(skb)->frags[i - 1]; | ||
2223 | get_page(skb_shinfo(skb)->frags[i].page); | 2507 | get_page(skb_shinfo(skb)->frags[i].page); |
2224 | skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i - 1].page; | 2508 | skb_shinfo(skb)->frags[i].page = |
2225 | skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i - 1].size; | 2509 | skb_shinfo(skb)->frags[i - 1].page; |
2510 | skb_shinfo(skb)->frags[i].page_offset += | ||
2511 | skb_shinfo(skb)->frags[i - 1].size; | ||
2226 | skb_shinfo(skb)->frags[i].size = rem; | 2512 | skb_shinfo(skb)->frags[i].size = rem; |
2227 | i++; | 2513 | i++; |
2228 | skb_shinfo(skb)->nr_frags = i; | 2514 | skb_shinfo(skb)->nr_frags = i; |
2229 | } | 2515 | } |
2230 | } | 2516 | } |
2231 | 2517 | ||
2232 | /* Stamp the time, and sequence number, convert them to network byte order */ | 2518 | /* Stamp the time, and sequence number, convert them to network byte order */ |
2233 | /* should we update cloned packets too ? */ | 2519 | /* should we update cloned packets too ? */ |
2234 | if (pgh) { | 2520 | if (pgh) { |
2235 | struct timeval timestamp; | 2521 | struct timeval timestamp; |
2236 | 2522 | ||
2237 | pgh->pgh_magic = htonl(PKTGEN_MAGIC); | 2523 | pgh->pgh_magic = htonl(PKTGEN_MAGIC); |
2238 | pgh->seq_num = htonl(pkt_dev->seq_num); | 2524 | pgh->seq_num = htonl(pkt_dev->seq_num); |
2239 | 2525 | ||
2240 | do_gettimeofday(×tamp); | 2526 | do_gettimeofday(×tamp); |
2241 | pgh->tv_sec = htonl(timestamp.tv_sec); | 2527 | pgh->tv_sec = htonl(timestamp.tv_sec); |
2242 | pgh->tv_usec = htonl(timestamp.tv_usec); | 2528 | pgh->tv_usec = htonl(timestamp.tv_usec); |
2243 | } | 2529 | } |
2244 | pkt_dev->seq_num++; | 2530 | pkt_dev->seq_num++; |
2245 | 2531 | ||
2246 | return skb; | 2532 | return skb; |
2247 | } | 2533 | } |
2248 | 2534 | ||
2249 | static inline struct sk_buff *fill_packet(struct net_device *odev, | 2535 | static inline struct sk_buff *fill_packet(struct net_device *odev, |
2250 | struct pktgen_dev *pkt_dev) | 2536 | struct pktgen_dev *pkt_dev) |
2251 | { | 2537 | { |
2252 | if(pkt_dev->flags & F_IPV6) | 2538 | if (pkt_dev->flags & F_IPV6) |
2253 | return fill_packet_ipv6(odev, pkt_dev); | 2539 | return fill_packet_ipv6(odev, pkt_dev); |
2254 | else | 2540 | else |
2255 | return fill_packet_ipv4(odev, pkt_dev); | 2541 | return fill_packet_ipv4(odev, pkt_dev); |
2256 | } | 2542 | } |
2257 | 2543 | ||
2258 | static void pktgen_clear_counters(struct pktgen_dev *pkt_dev) | 2544 | static void pktgen_clear_counters(struct pktgen_dev *pkt_dev) |
2259 | { | 2545 | { |
2260 | pkt_dev->seq_num = 1; | 2546 | pkt_dev->seq_num = 1; |
2261 | pkt_dev->idle_acc = 0; | 2547 | pkt_dev->idle_acc = 0; |
2262 | pkt_dev->sofar = 0; | 2548 | pkt_dev->sofar = 0; |
2263 | pkt_dev->tx_bytes = 0; | 2549 | pkt_dev->tx_bytes = 0; |
2264 | pkt_dev->errors = 0; | 2550 | pkt_dev->errors = 0; |
2265 | } | 2551 | } |
2266 | 2552 | ||
2267 | /* Set up structure for sending pkts, clear counters */ | 2553 | /* Set up structure for sending pkts, clear counters */ |
2268 | 2554 | ||
2269 | static void pktgen_run(struct pktgen_thread *t) | 2555 | static void pktgen_run(struct pktgen_thread *t) |
2270 | { | 2556 | { |
2271 | struct pktgen_dev *pkt_dev = NULL; | 2557 | struct pktgen_dev *pkt_dev; |
2272 | int started = 0; | 2558 | int started = 0; |
2273 | 2559 | ||
2274 | PG_DEBUG(printk("pktgen: entering pktgen_run. %p\n", t)); | 2560 | PG_DEBUG(printk("pktgen: entering pktgen_run. %p\n", t)); |
2275 | 2561 | ||
2276 | if_lock(t); | 2562 | if_lock(t); |
2277 | for (pkt_dev = t->if_list; pkt_dev; pkt_dev = pkt_dev->next ) { | 2563 | list_for_each_entry(pkt_dev, &t->if_list, list) { |
2278 | 2564 | ||
2279 | /* | 2565 | /* |
2280 | * setup odev and create initial packet. | 2566 | * setup odev and create initial packet. |
2281 | */ | 2567 | */ |
2282 | pktgen_setup_inject(pkt_dev); | 2568 | pktgen_setup_inject(pkt_dev); |
2283 | 2569 | ||
2284 | if(pkt_dev->odev) { | 2570 | if (pkt_dev->odev) { |
2285 | pktgen_clear_counters(pkt_dev); | 2571 | pktgen_clear_counters(pkt_dev); |
2286 | pkt_dev->running = 1; /* Cranke yeself! */ | 2572 | pkt_dev->running = 1; /* Cranke yeself! */ |
2287 | pkt_dev->skb = NULL; | 2573 | pkt_dev->skb = NULL; |
2288 | pkt_dev->started_at = getCurUs(); | 2574 | pkt_dev->started_at = getCurUs(); |
2289 | pkt_dev->next_tx_us = getCurUs(); /* Transmit immediately */ | 2575 | pkt_dev->next_tx_us = getCurUs(); /* Transmit immediately */ |
2290 | pkt_dev->next_tx_ns = 0; | 2576 | pkt_dev->next_tx_ns = 0; |
2291 | 2577 | ||
2292 | strcpy(pkt_dev->result, "Starting"); | 2578 | strcpy(pkt_dev->result, "Starting"); |
2293 | started++; | 2579 | started++; |
2294 | } | 2580 | } else |
2295 | else | ||
2296 | strcpy(pkt_dev->result, "Error starting"); | 2581 | strcpy(pkt_dev->result, "Error starting"); |
2297 | } | 2582 | } |
2298 | if_unlock(t); | 2583 | if_unlock(t); |
2299 | if(started) t->control &= ~(T_STOP); | 2584 | if (started) |
2585 | t->control &= ~(T_STOP); | ||
2300 | } | 2586 | } |
2301 | 2587 | ||
2302 | static void pktgen_stop_all_threads_ifs(void) | 2588 | static void pktgen_stop_all_threads_ifs(void) |
2303 | { | 2589 | { |
2304 | struct pktgen_thread *t = pktgen_threads; | 2590 | struct pktgen_thread *t; |
2305 | 2591 | ||
2306 | PG_DEBUG(printk("pktgen: entering pktgen_stop_all_threads.\n")); | 2592 | PG_DEBUG(printk("pktgen: entering pktgen_stop_all_threads_ifs.\n")); |
2307 | 2593 | ||
2308 | thread_lock(); | 2594 | mutex_lock(&pktgen_thread_lock); |
2309 | while(t) { | 2595 | |
2310 | pktgen_stop(t); | 2596 | list_for_each_entry(t, &pktgen_threads, th_list) |
2311 | t = t->next; | 2597 | t->control |= T_STOP; |
2312 | } | 2598 | |
2313 | thread_unlock(); | 2599 | mutex_unlock(&pktgen_thread_lock); |
2314 | } | 2600 | } |
2315 | 2601 | ||
2316 | static int thread_is_running(struct pktgen_thread *t ) | 2602 | static int thread_is_running(struct pktgen_thread *t) |
2317 | { | 2603 | { |
2318 | struct pktgen_dev *next; | 2604 | struct pktgen_dev *pkt_dev; |
2319 | int res = 0; | 2605 | int res = 0; |
2320 | 2606 | ||
2321 | for(next=t->if_list; next; next=next->next) { | 2607 | list_for_each_entry(pkt_dev, &t->if_list, list) |
2322 | if(next->running) { | 2608 | if (pkt_dev->running) { |
2323 | res = 1; | 2609 | res = 1; |
2324 | break; | 2610 | break; |
2325 | } | 2611 | } |
2326 | } | 2612 | return res; |
2327 | return res; | ||
2328 | } | 2613 | } |
2329 | 2614 | ||
2330 | static int pktgen_wait_thread_run(struct pktgen_thread *t ) | 2615 | static int pktgen_wait_thread_run(struct pktgen_thread *t) |
2331 | { | 2616 | { |
2332 | if_lock(t); | 2617 | if_lock(t); |
2333 | 2618 | ||
2334 | while(thread_is_running(t)) { | 2619 | while (thread_is_running(t)) { |
2335 | 2620 | ||
2336 | if_unlock(t); | 2621 | if_unlock(t); |
2337 | 2622 | ||
2338 | msleep_interruptible(100); | 2623 | msleep_interruptible(100); |
2339 | 2624 | ||
2340 | if (signal_pending(current)) | 2625 | if (signal_pending(current)) |
2341 | goto signal; | 2626 | goto signal; |
2342 | if_lock(t); | 2627 | if_lock(t); |
2343 | } | 2628 | } |
2344 | if_unlock(t); | 2629 | if_unlock(t); |
2345 | return 1; | 2630 | return 1; |
2346 | signal: | 2631 | signal: |
2347 | return 0; | 2632 | return 0; |
2348 | } | 2633 | } |
2349 | 2634 | ||
2350 | static int pktgen_wait_all_threads_run(void) | 2635 | static int pktgen_wait_all_threads_run(void) |
2351 | { | 2636 | { |
2352 | struct pktgen_thread *t = pktgen_threads; | 2637 | struct pktgen_thread *t; |
2353 | int sig = 1; | 2638 | int sig = 1; |
2354 | 2639 | ||
2355 | while (t) { | 2640 | mutex_lock(&pktgen_thread_lock); |
2641 | |||
2642 | list_for_each_entry(t, &pktgen_threads, th_list) { | ||
2356 | sig = pktgen_wait_thread_run(t); | 2643 | sig = pktgen_wait_thread_run(t); |
2357 | if( sig == 0 ) break; | 2644 | if (sig == 0) |
2358 | thread_lock(); | 2645 | break; |
2359 | t=t->next; | ||
2360 | thread_unlock(); | ||
2361 | } | ||
2362 | if(sig == 0) { | ||
2363 | thread_lock(); | ||
2364 | while (t) { | ||
2365 | t->control |= (T_STOP); | ||
2366 | t=t->next; | ||
2367 | } | ||
2368 | thread_unlock(); | ||
2369 | } | 2646 | } |
2647 | |||
2648 | if (sig == 0) | ||
2649 | list_for_each_entry(t, &pktgen_threads, th_list) | ||
2650 | t->control |= (T_STOP); | ||
2651 | |||
2652 | mutex_unlock(&pktgen_thread_lock); | ||
2370 | return sig; | 2653 | return sig; |
2371 | } | 2654 | } |
2372 | 2655 | ||
2373 | static void pktgen_run_all_threads(void) | 2656 | static void pktgen_run_all_threads(void) |
2374 | { | 2657 | { |
2375 | struct pktgen_thread *t = pktgen_threads; | 2658 | struct pktgen_thread *t; |
2376 | 2659 | ||
2377 | PG_DEBUG(printk("pktgen: entering pktgen_run_all_threads.\n")); | 2660 | PG_DEBUG(printk("pktgen: entering pktgen_run_all_threads.\n")); |
2378 | 2661 | ||
2379 | thread_lock(); | 2662 | mutex_lock(&pktgen_thread_lock); |
2380 | 2663 | ||
2381 | while(t) { | 2664 | list_for_each_entry(t, &pktgen_threads, th_list) |
2382 | t->control |= (T_RUN); | 2665 | t->control |= (T_RUN); |
2383 | t = t->next; | ||
2384 | } | ||
2385 | thread_unlock(); | ||
2386 | 2666 | ||
2387 | schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ | 2667 | mutex_unlock(&pktgen_thread_lock); |
2388 | 2668 | ||
2669 | schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ | ||
2670 | |||
2389 | pktgen_wait_all_threads_run(); | 2671 | pktgen_wait_all_threads_run(); |
2390 | } | 2672 | } |
2391 | 2673 | ||
2392 | |||
2393 | static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) | 2674 | static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) |
2394 | { | 2675 | { |
2395 | __u64 total_us, bps, mbps, pps, idle; | 2676 | __u64 total_us, bps, mbps, pps, idle; |
2396 | char *p = pkt_dev->result; | 2677 | char *p = pkt_dev->result; |
2397 | 2678 | ||
2398 | total_us = pkt_dev->stopped_at - pkt_dev->started_at; | 2679 | total_us = pkt_dev->stopped_at - pkt_dev->started_at; |
2399 | 2680 | ||
2400 | idle = pkt_dev->idle_acc; | 2681 | idle = pkt_dev->idle_acc; |
2401 | 2682 | ||
2402 | p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n", | 2683 | p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags)\n", |
2403 | (unsigned long long) total_us, | 2684 | (unsigned long long)total_us, |
2404 | (unsigned long long)(total_us - idle), | 2685 | (unsigned long long)(total_us - idle), |
2405 | (unsigned long long) idle, | 2686 | (unsigned long long)idle, |
2406 | (unsigned long long) pkt_dev->sofar, | 2687 | (unsigned long long)pkt_dev->sofar, |
2407 | pkt_dev->cur_pkt_size, nr_frags); | 2688 | pkt_dev->cur_pkt_size, nr_frags); |
2408 | 2689 | ||
2409 | pps = pkt_dev->sofar * USEC_PER_SEC; | 2690 | pps = pkt_dev->sofar * USEC_PER_SEC; |
2410 | 2691 | ||
2411 | while ((total_us >> 32) != 0) { | 2692 | while ((total_us >> 32) != 0) { |
2412 | pps >>= 1; | 2693 | pps >>= 1; |
2413 | total_us >>= 1; | 2694 | total_us >>= 1; |
2414 | } | 2695 | } |
2415 | 2696 | ||
2416 | do_div(pps, total_us); | 2697 | do_div(pps, total_us); |
2417 | 2698 | ||
2418 | bps = pps * 8 * pkt_dev->cur_pkt_size; | 2699 | bps = pps * 8 * pkt_dev->cur_pkt_size; |
2419 | 2700 | ||
2420 | mbps = bps; | 2701 | mbps = bps; |
2421 | do_div(mbps, 1000000); | 2702 | do_div(mbps, 1000000); |
2422 | p += sprintf(p, " %llupps %lluMb/sec (%llubps) errors: %llu", | 2703 | p += sprintf(p, " %llupps %lluMb/sec (%llubps) errors: %llu", |
2423 | (unsigned long long) pps, | 2704 | (unsigned long long)pps, |
2424 | (unsigned long long) mbps, | 2705 | (unsigned long long)mbps, |
2425 | (unsigned long long) bps, | 2706 | (unsigned long long)bps, |
2426 | (unsigned long long) pkt_dev->errors); | 2707 | (unsigned long long)pkt_dev->errors); |
2427 | } | 2708 | } |
2428 | |||
2429 | 2709 | ||
2430 | /* Set stopped-at timer, remove from running list, do counters & statistics */ | 2710 | /* Set stopped-at timer, remove from running list, do counters & statistics */ |
2431 | 2711 | ||
2432 | static int pktgen_stop_device(struct pktgen_dev *pkt_dev) | 2712 | static int pktgen_stop_device(struct pktgen_dev *pkt_dev) |
2433 | { | 2713 | { |
2434 | 2714 | int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1; | |
2435 | if (!pkt_dev->running) { | ||
2436 | printk("pktgen: interface: %s is already stopped\n", pkt_dev->ifname); | ||
2437 | return -EINVAL; | ||
2438 | } | ||
2439 | 2715 | ||
2440 | pkt_dev->stopped_at = getCurUs(); | 2716 | if (!pkt_dev->running) { |
2441 | pkt_dev->running = 0; | 2717 | printk("pktgen: interface: %s is already stopped\n", |
2718 | pkt_dev->ifname); | ||
2719 | return -EINVAL; | ||
2720 | } | ||
2442 | 2721 | ||
2443 | show_results(pkt_dev, skb_shinfo(pkt_dev->skb)->nr_frags); | 2722 | pkt_dev->stopped_at = getCurUs(); |
2723 | pkt_dev->running = 0; | ||
2444 | 2724 | ||
2445 | if (pkt_dev->skb) | 2725 | show_results(pkt_dev, nr_frags); |
2446 | kfree_skb(pkt_dev->skb); | ||
2447 | 2726 | ||
2448 | pkt_dev->skb = NULL; | 2727 | return 0; |
2449 | |||
2450 | return 0; | ||
2451 | } | 2728 | } |
2452 | 2729 | ||
2453 | static struct pktgen_dev *next_to_run(struct pktgen_thread *t ) | 2730 | static struct pktgen_dev *next_to_run(struct pktgen_thread *t) |
2454 | { | 2731 | { |
2455 | struct pktgen_dev *next, *best = NULL; | 2732 | struct pktgen_dev *pkt_dev, *best = NULL; |
2456 | 2733 | ||
2457 | if_lock(t); | 2734 | if_lock(t); |
2458 | 2735 | ||
2459 | for(next=t->if_list; next ; next=next->next) { | 2736 | list_for_each_entry(pkt_dev, &t->if_list, list) { |
2460 | if(!next->running) continue; | 2737 | if (!pkt_dev->running) |
2461 | if(best == NULL) best=next; | 2738 | continue; |
2462 | else if ( next->next_tx_us < best->next_tx_us) | 2739 | if (best == NULL) |
2463 | best = next; | 2740 | best = pkt_dev; |
2741 | else if (pkt_dev->next_tx_us < best->next_tx_us) | ||
2742 | best = pkt_dev; | ||
2464 | } | 2743 | } |
2465 | if_unlock(t); | 2744 | if_unlock(t); |
2466 | return best; | 2745 | return best; |
2467 | } | 2746 | } |
2468 | 2747 | ||
2469 | static void pktgen_stop(struct pktgen_thread *t) { | 2748 | static void pktgen_stop(struct pktgen_thread *t) |
2470 | struct pktgen_dev *next = NULL; | 2749 | { |
2750 | struct pktgen_dev *pkt_dev; | ||
2471 | 2751 | ||
2472 | PG_DEBUG(printk("pktgen: entering pktgen_stop.\n")); | 2752 | PG_DEBUG(printk("pktgen: entering pktgen_stop\n")); |
2473 | 2753 | ||
2474 | if_lock(t); | 2754 | if_lock(t); |
2755 | |||
2756 | list_for_each_entry(pkt_dev, &t->if_list, list) { | ||
2757 | pktgen_stop_device(pkt_dev); | ||
2758 | if (pkt_dev->skb) | ||
2759 | kfree_skb(pkt_dev->skb); | ||
2475 | 2760 | ||
2476 | for(next=t->if_list; next; next=next->next) | 2761 | pkt_dev->skb = NULL; |
2477 | pktgen_stop_device(next); | 2762 | } |
2478 | 2763 | ||
2479 | if_unlock(t); | 2764 | if_unlock(t); |
2480 | } | 2765 | } |
2481 | 2766 | ||
2482 | static void pktgen_rem_all_ifs(struct pktgen_thread *t) | 2767 | /* |
2768 | * one of our devices needs to be removed - find it | ||
2769 | * and remove it | ||
2770 | */ | ||
2771 | static void pktgen_rem_one_if(struct pktgen_thread *t) | ||
2483 | { | 2772 | { |
2484 | struct pktgen_dev *cur, *next = NULL; | 2773 | struct list_head *q, *n; |
2485 | 2774 | struct pktgen_dev *cur; | |
2486 | /* Remove all devices, free mem */ | 2775 | |
2487 | 2776 | PG_DEBUG(printk("pktgen: entering pktgen_rem_one_if\n")); | |
2488 | if_lock(t); | 2777 | |
2489 | 2778 | if_lock(t); | |
2490 | for(cur=t->if_list; cur; cur=next) { | 2779 | |
2491 | next = cur->next; | 2780 | list_for_each_safe(q, n, &t->if_list) { |
2781 | cur = list_entry(q, struct pktgen_dev, list); | ||
2782 | |||
2783 | if (!cur->removal_mark) | ||
2784 | continue; | ||
2785 | |||
2786 | if (cur->skb) | ||
2787 | kfree_skb(cur->skb); | ||
2788 | cur->skb = NULL; | ||
2789 | |||
2492 | pktgen_remove_device(t, cur); | 2790 | pktgen_remove_device(t, cur); |
2791 | |||
2792 | break; | ||
2493 | } | 2793 | } |
2494 | 2794 | ||
2495 | if_unlock(t); | 2795 | if_unlock(t); |
2496 | } | 2796 | } |
2497 | 2797 | ||
2498 | static void pktgen_rem_thread(struct pktgen_thread *t) | 2798 | static void pktgen_rem_all_ifs(struct pktgen_thread *t) |
2499 | { | 2799 | { |
2500 | /* Remove from the thread list */ | 2800 | struct list_head *q, *n; |
2801 | struct pktgen_dev *cur; | ||
2501 | 2802 | ||
2502 | struct pktgen_thread *tmp = pktgen_threads; | 2803 | /* Remove all devices, free mem */ |
2503 | 2804 | ||
2504 | remove_proc_entry(t->name, pg_proc_dir); | 2805 | PG_DEBUG(printk("pktgen: entering pktgen_rem_all_ifs\n")); |
2806 | if_lock(t); | ||
2505 | 2807 | ||
2506 | thread_lock(); | 2808 | list_for_each_safe(q, n, &t->if_list) { |
2809 | cur = list_entry(q, struct pktgen_dev, list); | ||
2507 | 2810 | ||
2508 | if (tmp == t) | 2811 | if (cur->skb) |
2509 | pktgen_threads = tmp->next; | 2812 | kfree_skb(cur->skb); |
2510 | else { | 2813 | cur->skb = NULL; |
2511 | while (tmp) { | 2814 | |
2512 | if (tmp->next == t) { | 2815 | pktgen_remove_device(t, cur); |
2513 | tmp->next = t->next; | ||
2514 | t->next = NULL; | ||
2515 | break; | ||
2516 | } | ||
2517 | tmp = tmp->next; | ||
2518 | } | ||
2519 | } | 2816 | } |
2520 | thread_unlock(); | 2817 | |
2818 | if_unlock(t); | ||
2819 | } | ||
2820 | |||
2821 | static void pktgen_rem_thread(struct pktgen_thread *t) | ||
2822 | { | ||
2823 | /* Remove from the thread list */ | ||
2824 | |||
2825 | remove_proc_entry(t->name, pg_proc_dir); | ||
2826 | |||
2827 | mutex_lock(&pktgen_thread_lock); | ||
2828 | |||
2829 | list_del(&t->th_list); | ||
2830 | |||
2831 | mutex_unlock(&pktgen_thread_lock); | ||
2521 | } | 2832 | } |
2522 | 2833 | ||
2523 | static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) | 2834 | static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) |
@@ -2527,7 +2838,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) | |||
2527 | int ret; | 2838 | int ret; |
2528 | 2839 | ||
2529 | odev = pkt_dev->odev; | 2840 | odev = pkt_dev->odev; |
2530 | 2841 | ||
2531 | if (pkt_dev->delay_us || pkt_dev->delay_ns) { | 2842 | if (pkt_dev->delay_us || pkt_dev->delay_ns) { |
2532 | u64 now; | 2843 | u64 now; |
2533 | 2844 | ||
@@ -2544,67 +2855,71 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) | |||
2544 | goto out; | 2855 | goto out; |
2545 | } | 2856 | } |
2546 | } | 2857 | } |
2547 | 2858 | ||
2548 | if (netif_queue_stopped(odev) || need_resched()) { | 2859 | if (netif_queue_stopped(odev) || need_resched()) { |
2549 | idle_start = getCurUs(); | 2860 | idle_start = getCurUs(); |
2550 | 2861 | ||
2551 | if (!netif_running(odev)) { | 2862 | if (!netif_running(odev)) { |
2552 | pktgen_stop_device(pkt_dev); | 2863 | pktgen_stop_device(pkt_dev); |
2864 | if (pkt_dev->skb) | ||
2865 | kfree_skb(pkt_dev->skb); | ||
2866 | pkt_dev->skb = NULL; | ||
2553 | goto out; | 2867 | goto out; |
2554 | } | 2868 | } |
2555 | if (need_resched()) | 2869 | if (need_resched()) |
2556 | schedule(); | 2870 | schedule(); |
2557 | 2871 | ||
2558 | pkt_dev->idle_acc += getCurUs() - idle_start; | 2872 | pkt_dev->idle_acc += getCurUs() - idle_start; |
2559 | 2873 | ||
2560 | if (netif_queue_stopped(odev)) { | 2874 | if (netif_queue_stopped(odev)) { |
2561 | pkt_dev->next_tx_us = getCurUs(); /* TODO */ | 2875 | pkt_dev->next_tx_us = getCurUs(); /* TODO */ |
2562 | pkt_dev->next_tx_ns = 0; | 2876 | pkt_dev->next_tx_ns = 0; |
2563 | goto out; /* Try the next interface */ | 2877 | goto out; /* Try the next interface */ |
2564 | } | 2878 | } |
2565 | } | 2879 | } |
2566 | 2880 | ||
2567 | if (pkt_dev->last_ok || !pkt_dev->skb) { | 2881 | if (pkt_dev->last_ok || !pkt_dev->skb) { |
2568 | if ((++pkt_dev->clone_count >= pkt_dev->clone_skb ) || (!pkt_dev->skb)) { | 2882 | if ((++pkt_dev->clone_count >= pkt_dev->clone_skb) |
2883 | || (!pkt_dev->skb)) { | ||
2569 | /* build a new pkt */ | 2884 | /* build a new pkt */ |
2570 | if (pkt_dev->skb) | 2885 | if (pkt_dev->skb) |
2571 | kfree_skb(pkt_dev->skb); | 2886 | kfree_skb(pkt_dev->skb); |
2572 | 2887 | ||
2573 | pkt_dev->skb = fill_packet(odev, pkt_dev); | 2888 | pkt_dev->skb = fill_packet(odev, pkt_dev); |
2574 | if (pkt_dev->skb == NULL) { | 2889 | if (pkt_dev->skb == NULL) { |
2575 | printk("pktgen: ERROR: couldn't allocate skb in fill_packet.\n"); | 2890 | printk("pktgen: ERROR: couldn't allocate skb in fill_packet.\n"); |
2576 | schedule(); | 2891 | schedule(); |
2577 | pkt_dev->clone_count--; /* back out increment, OOM */ | 2892 | pkt_dev->clone_count--; /* back out increment, OOM */ |
2578 | goto out; | 2893 | goto out; |
2579 | } | 2894 | } |
2580 | pkt_dev->allocated_skbs++; | 2895 | pkt_dev->allocated_skbs++; |
2581 | pkt_dev->clone_count = 0; /* reset counter */ | 2896 | pkt_dev->clone_count = 0; /* reset counter */ |
2582 | } | 2897 | } |
2583 | } | 2898 | } |
2584 | 2899 | ||
2585 | spin_lock_bh(&odev->xmit_lock); | 2900 | spin_lock_bh(&odev->xmit_lock); |
2586 | if (!netif_queue_stopped(odev)) { | 2901 | if (!netif_queue_stopped(odev)) { |
2587 | 2902 | ||
2588 | atomic_inc(&(pkt_dev->skb->users)); | 2903 | atomic_inc(&(pkt_dev->skb->users)); |
2589 | retry_now: | 2904 | retry_now: |
2590 | ret = odev->hard_start_xmit(pkt_dev->skb, odev); | 2905 | ret = odev->hard_start_xmit(pkt_dev->skb, odev); |
2591 | if (likely(ret == NETDEV_TX_OK)) { | 2906 | if (likely(ret == NETDEV_TX_OK)) { |
2592 | pkt_dev->last_ok = 1; | 2907 | pkt_dev->last_ok = 1; |
2593 | pkt_dev->sofar++; | 2908 | pkt_dev->sofar++; |
2594 | pkt_dev->seq_num++; | 2909 | pkt_dev->seq_num++; |
2595 | pkt_dev->tx_bytes += pkt_dev->cur_pkt_size; | 2910 | pkt_dev->tx_bytes += pkt_dev->cur_pkt_size; |
2596 | 2911 | ||
2597 | } else if (ret == NETDEV_TX_LOCKED | 2912 | } else if (ret == NETDEV_TX_LOCKED |
2598 | && (odev->features & NETIF_F_LLTX)) { | 2913 | && (odev->features & NETIF_F_LLTX)) { |
2599 | cpu_relax(); | 2914 | cpu_relax(); |
2600 | goto retry_now; | 2915 | goto retry_now; |
2601 | } else { /* Retry it next time */ | 2916 | } else { /* Retry it next time */ |
2602 | 2917 | ||
2603 | atomic_dec(&(pkt_dev->skb->users)); | 2918 | atomic_dec(&(pkt_dev->skb->users)); |
2604 | 2919 | ||
2605 | if (debug && net_ratelimit()) | 2920 | if (debug && net_ratelimit()) |
2606 | printk(KERN_INFO "pktgen: Hard xmit error\n"); | 2921 | printk(KERN_INFO "pktgen: Hard xmit error\n"); |
2607 | 2922 | ||
2608 | pkt_dev->errors++; | 2923 | pkt_dev->errors++; |
2609 | pkt_dev->last_ok = 0; | 2924 | pkt_dev->last_ok = 0; |
2610 | } | 2925 | } |
@@ -2619,16 +2934,16 @@ retry_now: | |||
2619 | pkt_dev->next_tx_us++; | 2934 | pkt_dev->next_tx_us++; |
2620 | pkt_dev->next_tx_ns -= 1000; | 2935 | pkt_dev->next_tx_ns -= 1000; |
2621 | } | 2936 | } |
2622 | } | 2937 | } |
2623 | 2938 | ||
2624 | else { /* Retry it next time */ | 2939 | else { /* Retry it next time */ |
2625 | pkt_dev->last_ok = 0; | 2940 | pkt_dev->last_ok = 0; |
2626 | pkt_dev->next_tx_us = getCurUs(); /* TODO */ | 2941 | pkt_dev->next_tx_us = getCurUs(); /* TODO */ |
2627 | pkt_dev->next_tx_ns = 0; | 2942 | pkt_dev->next_tx_ns = 0; |
2628 | } | 2943 | } |
2629 | 2944 | ||
2630 | spin_unlock_bh(&odev->xmit_lock); | 2945 | spin_unlock_bh(&odev->xmit_lock); |
2631 | 2946 | ||
2632 | /* If pkt_dev->count is zero, then run forever */ | 2947 | /* If pkt_dev->count is zero, then run forever */ |
2633 | if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { | 2948 | if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { |
2634 | if (atomic_read(&(pkt_dev->skb->users)) != 1) { | 2949 | if (atomic_read(&(pkt_dev->skb->users)) != 1) { |
@@ -2641,72 +2956,74 @@ retry_now: | |||
2641 | } | 2956 | } |
2642 | pkt_dev->idle_acc += getCurUs() - idle_start; | 2957 | pkt_dev->idle_acc += getCurUs() - idle_start; |
2643 | } | 2958 | } |
2644 | 2959 | ||
2645 | /* Done with this */ | 2960 | /* Done with this */ |
2646 | pktgen_stop_device(pkt_dev); | 2961 | pktgen_stop_device(pkt_dev); |
2647 | } | 2962 | if (pkt_dev->skb) |
2648 | out:; | 2963 | kfree_skb(pkt_dev->skb); |
2649 | } | 2964 | pkt_dev->skb = NULL; |
2965 | } | ||
2966 | out:; | ||
2967 | } | ||
2650 | 2968 | ||
2651 | /* | 2969 | /* |
2652 | * Main loop of the thread goes here | 2970 | * Main loop of the thread goes here |
2653 | */ | 2971 | */ |
2654 | 2972 | ||
2655 | static void pktgen_thread_worker(struct pktgen_thread *t) | 2973 | static void pktgen_thread_worker(struct pktgen_thread *t) |
2656 | { | 2974 | { |
2657 | DEFINE_WAIT(wait); | 2975 | DEFINE_WAIT(wait); |
2658 | struct pktgen_dev *pkt_dev = NULL; | 2976 | struct pktgen_dev *pkt_dev = NULL; |
2659 | int cpu = t->cpu; | 2977 | int cpu = t->cpu; |
2660 | sigset_t tmpsig; | 2978 | sigset_t tmpsig; |
2661 | u32 max_before_softirq; | 2979 | u32 max_before_softirq; |
2662 | u32 tx_since_softirq = 0; | 2980 | u32 tx_since_softirq = 0; |
2663 | 2981 | ||
2664 | daemonize("pktgen/%d", cpu); | 2982 | daemonize("pktgen/%d", cpu); |
2665 | 2983 | ||
2666 | /* Block all signals except SIGKILL, SIGSTOP and SIGTERM */ | 2984 | /* Block all signals except SIGKILL, SIGSTOP and SIGTERM */ |
2667 | 2985 | ||
2668 | spin_lock_irq(¤t->sighand->siglock); | 2986 | spin_lock_irq(¤t->sighand->siglock); |
2669 | tmpsig = current->blocked; | 2987 | tmpsig = current->blocked; |
2670 | siginitsetinv(¤t->blocked, | 2988 | siginitsetinv(¤t->blocked, |
2671 | sigmask(SIGKILL) | | 2989 | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGTERM)); |
2672 | sigmask(SIGSTOP)| | ||
2673 | sigmask(SIGTERM)); | ||
2674 | 2990 | ||
2675 | recalc_sigpending(); | 2991 | recalc_sigpending(); |
2676 | spin_unlock_irq(¤t->sighand->siglock); | 2992 | spin_unlock_irq(¤t->sighand->siglock); |
2677 | 2993 | ||
2678 | /* Migrate to the right CPU */ | 2994 | /* Migrate to the right CPU */ |
2679 | set_cpus_allowed(current, cpumask_of_cpu(cpu)); | 2995 | set_cpus_allowed(current, cpumask_of_cpu(cpu)); |
2680 | if (smp_processor_id() != cpu) | 2996 | if (smp_processor_id() != cpu) |
2681 | BUG(); | 2997 | BUG(); |
2682 | 2998 | ||
2683 | init_waitqueue_head(&t->queue); | 2999 | init_waitqueue_head(&t->queue); |
2684 | 3000 | ||
2685 | t->control &= ~(T_TERMINATE); | 3001 | t->control &= ~(T_TERMINATE); |
2686 | t->control &= ~(T_RUN); | 3002 | t->control &= ~(T_RUN); |
2687 | t->control &= ~(T_STOP); | 3003 | t->control &= ~(T_STOP); |
3004 | t->control &= ~(T_REMDEVALL); | ||
2688 | t->control &= ~(T_REMDEV); | 3005 | t->control &= ~(T_REMDEV); |
2689 | 3006 | ||
2690 | t->pid = current->pid; | 3007 | t->pid = current->pid; |
2691 | 3008 | ||
2692 | PG_DEBUG(printk("pktgen: starting pktgen/%d: pid=%d\n", cpu, current->pid)); | 3009 | PG_DEBUG(printk("pktgen: starting pktgen/%d: pid=%d\n", cpu, current->pid)); |
2693 | 3010 | ||
2694 | max_before_softirq = t->max_before_softirq; | 3011 | max_before_softirq = t->max_before_softirq; |
2695 | |||
2696 | __set_current_state(TASK_INTERRUPTIBLE); | ||
2697 | mb(); | ||
2698 | 3012 | ||
2699 | while (1) { | 3013 | __set_current_state(TASK_INTERRUPTIBLE); |
2700 | 3014 | mb(); | |
3015 | |||
3016 | while (1) { | ||
3017 | |||
2701 | __set_current_state(TASK_RUNNING); | 3018 | __set_current_state(TASK_RUNNING); |
2702 | 3019 | ||
2703 | /* | 3020 | /* |
2704 | * Get next dev to xmit -- if any. | 3021 | * Get next dev to xmit -- if any. |
2705 | */ | 3022 | */ |
2706 | 3023 | ||
2707 | pkt_dev = next_to_run(t); | 3024 | pkt_dev = next_to_run(t); |
2708 | 3025 | ||
2709 | if (pkt_dev) { | 3026 | if (pkt_dev) { |
2710 | 3027 | ||
2711 | pktgen_xmit(pkt_dev); | 3028 | pktgen_xmit(pkt_dev); |
2712 | 3029 | ||
@@ -2724,115 +3041,125 @@ static void pktgen_thread_worker(struct pktgen_thread *t) | |||
2724 | } | 3041 | } |
2725 | } else { | 3042 | } else { |
2726 | prepare_to_wait(&(t->queue), &wait, TASK_INTERRUPTIBLE); | 3043 | prepare_to_wait(&(t->queue), &wait, TASK_INTERRUPTIBLE); |
2727 | schedule_timeout(HZ/10); | 3044 | schedule_timeout(HZ / 10); |
2728 | finish_wait(&(t->queue), &wait); | 3045 | finish_wait(&(t->queue), &wait); |
2729 | } | 3046 | } |
2730 | 3047 | ||
2731 | /* | 3048 | /* |
2732 | * Back from sleep, either due to the timeout or signal. | 3049 | * Back from sleep, either due to the timeout or signal. |
2733 | * We check if we have any "posted" work for us. | 3050 | * We check if we have any "posted" work for us. |
2734 | */ | 3051 | */ |
2735 | 3052 | ||
2736 | if (t->control & T_TERMINATE || signal_pending(current)) | 3053 | if (t->control & T_TERMINATE || signal_pending(current)) |
2737 | /* we received a request to terminate ourself */ | 3054 | /* we received a request to terminate ourself */ |
2738 | break; | 3055 | break; |
2739 | |||
2740 | 3056 | ||
2741 | if(t->control & T_STOP) { | 3057 | if (t->control & T_STOP) { |
2742 | pktgen_stop(t); | 3058 | pktgen_stop(t); |
2743 | t->control &= ~(T_STOP); | 3059 | t->control &= ~(T_STOP); |
2744 | } | 3060 | } |
2745 | 3061 | ||
2746 | if(t->control & T_RUN) { | 3062 | if (t->control & T_RUN) { |
2747 | pktgen_run(t); | 3063 | pktgen_run(t); |
2748 | t->control &= ~(T_RUN); | 3064 | t->control &= ~(T_RUN); |
2749 | } | 3065 | } |
2750 | 3066 | ||
2751 | if(t->control & T_REMDEV) { | 3067 | if (t->control & T_REMDEVALL) { |
2752 | pktgen_rem_all_ifs(t); | 3068 | pktgen_rem_all_ifs(t); |
3069 | t->control &= ~(T_REMDEVALL); | ||
3070 | } | ||
3071 | |||
3072 | if (t->control & T_REMDEV) { | ||
3073 | pktgen_rem_one_if(t); | ||
2753 | t->control &= ~(T_REMDEV); | 3074 | t->control &= ~(T_REMDEV); |
2754 | } | 3075 | } |
2755 | 3076 | ||
2756 | if (need_resched()) | 3077 | if (need_resched()) |
2757 | schedule(); | 3078 | schedule(); |
2758 | } | 3079 | } |
3080 | |||
3081 | PG_DEBUG(printk("pktgen: %s stopping all device\n", t->name)); | ||
3082 | pktgen_stop(t); | ||
2759 | 3083 | ||
2760 | PG_DEBUG(printk("pktgen: %s stopping all device\n", t->name)); | 3084 | PG_DEBUG(printk("pktgen: %s removing all device\n", t->name)); |
2761 | pktgen_stop(t); | 3085 | pktgen_rem_all_ifs(t); |
2762 | 3086 | ||
2763 | PG_DEBUG(printk("pktgen: %s removing all device\n", t->name)); | 3087 | PG_DEBUG(printk("pktgen: %s removing thread.\n", t->name)); |
2764 | pktgen_rem_all_ifs(t); | 3088 | pktgen_rem_thread(t); |
2765 | 3089 | ||
2766 | PG_DEBUG(printk("pktgen: %s removing thread.\n", t->name)); | 3090 | t->removed = 1; |
2767 | pktgen_rem_thread(t); | ||
2768 | } | 3091 | } |
2769 | 3092 | ||
2770 | static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, const char* ifname) | 3093 | static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, |
3094 | const char *ifname) | ||
2771 | { | 3095 | { |
2772 | struct pktgen_dev *pkt_dev = NULL; | 3096 | struct pktgen_dev *p, *pkt_dev = NULL; |
2773 | if_lock(t); | 3097 | if_lock(t); |
2774 | 3098 | ||
2775 | for(pkt_dev=t->if_list; pkt_dev; pkt_dev = pkt_dev->next ) { | 3099 | list_for_each_entry(p, &t->if_list, list) |
2776 | if (strncmp(pkt_dev->ifname, ifname, IFNAMSIZ) == 0) { | 3100 | if (strncmp(p->ifname, ifname, IFNAMSIZ) == 0) { |
2777 | break; | 3101 | pkt_dev = p; |
2778 | } | 3102 | break; |
2779 | } | 3103 | } |
2780 | 3104 | ||
2781 | if_unlock(t); | 3105 | if_unlock(t); |
2782 | PG_DEBUG(printk("pktgen: find_dev(%s) returning %p\n", ifname,pkt_dev)); | 3106 | PG_DEBUG(printk("pktgen: find_dev(%s) returning %p\n", ifname, pkt_dev)); |
2783 | return pkt_dev; | 3107 | return pkt_dev; |
2784 | } | 3108 | } |
2785 | 3109 | ||
2786 | /* | 3110 | /* |
2787 | * Adds a dev at front of if_list. | 3111 | * Adds a dev at front of if_list. |
2788 | */ | 3112 | */ |
2789 | 3113 | ||
2790 | static int add_dev_to_thread(struct pktgen_thread *t, struct pktgen_dev *pkt_dev) | 3114 | static int add_dev_to_thread(struct pktgen_thread *t, |
3115 | struct pktgen_dev *pkt_dev) | ||
2791 | { | 3116 | { |
2792 | int rv = 0; | 3117 | int rv = 0; |
2793 | 3118 | ||
2794 | if_lock(t); | 3119 | if_lock(t); |
2795 | 3120 | ||
2796 | if (pkt_dev->pg_thread) { | 3121 | if (pkt_dev->pg_thread) { |
2797 | printk("pktgen: ERROR: already assigned to a thread.\n"); | 3122 | printk("pktgen: ERROR: already assigned to a thread.\n"); |
2798 | rv = -EBUSY; | 3123 | rv = -EBUSY; |
2799 | goto out; | 3124 | goto out; |
2800 | } | 3125 | } |
2801 | pkt_dev->next =t->if_list; t->if_list=pkt_dev; | 3126 | |
2802 | pkt_dev->pg_thread = t; | 3127 | list_add(&pkt_dev->list, &t->if_list); |
3128 | pkt_dev->pg_thread = t; | ||
2803 | pkt_dev->running = 0; | 3129 | pkt_dev->running = 0; |
2804 | 3130 | ||
2805 | out: | 3131 | out: |
2806 | if_unlock(t); | 3132 | if_unlock(t); |
2807 | return rv; | 3133 | return rv; |
2808 | } | 3134 | } |
2809 | 3135 | ||
2810 | /* Called under thread lock */ | 3136 | /* Called under thread lock */ |
2811 | 3137 | ||
2812 | static int pktgen_add_device(struct pktgen_thread *t, const char* ifname) | 3138 | static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) |
2813 | { | 3139 | { |
2814 | struct pktgen_dev *pkt_dev; | 3140 | struct pktgen_dev *pkt_dev; |
2815 | struct proc_dir_entry *pe; | 3141 | struct proc_dir_entry *pe; |
2816 | 3142 | ||
2817 | /* We don't allow a device to be on several threads */ | 3143 | /* We don't allow a device to be on several threads */ |
2818 | 3144 | ||
2819 | pkt_dev = __pktgen_NN_threads(ifname, FIND); | 3145 | pkt_dev = __pktgen_NN_threads(ifname, FIND); |
2820 | if (pkt_dev) { | 3146 | if (pkt_dev) { |
2821 | printk("pktgen: ERROR: interface already used.\n"); | 3147 | printk("pktgen: ERROR: interface already used.\n"); |
2822 | return -EBUSY; | 3148 | return -EBUSY; |
2823 | } | 3149 | } |
2824 | 3150 | ||
2825 | pkt_dev = kzalloc(sizeof(struct pktgen_dev), GFP_KERNEL); | 3151 | pkt_dev = kzalloc(sizeof(struct pktgen_dev), GFP_KERNEL); |
2826 | if (!pkt_dev) | 3152 | if (!pkt_dev) |
2827 | return -ENOMEM; | 3153 | return -ENOMEM; |
2828 | 3154 | ||
2829 | pkt_dev->flows = vmalloc(MAX_CFLOWS*sizeof(struct flow_state)); | 3155 | pkt_dev->flows = vmalloc(MAX_CFLOWS * sizeof(struct flow_state)); |
2830 | if (pkt_dev->flows == NULL) { | 3156 | if (pkt_dev->flows == NULL) { |
2831 | kfree(pkt_dev); | 3157 | kfree(pkt_dev); |
2832 | return -ENOMEM; | 3158 | return -ENOMEM; |
2833 | } | 3159 | } |
2834 | memset(pkt_dev->flows, 0, MAX_CFLOWS*sizeof(struct flow_state)); | 3160 | memset(pkt_dev->flows, 0, MAX_CFLOWS * sizeof(struct flow_state)); |
2835 | 3161 | ||
3162 | pkt_dev->removal_mark = 0; | ||
2836 | pkt_dev->min_pkt_size = ETH_ZLEN; | 3163 | pkt_dev->min_pkt_size = ETH_ZLEN; |
2837 | pkt_dev->max_pkt_size = ETH_ZLEN; | 3164 | pkt_dev->max_pkt_size = ETH_ZLEN; |
2838 | pkt_dev->nfrags = 0; | 3165 | pkt_dev->nfrags = 0; |
@@ -2841,14 +3168,14 @@ static int pktgen_add_device(struct pktgen_thread *t, const char* ifname) | |||
2841 | pkt_dev->delay_ns = pg_delay_d % 1000; | 3168 | pkt_dev->delay_ns = pg_delay_d % 1000; |
2842 | pkt_dev->count = pg_count_d; | 3169 | pkt_dev->count = pg_count_d; |
2843 | pkt_dev->sofar = 0; | 3170 | pkt_dev->sofar = 0; |
2844 | pkt_dev->udp_src_min = 9; /* sink port */ | 3171 | pkt_dev->udp_src_min = 9; /* sink port */ |
2845 | pkt_dev->udp_src_max = 9; | 3172 | pkt_dev->udp_src_max = 9; |
2846 | pkt_dev->udp_dst_min = 9; | 3173 | pkt_dev->udp_dst_min = 9; |
2847 | pkt_dev->udp_dst_max = 9; | 3174 | pkt_dev->udp_dst_max = 9; |
2848 | 3175 | ||
2849 | strncpy(pkt_dev->ifname, ifname, IFNAMSIZ); | 3176 | strncpy(pkt_dev->ifname, ifname, IFNAMSIZ); |
2850 | 3177 | ||
2851 | if (! pktgen_setup_dev(pkt_dev)) { | 3178 | if (!pktgen_setup_dev(pkt_dev)) { |
2852 | printk("pktgen: ERROR: pktgen_setup_dev failed.\n"); | 3179 | printk("pktgen: ERROR: pktgen_setup_dev failed.\n"); |
2853 | if (pkt_dev->flows) | 3180 | if (pkt_dev->flows) |
2854 | vfree(pkt_dev->flows); | 3181 | vfree(pkt_dev->flows); |
@@ -2871,65 +3198,74 @@ static int pktgen_add_device(struct pktgen_thread *t, const char* ifname) | |||
2871 | return add_dev_to_thread(t, pkt_dev); | 3198 | return add_dev_to_thread(t, pkt_dev); |
2872 | } | 3199 | } |
2873 | 3200 | ||
2874 | static struct pktgen_thread * __init pktgen_find_thread(const char* name) | 3201 | static struct pktgen_thread *__init pktgen_find_thread(const char *name) |
2875 | { | 3202 | { |
2876 | struct pktgen_thread *t = NULL; | 3203 | struct pktgen_thread *t; |
2877 | 3204 | ||
2878 | thread_lock(); | 3205 | mutex_lock(&pktgen_thread_lock); |
2879 | 3206 | ||
2880 | t = pktgen_threads; | 3207 | list_for_each_entry(t, &pktgen_threads, th_list) |
2881 | while (t) { | 3208 | if (strcmp(t->name, name) == 0) { |
2882 | if (strcmp(t->name, name) == 0) | 3209 | mutex_unlock(&pktgen_thread_lock); |
2883 | break; | 3210 | return t; |
3211 | } | ||
2884 | 3212 | ||
2885 | t = t->next; | 3213 | mutex_unlock(&pktgen_thread_lock); |
2886 | } | 3214 | return NULL; |
2887 | thread_unlock(); | ||
2888 | return t; | ||
2889 | } | 3215 | } |
2890 | 3216 | ||
2891 | static int __init pktgen_create_thread(const char* name, int cpu) | 3217 | static int __init pktgen_create_thread(const char *name, int cpu) |
2892 | { | 3218 | { |
2893 | struct pktgen_thread *t = NULL; | 3219 | int err; |
3220 | struct pktgen_thread *t = NULL; | ||
2894 | struct proc_dir_entry *pe; | 3221 | struct proc_dir_entry *pe; |
2895 | 3222 | ||
2896 | if (strlen(name) > 31) { | 3223 | if (strlen(name) > 31) { |
2897 | printk("pktgen: ERROR: Thread name cannot be more than 31 characters.\n"); | 3224 | printk("pktgen: ERROR: Thread name cannot be more than 31 characters.\n"); |
2898 | return -EINVAL; | 3225 | return -EINVAL; |
2899 | } | 3226 | } |
2900 | 3227 | ||
2901 | if (pktgen_find_thread(name)) { | 3228 | if (pktgen_find_thread(name)) { |
2902 | printk("pktgen: ERROR: thread: %s already exists\n", name); | 3229 | printk("pktgen: ERROR: thread: %s already exists\n", name); |
2903 | return -EINVAL; | 3230 | return -EINVAL; |
2904 | } | 3231 | } |
2905 | 3232 | ||
2906 | t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL); | 3233 | t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL); |
2907 | if (!t) { | 3234 | if (!t) { |
2908 | printk("pktgen: ERROR: out of memory, can't create new thread.\n"); | 3235 | printk("pktgen: ERROR: out of memory, can't create new thread.\n"); |
2909 | return -ENOMEM; | 3236 | return -ENOMEM; |
2910 | } | 3237 | } |
2911 | 3238 | ||
2912 | strcpy(t->name, name); | 3239 | strcpy(t->name, name); |
2913 | spin_lock_init(&t->if_lock); | 3240 | spin_lock_init(&t->if_lock); |
2914 | t->cpu = cpu; | 3241 | t->cpu = cpu; |
2915 | 3242 | ||
2916 | pe = create_proc_entry(t->name, 0600, pg_proc_dir); | 3243 | pe = create_proc_entry(t->name, 0600, pg_proc_dir); |
2917 | if (!pe) { | 3244 | if (!pe) { |
2918 | printk("pktgen: cannot create %s/%s procfs entry.\n", | 3245 | printk("pktgen: cannot create %s/%s procfs entry.\n", |
2919 | PG_PROC_DIR, t->name); | 3246 | PG_PROC_DIR, t->name); |
2920 | kfree(t); | 3247 | kfree(t); |
2921 | return -EINVAL; | 3248 | return -EINVAL; |
2922 | } | 3249 | } |
2923 | 3250 | ||
2924 | pe->proc_fops = &pktgen_thread_fops; | 3251 | pe->proc_fops = &pktgen_thread_fops; |
2925 | pe->data = t; | 3252 | pe->data = t; |
2926 | 3253 | ||
2927 | t->next = pktgen_threads; | 3254 | INIT_LIST_HEAD(&t->if_list); |
2928 | pktgen_threads = t; | 3255 | |
3256 | list_add_tail(&t->th_list, &pktgen_threads); | ||
3257 | |||
3258 | t->removed = 0; | ||
2929 | 3259 | ||
2930 | if (kernel_thread((void *) pktgen_thread_worker, (void *) t, | 3260 | err = kernel_thread((void *)pktgen_thread_worker, (void *)t, |
2931 | CLONE_FS | CLONE_FILES | CLONE_SIGHAND) < 0) | 3261 | CLONE_FS | CLONE_FILES | CLONE_SIGHAND); |
3262 | if (err < 0) { | ||
2932 | printk("pktgen: kernel_thread() failed for cpu %d\n", t->cpu); | 3263 | printk("pktgen: kernel_thread() failed for cpu %d\n", t->cpu); |
3264 | remove_proc_entry(t->name, pg_proc_dir); | ||
3265 | list_del(&t->th_list); | ||
3266 | kfree(t); | ||
3267 | return err; | ||
3268 | } | ||
2933 | 3269 | ||
2934 | return 0; | 3270 | return 0; |
2935 | } | 3271 | } |
@@ -2937,55 +3273,52 @@ static int __init pktgen_create_thread(const char* name, int cpu) | |||
2937 | /* | 3273 | /* |
2938 | * Removes a device from the thread if_list. | 3274 | * Removes a device from the thread if_list. |
2939 | */ | 3275 | */ |
2940 | static void _rem_dev_from_if_list(struct pktgen_thread *t, struct pktgen_dev *pkt_dev) | 3276 | static void _rem_dev_from_if_list(struct pktgen_thread *t, |
3277 | struct pktgen_dev *pkt_dev) | ||
2941 | { | 3278 | { |
2942 | struct pktgen_dev *i, *prev = NULL; | 3279 | struct list_head *q, *n; |
2943 | 3280 | struct pktgen_dev *p; | |
2944 | i = t->if_list; | ||
2945 | 3281 | ||
2946 | while(i) { | 3282 | list_for_each_safe(q, n, &t->if_list) { |
2947 | if(i == pkt_dev) { | 3283 | p = list_entry(q, struct pktgen_dev, list); |
2948 | if(prev) prev->next = i->next; | 3284 | if (p == pkt_dev) |
2949 | else t->if_list = NULL; | 3285 | list_del(&p->list); |
2950 | break; | ||
2951 | } | ||
2952 | prev = i; | ||
2953 | i=i->next; | ||
2954 | } | 3286 | } |
2955 | } | 3287 | } |
2956 | 3288 | ||
2957 | static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *pkt_dev) | 3289 | static int pktgen_remove_device(struct pktgen_thread *t, |
3290 | struct pktgen_dev *pkt_dev) | ||
2958 | { | 3291 | { |
2959 | 3292 | ||
2960 | PG_DEBUG(printk("pktgen: remove_device pkt_dev=%p\n", pkt_dev)); | 3293 | PG_DEBUG(printk("pktgen: remove_device pkt_dev=%p\n", pkt_dev)); |
2961 | 3294 | ||
2962 | if (pkt_dev->running) { | 3295 | if (pkt_dev->running) { |
2963 | printk("pktgen:WARNING: trying to remove a running interface, stopping it now.\n"); | 3296 | printk("pktgen:WARNING: trying to remove a running interface, stopping it now.\n"); |
2964 | pktgen_stop_device(pkt_dev); | 3297 | pktgen_stop_device(pkt_dev); |
2965 | } | 3298 | } |
2966 | 3299 | ||
2967 | /* Dis-associate from the interface */ | 3300 | /* Dis-associate from the interface */ |
2968 | 3301 | ||
2969 | if (pkt_dev->odev) { | 3302 | if (pkt_dev->odev) { |
2970 | dev_put(pkt_dev->odev); | 3303 | dev_put(pkt_dev->odev); |
2971 | pkt_dev->odev = NULL; | 3304 | pkt_dev->odev = NULL; |
2972 | } | 3305 | } |
2973 | 3306 | ||
2974 | /* And update the thread if_list */ | 3307 | /* And update the thread if_list */ |
2975 | 3308 | ||
2976 | _rem_dev_from_if_list(t, pkt_dev); | 3309 | _rem_dev_from_if_list(t, pkt_dev); |
2977 | 3310 | ||
2978 | /* Clean up proc file system */ | 3311 | /* Clean up proc file system */ |
2979 | 3312 | ||
2980 | remove_proc_entry(pkt_dev->ifname, pg_proc_dir); | 3313 | remove_proc_entry(pkt_dev->ifname, pg_proc_dir); |
2981 | 3314 | ||
2982 | if (pkt_dev->flows) | 3315 | if (pkt_dev->flows) |
2983 | vfree(pkt_dev->flows); | 3316 | vfree(pkt_dev->flows); |
2984 | kfree(pkt_dev); | 3317 | kfree(pkt_dev); |
2985 | return 0; | 3318 | return 0; |
2986 | } | 3319 | } |
2987 | 3320 | ||
2988 | static int __init pg_init(void) | 3321 | static int __init pg_init(void) |
2989 | { | 3322 | { |
2990 | int cpu; | 3323 | int cpu; |
2991 | struct proc_dir_entry *pe; | 3324 | struct proc_dir_entry *pe; |
@@ -2998,50 +3331,65 @@ static int __init pg_init(void) | |||
2998 | pg_proc_dir->owner = THIS_MODULE; | 3331 | pg_proc_dir->owner = THIS_MODULE; |
2999 | 3332 | ||
3000 | pe = create_proc_entry(PGCTRL, 0600, pg_proc_dir); | 3333 | pe = create_proc_entry(PGCTRL, 0600, pg_proc_dir); |
3001 | if (pe == NULL) { | 3334 | if (pe == NULL) { |
3002 | printk("pktgen: ERROR: cannot create %s procfs entry.\n", PGCTRL); | 3335 | printk("pktgen: ERROR: cannot create %s procfs entry.\n", |
3336 | PGCTRL); | ||
3003 | proc_net_remove(PG_PROC_DIR); | 3337 | proc_net_remove(PG_PROC_DIR); |
3004 | return -EINVAL; | 3338 | return -EINVAL; |
3005 | } | 3339 | } |
3006 | 3340 | ||
3007 | pe->proc_fops = &pktgen_fops; | 3341 | pe->proc_fops = &pktgen_fops; |
3008 | pe->data = NULL; | 3342 | pe->data = NULL; |
3009 | 3343 | ||
3010 | /* Register us to receive netdevice events */ | 3344 | /* Register us to receive netdevice events */ |
3011 | register_netdevice_notifier(&pktgen_notifier_block); | 3345 | register_netdevice_notifier(&pktgen_notifier_block); |
3012 | 3346 | ||
3013 | for_each_online_cpu(cpu) { | 3347 | for_each_online_cpu(cpu) { |
3348 | int err; | ||
3014 | char buf[30]; | 3349 | char buf[30]; |
3015 | 3350 | ||
3016 | sprintf(buf, "kpktgend_%i", cpu); | 3351 | sprintf(buf, "kpktgend_%i", cpu); |
3017 | pktgen_create_thread(buf, cpu); | 3352 | err = pktgen_create_thread(buf, cpu); |
3018 | } | 3353 | if (err) |
3019 | return 0; | 3354 | printk("pktgen: WARNING: Cannot create thread for cpu %d (%d)\n", |
3355 | cpu, err); | ||
3356 | } | ||
3357 | |||
3358 | if (list_empty(&pktgen_threads)) { | ||
3359 | printk("pktgen: ERROR: Initialization failed for all threads\n"); | ||
3360 | unregister_netdevice_notifier(&pktgen_notifier_block); | ||
3361 | remove_proc_entry(PGCTRL, pg_proc_dir); | ||
3362 | proc_net_remove(PG_PROC_DIR); | ||
3363 | return -ENODEV; | ||
3364 | } | ||
3365 | |||
3366 | return 0; | ||
3020 | } | 3367 | } |
3021 | 3368 | ||
3022 | static void __exit pg_cleanup(void) | 3369 | static void __exit pg_cleanup(void) |
3023 | { | 3370 | { |
3371 | struct pktgen_thread *t; | ||
3372 | struct list_head *q, *n; | ||
3024 | wait_queue_head_t queue; | 3373 | wait_queue_head_t queue; |
3025 | init_waitqueue_head(&queue); | 3374 | init_waitqueue_head(&queue); |
3026 | 3375 | ||
3027 | /* Stop all interfaces & threads */ | 3376 | /* Stop all interfaces & threads */ |
3028 | 3377 | ||
3029 | while (pktgen_threads) { | 3378 | list_for_each_safe(q, n, &pktgen_threads) { |
3030 | struct pktgen_thread *t = pktgen_threads; | 3379 | t = list_entry(q, struct pktgen_thread, th_list); |
3031 | pktgen_threads->control |= (T_TERMINATE); | 3380 | t->control |= (T_TERMINATE); |
3032 | 3381 | ||
3033 | wait_event_interruptible_timeout(queue, (t != pktgen_threads), HZ); | 3382 | wait_event_interruptible_timeout(queue, (t->removed == 1), HZ); |
3034 | } | 3383 | } |
3035 | 3384 | ||
3036 | /* Un-register us from receiving netdevice events */ | 3385 | /* Un-register us from receiving netdevice events */ |
3037 | unregister_netdevice_notifier(&pktgen_notifier_block); | 3386 | unregister_netdevice_notifier(&pktgen_notifier_block); |
3038 | 3387 | ||
3039 | /* Clean up proc file system */ | 3388 | /* Clean up proc file system */ |
3040 | remove_proc_entry(PGCTRL, pg_proc_dir); | 3389 | remove_proc_entry(PGCTRL, pg_proc_dir); |
3041 | proc_net_remove(PG_PROC_DIR); | 3390 | proc_net_remove(PG_PROC_DIR); |
3042 | } | 3391 | } |
3043 | 3392 | ||
3044 | |||
3045 | module_init(pg_init); | 3393 | module_init(pg_init); |
3046 | module_exit(pg_cleanup); | 3394 | module_exit(pg_cleanup); |
3047 | 3395 | ||
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index eca2976abb25..3fcfa9c59e1f 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/skbuff.h> | 35 | #include <linux/skbuff.h> |
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
37 | #include <linux/security.h> | 37 | #include <linux/security.h> |
38 | #include <linux/mutex.h> | ||
38 | 39 | ||
39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
40 | #include <asm/system.h> | 41 | #include <asm/system.h> |
@@ -50,26 +51,36 @@ | |||
50 | #include <net/sock.h> | 51 | #include <net/sock.h> |
51 | #include <net/pkt_sched.h> | 52 | #include <net/pkt_sched.h> |
52 | #include <net/netlink.h> | 53 | #include <net/netlink.h> |
54 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | ||
55 | #include <linux/wireless.h> | ||
56 | #include <net/iw_handler.h> | ||
57 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | ||
53 | 58 | ||
54 | DECLARE_MUTEX(rtnl_sem); | 59 | static DEFINE_MUTEX(rtnl_mutex); |
55 | 60 | ||
56 | void rtnl_lock(void) | 61 | void rtnl_lock(void) |
57 | { | 62 | { |
58 | rtnl_shlock(); | 63 | mutex_lock(&rtnl_mutex); |
59 | } | 64 | } |
60 | 65 | ||
61 | int rtnl_lock_interruptible(void) | 66 | void __rtnl_unlock(void) |
62 | { | 67 | { |
63 | return down_interruptible(&rtnl_sem); | 68 | mutex_unlock(&rtnl_mutex); |
64 | } | 69 | } |
65 | 70 | ||
66 | void rtnl_unlock(void) | 71 | void rtnl_unlock(void) |
67 | { | 72 | { |
68 | rtnl_shunlock(); | 73 | mutex_unlock(&rtnl_mutex); |
69 | 74 | if (rtnl && rtnl->sk_receive_queue.qlen) | |
75 | rtnl->sk_data_ready(rtnl, 0); | ||
70 | netdev_run_todo(); | 76 | netdev_run_todo(); |
71 | } | 77 | } |
72 | 78 | ||
79 | int rtnl_trylock(void) | ||
80 | { | ||
81 | return mutex_trylock(&rtnl_mutex); | ||
82 | } | ||
83 | |||
73 | int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len) | 84 | int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len) |
74 | { | 85 | { |
75 | memset(tb, 0, sizeof(struct rtattr*)*maxattr); | 86 | memset(tb, 0, sizeof(struct rtattr*)*maxattr); |
@@ -179,6 +190,33 @@ rtattr_failure: | |||
179 | } | 190 | } |
180 | 191 | ||
181 | 192 | ||
193 | static void set_operstate(struct net_device *dev, unsigned char transition) | ||
194 | { | ||
195 | unsigned char operstate = dev->operstate; | ||
196 | |||
197 | switch(transition) { | ||
198 | case IF_OPER_UP: | ||
199 | if ((operstate == IF_OPER_DORMANT || | ||
200 | operstate == IF_OPER_UNKNOWN) && | ||
201 | !netif_dormant(dev)) | ||
202 | operstate = IF_OPER_UP; | ||
203 | break; | ||
204 | |||
205 | case IF_OPER_DORMANT: | ||
206 | if (operstate == IF_OPER_UP || | ||
207 | operstate == IF_OPER_UNKNOWN) | ||
208 | operstate = IF_OPER_DORMANT; | ||
209 | break; | ||
210 | }; | ||
211 | |||
212 | if (dev->operstate != operstate) { | ||
213 | write_lock_bh(&dev_base_lock); | ||
214 | dev->operstate = operstate; | ||
215 | write_unlock_bh(&dev_base_lock); | ||
216 | netdev_state_change(dev); | ||
217 | } | ||
218 | } | ||
219 | |||
182 | static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | 220 | static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, |
183 | int type, u32 pid, u32 seq, u32 change, | 221 | int type, u32 pid, u32 seq, u32 change, |
184 | unsigned int flags) | 222 | unsigned int flags) |
@@ -209,6 +247,13 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
209 | } | 247 | } |
210 | 248 | ||
211 | if (1) { | 249 | if (1) { |
250 | u8 operstate = netif_running(dev)?dev->operstate:IF_OPER_DOWN; | ||
251 | u8 link_mode = dev->link_mode; | ||
252 | RTA_PUT(skb, IFLA_OPERSTATE, sizeof(operstate), &operstate); | ||
253 | RTA_PUT(skb, IFLA_LINKMODE, sizeof(link_mode), &link_mode); | ||
254 | } | ||
255 | |||
256 | if (1) { | ||
212 | struct rtnl_link_ifmap map = { | 257 | struct rtnl_link_ifmap map = { |
213 | .mem_start = dev->mem_start, | 258 | .mem_start = dev->mem_start, |
214 | .mem_end = dev->mem_end, | 259 | .mem_end = dev->mem_end, |
@@ -399,6 +444,22 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
399 | dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1])); | 444 | dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1])); |
400 | } | 445 | } |
401 | 446 | ||
447 | if (ida[IFLA_OPERSTATE - 1]) { | ||
448 | if (ida[IFLA_OPERSTATE - 1]->rta_len != RTA_LENGTH(sizeof(u8))) | ||
449 | goto out; | ||
450 | |||
451 | set_operstate(dev, *((u8 *) RTA_DATA(ida[IFLA_OPERSTATE - 1]))); | ||
452 | } | ||
453 | |||
454 | if (ida[IFLA_LINKMODE - 1]) { | ||
455 | if (ida[IFLA_LINKMODE - 1]->rta_len != RTA_LENGTH(sizeof(u8))) | ||
456 | goto out; | ||
457 | |||
458 | write_lock_bh(&dev_base_lock); | ||
459 | dev->link_mode = *((u8 *) RTA_DATA(ida[IFLA_LINKMODE - 1])); | ||
460 | write_unlock_bh(&dev_base_lock); | ||
461 | } | ||
462 | |||
402 | if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) { | 463 | if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) { |
403 | char ifname[IFNAMSIZ]; | 464 | char ifname[IFNAMSIZ]; |
404 | 465 | ||
@@ -410,6 +471,17 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
410 | goto out; | 471 | goto out; |
411 | } | 472 | } |
412 | 473 | ||
474 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | ||
475 | if (ida[IFLA_WIRELESS - 1]) { | ||
476 | |||
477 | /* Call Wireless Extensions. | ||
478 | * Various stuff checked in there... */ | ||
479 | err = wireless_rtnetlink_set(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len); | ||
480 | if (err) | ||
481 | goto out; | ||
482 | } | ||
483 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | ||
484 | |||
413 | err = 0; | 485 | err = 0; |
414 | 486 | ||
415 | out: | 487 | out: |
@@ -420,6 +492,83 @@ out: | |||
420 | return err; | 492 | return err; |
421 | } | 493 | } |
422 | 494 | ||
495 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | ||
496 | static int do_getlink(struct sk_buff *in_skb, struct nlmsghdr* in_nlh, void *arg) | ||
497 | { | ||
498 | struct ifinfomsg *ifm = NLMSG_DATA(in_nlh); | ||
499 | struct rtattr **ida = arg; | ||
500 | struct net_device *dev; | ||
501 | struct ifinfomsg *r; | ||
502 | struct nlmsghdr *nlh; | ||
503 | int err = -ENOBUFS; | ||
504 | struct sk_buff *skb; | ||
505 | unsigned char *b; | ||
506 | char *iw_buf = NULL; | ||
507 | int iw_buf_len = 0; | ||
508 | |||
509 | if (ifm->ifi_index >= 0) | ||
510 | dev = dev_get_by_index(ifm->ifi_index); | ||
511 | else | ||
512 | return -EINVAL; | ||
513 | if (!dev) | ||
514 | return -ENODEV; | ||
515 | |||
516 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | ||
517 | if (ida[IFLA_WIRELESS - 1]) { | ||
518 | |||
519 | /* Call Wireless Extensions. We need to know the size before | ||
520 | * we can alloc. Various stuff checked in there... */ | ||
521 | err = wireless_rtnetlink_get(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len, &iw_buf, &iw_buf_len); | ||
522 | if (err) | ||
523 | goto out; | ||
524 | } | ||
525 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | ||
526 | |||
527 | /* Create a skb big enough to include all the data. | ||
528 | * Some requests are way bigger than 4k... Jean II */ | ||
529 | skb = alloc_skb((NLMSG_LENGTH(sizeof(*r))) + (RTA_SPACE(iw_buf_len)), | ||
530 | GFP_KERNEL); | ||
531 | if (!skb) | ||
532 | goto out; | ||
533 | b = skb->tail; | ||
534 | |||
535 | /* Put in the message the usual good stuff */ | ||
536 | nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, in_nlh->nlmsg_seq, | ||
537 | RTM_NEWLINK, sizeof(*r)); | ||
538 | r = NLMSG_DATA(nlh); | ||
539 | r->ifi_family = AF_UNSPEC; | ||
540 | r->__ifi_pad = 0; | ||
541 | r->ifi_type = dev->type; | ||
542 | r->ifi_index = dev->ifindex; | ||
543 | r->ifi_flags = dev->flags; | ||
544 | r->ifi_change = 0; | ||
545 | |||
546 | /* Put the wireless payload if it exist */ | ||
547 | if(iw_buf != NULL) | ||
548 | RTA_PUT(skb, IFLA_WIRELESS, iw_buf_len, | ||
549 | iw_buf + IW_EV_POINT_OFF); | ||
550 | |||
551 | nlh->nlmsg_len = skb->tail - b; | ||
552 | |||
553 | /* Needed ? */ | ||
554 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | ||
555 | |||
556 | err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | ||
557 | if (err > 0) | ||
558 | err = 0; | ||
559 | out: | ||
560 | if(iw_buf != NULL) | ||
561 | kfree(iw_buf); | ||
562 | dev_put(dev); | ||
563 | return err; | ||
564 | |||
565 | rtattr_failure: | ||
566 | nlmsg_failure: | ||
567 | kfree_skb(skb); | ||
568 | goto out; | ||
569 | } | ||
570 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | ||
571 | |||
423 | static int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb) | 572 | static int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb) |
424 | { | 573 | { |
425 | int idx; | 574 | int idx; |
@@ -575,9 +724,9 @@ static void rtnetlink_rcv(struct sock *sk, int len) | |||
575 | unsigned int qlen = 0; | 724 | unsigned int qlen = 0; |
576 | 725 | ||
577 | do { | 726 | do { |
578 | rtnl_lock(); | 727 | mutex_lock(&rtnl_mutex); |
579 | netlink_run_queue(sk, &qlen, &rtnetlink_rcv_msg); | 728 | netlink_run_queue(sk, &qlen, &rtnetlink_rcv_msg); |
580 | up(&rtnl_sem); | 729 | mutex_unlock(&rtnl_mutex); |
581 | 730 | ||
582 | netdev_run_todo(); | 731 | netdev_run_todo(); |
583 | } while (qlen); | 732 | } while (qlen); |
@@ -585,7 +734,11 @@ static void rtnetlink_rcv(struct sock *sk, int len) | |||
585 | 734 | ||
586 | static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] = | 735 | static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] = |
587 | { | 736 | { |
588 | [RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo }, | 737 | [RTM_GETLINK - RTM_BASE] = { |
738 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | ||
739 | .doit = do_getlink, | ||
740 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | ||
741 | .dumpit = rtnetlink_dump_ifinfo }, | ||
589 | [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink }, | 742 | [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink }, |
590 | [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, | 743 | [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, |
591 | [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, | 744 | [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, |
@@ -654,6 +807,5 @@ EXPORT_SYMBOL(rtnetlink_links); | |||
654 | EXPORT_SYMBOL(rtnetlink_put_metrics); | 807 | EXPORT_SYMBOL(rtnetlink_put_metrics); |
655 | EXPORT_SYMBOL(rtnl); | 808 | EXPORT_SYMBOL(rtnl); |
656 | EXPORT_SYMBOL(rtnl_lock); | 809 | EXPORT_SYMBOL(rtnl_lock); |
657 | EXPORT_SYMBOL(rtnl_lock_interruptible); | 810 | EXPORT_SYMBOL(rtnl_trylock); |
658 | EXPORT_SYMBOL(rtnl_sem); | ||
659 | EXPORT_SYMBOL(rtnl_unlock); | 811 | EXPORT_SYMBOL(rtnl_unlock); |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 2144952d1c6c..c9f878454531 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -356,6 +356,24 @@ void __kfree_skb(struct sk_buff *skb) | |||
356 | } | 356 | } |
357 | 357 | ||
358 | /** | 358 | /** |
359 | * kfree_skb - free an sk_buff | ||
360 | * @skb: buffer to free | ||
361 | * | ||
362 | * Drop a reference to the buffer and free it if the usage count has | ||
363 | * hit zero. | ||
364 | */ | ||
365 | void kfree_skb(struct sk_buff *skb) | ||
366 | { | ||
367 | if (unlikely(!skb)) | ||
368 | return; | ||
369 | if (likely(atomic_read(&skb->users) == 1)) | ||
370 | smp_rmb(); | ||
371 | else if (likely(!atomic_dec_and_test(&skb->users))) | ||
372 | return; | ||
373 | __kfree_skb(skb); | ||
374 | } | ||
375 | |||
376 | /** | ||
359 | * skb_clone - duplicate an sk_buff | 377 | * skb_clone - duplicate an sk_buff |
360 | * @skb: buffer to clone | 378 | * @skb: buffer to clone |
361 | * @gfp_mask: allocation priority | 379 | * @gfp_mask: allocation priority |
@@ -1777,6 +1795,29 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, | |||
1777 | return 0; | 1795 | return 0; |
1778 | } | 1796 | } |
1779 | 1797 | ||
1798 | /** | ||
1799 | * skb_pull_rcsum - pull skb and update receive checksum | ||
1800 | * @skb: buffer to update | ||
1801 | * @start: start of data before pull | ||
1802 | * @len: length of data pulled | ||
1803 | * | ||
1804 | * This function performs an skb_pull on the packet and updates | ||
1805 | * update the CHECKSUM_HW checksum. It should be used on receive | ||
1806 | * path processing instead of skb_pull unless you know that the | ||
1807 | * checksum difference is zero (e.g., a valid IP header) or you | ||
1808 | * are setting ip_summed to CHECKSUM_NONE. | ||
1809 | */ | ||
1810 | unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len) | ||
1811 | { | ||
1812 | BUG_ON(len > skb->len); | ||
1813 | skb->len -= len; | ||
1814 | BUG_ON(skb->len < skb->data_len); | ||
1815 | skb_postpull_rcsum(skb, skb->data, len); | ||
1816 | return skb->data += len; | ||
1817 | } | ||
1818 | |||
1819 | EXPORT_SYMBOL_GPL(skb_pull_rcsum); | ||
1820 | |||
1780 | void __init skb_init(void) | 1821 | void __init skb_init(void) |
1781 | { | 1822 | { |
1782 | skbuff_head_cache = kmem_cache_create("skbuff_head_cache", | 1823 | skbuff_head_cache = kmem_cache_create("skbuff_head_cache", |
@@ -1799,6 +1840,7 @@ void __init skb_init(void) | |||
1799 | 1840 | ||
1800 | EXPORT_SYMBOL(___pskb_trim); | 1841 | EXPORT_SYMBOL(___pskb_trim); |
1801 | EXPORT_SYMBOL(__kfree_skb); | 1842 | EXPORT_SYMBOL(__kfree_skb); |
1843 | EXPORT_SYMBOL(kfree_skb); | ||
1802 | EXPORT_SYMBOL(__pskb_pull_tail); | 1844 | EXPORT_SYMBOL(__pskb_pull_tail); |
1803 | EXPORT_SYMBOL(__alloc_skb); | 1845 | EXPORT_SYMBOL(__alloc_skb); |
1804 | EXPORT_SYMBOL(pskb_copy); | 1846 | EXPORT_SYMBOL(pskb_copy); |
diff --git a/net/core/sock.c b/net/core/sock.c index 6e00811d44bc..1a7e6eac90b0 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -616,7 +616,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, | |||
616 | break; | 616 | break; |
617 | 617 | ||
618 | case SO_PEERSEC: | 618 | case SO_PEERSEC: |
619 | return security_socket_getpeersec(sock, optval, optlen, len); | 619 | return security_socket_getpeersec_stream(sock, optval, optlen, len); |
620 | 620 | ||
621 | default: | 621 | default: |
622 | return(-ENOPROTOOPT); | 622 | return(-ENOPROTOOPT); |
@@ -1385,6 +1385,20 @@ int sock_common_getsockopt(struct socket *sock, int level, int optname, | |||
1385 | 1385 | ||
1386 | EXPORT_SYMBOL(sock_common_getsockopt); | 1386 | EXPORT_SYMBOL(sock_common_getsockopt); |
1387 | 1387 | ||
1388 | #ifdef CONFIG_COMPAT | ||
1389 | int compat_sock_common_getsockopt(struct socket *sock, int level, int optname, | ||
1390 | char __user *optval, int __user *optlen) | ||
1391 | { | ||
1392 | struct sock *sk = sock->sk; | ||
1393 | |||
1394 | if (sk->sk_prot->compat_setsockopt != NULL) | ||
1395 | return sk->sk_prot->compat_getsockopt(sk, level, optname, | ||
1396 | optval, optlen); | ||
1397 | return sk->sk_prot->getsockopt(sk, level, optname, optval, optlen); | ||
1398 | } | ||
1399 | EXPORT_SYMBOL(compat_sock_common_getsockopt); | ||
1400 | #endif | ||
1401 | |||
1388 | int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock, | 1402 | int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock, |
1389 | struct msghdr *msg, size_t size, int flags) | 1403 | struct msghdr *msg, size_t size, int flags) |
1390 | { | 1404 | { |
@@ -1414,6 +1428,20 @@ int sock_common_setsockopt(struct socket *sock, int level, int optname, | |||
1414 | 1428 | ||
1415 | EXPORT_SYMBOL(sock_common_setsockopt); | 1429 | EXPORT_SYMBOL(sock_common_setsockopt); |
1416 | 1430 | ||
1431 | #ifdef CONFIG_COMPAT | ||
1432 | int compat_sock_common_setsockopt(struct socket *sock, int level, int optname, | ||
1433 | char __user *optval, int optlen) | ||
1434 | { | ||
1435 | struct sock *sk = sock->sk; | ||
1436 | |||
1437 | if (sk->sk_prot->compat_setsockopt != NULL) | ||
1438 | return sk->sk_prot->compat_setsockopt(sk, level, optname, | ||
1439 | optval, optlen); | ||
1440 | return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen); | ||
1441 | } | ||
1442 | EXPORT_SYMBOL(compat_sock_common_setsockopt); | ||
1443 | #endif | ||
1444 | |||
1417 | void sk_common_release(struct sock *sk) | 1445 | void sk_common_release(struct sock *sk) |
1418 | { | 1446 | { |
1419 | if (sk->sk_prot->destroy) | 1447 | if (sk->sk_prot->destroy) |
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 2f278c8e4743..710453656721 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c | |||
@@ -26,6 +26,11 @@ extern int sysctl_core_destroy_delay; | |||
26 | extern char sysctl_divert_version[]; | 26 | extern char sysctl_divert_version[]; |
27 | #endif /* CONFIG_NET_DIVERT */ | 27 | #endif /* CONFIG_NET_DIVERT */ |
28 | 28 | ||
29 | #ifdef CONFIG_XFRM | ||
30 | extern u32 sysctl_xfrm_aevent_etime; | ||
31 | extern u32 sysctl_xfrm_aevent_rseqth; | ||
32 | #endif | ||
33 | |||
29 | ctl_table core_table[] = { | 34 | ctl_table core_table[] = { |
30 | #ifdef CONFIG_NET | 35 | #ifdef CONFIG_NET |
31 | { | 36 | { |
@@ -111,6 +116,24 @@ ctl_table core_table[] = { | |||
111 | .proc_handler = &proc_dostring | 116 | .proc_handler = &proc_dostring |
112 | }, | 117 | }, |
113 | #endif /* CONFIG_NET_DIVERT */ | 118 | #endif /* CONFIG_NET_DIVERT */ |
119 | #ifdef CONFIG_XFRM | ||
120 | { | ||
121 | .ctl_name = NET_CORE_AEVENT_ETIME, | ||
122 | .procname = "xfrm_aevent_etime", | ||
123 | .data = &sysctl_xfrm_aevent_etime, | ||
124 | .maxlen = sizeof(u32), | ||
125 | .mode = 0644, | ||
126 | .proc_handler = &proc_dointvec | ||
127 | }, | ||
128 | { | ||
129 | .ctl_name = NET_CORE_AEVENT_RSEQTH, | ||
130 | .procname = "xfrm_aevent_rseqth", | ||
131 | .data = &sysctl_xfrm_aevent_rseqth, | ||
132 | .maxlen = sizeof(u32), | ||
133 | .mode = 0644, | ||
134 | .proc_handler = &proc_dointvec | ||
135 | }, | ||
136 | #endif /* CONFIG_XFRM */ | ||
114 | #endif /* CONFIG_NET */ | 137 | #endif /* CONFIG_NET */ |
115 | { | 138 | { |
116 | .ctl_name = NET_CORE_SOMAXCONN, | 139 | .ctl_name = NET_CORE_SOMAXCONN, |
diff --git a/net/core/wireless.c b/net/core/wireless.c index 2add7ed609e9..81d6995fcfdb 100644 --- a/net/core/wireless.c +++ b/net/core/wireless.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * This file implement the Wireless Extensions APIs. | 2 | * This file implement the Wireless Extensions APIs. |
3 | * | 3 | * |
4 | * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> | 4 | * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> |
5 | * Copyright (c) 1997-2005 Jean Tourrilhes, All Rights Reserved. | 5 | * Copyright (c) 1997-2006 Jean Tourrilhes, All Rights Reserved. |
6 | * | 6 | * |
7 | * (As all part of the Linux kernel, this file is GPL) | 7 | * (As all part of the Linux kernel, this file is GPL) |
8 | */ | 8 | */ |
@@ -65,6 +65,9 @@ | |||
65 | * o Start deprecating dev->get_wireless_stats, output a warning | 65 | * o Start deprecating dev->get_wireless_stats, output a warning |
66 | * o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless | 66 | * o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless |
67 | * o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats) | 67 | * o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats) |
68 | * | ||
69 | * v8 - 17.02.06 - Jean II | ||
70 | * o RtNetlink requests support (SET/GET) | ||
68 | */ | 71 | */ |
69 | 72 | ||
70 | /***************************** INCLUDES *****************************/ | 73 | /***************************** INCLUDES *****************************/ |
@@ -89,11 +92,13 @@ | |||
89 | 92 | ||
90 | /* Debugging stuff */ | 93 | /* Debugging stuff */ |
91 | #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ | 94 | #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ |
95 | #undef WE_RTNETLINK_DEBUG /* Debug RtNetlink API */ | ||
92 | #undef WE_EVENT_DEBUG /* Debug Event dispatcher */ | 96 | #undef WE_EVENT_DEBUG /* Debug Event dispatcher */ |
93 | #undef WE_SPY_DEBUG /* Debug enhanced spy support */ | 97 | #undef WE_SPY_DEBUG /* Debug enhanced spy support */ |
94 | 98 | ||
95 | /* Options */ | 99 | /* Options */ |
96 | #define WE_EVENT_NETLINK /* Propagate events using rtnetlink */ | 100 | //CONFIG_NET_WIRELESS_RTNETLINK /* Wireless requests over RtNetlink */ |
101 | #define WE_EVENT_RTNETLINK /* Propagate events using RtNetlink */ | ||
97 | #define WE_SET_EVENT /* Generate an event on some set commands */ | 102 | #define WE_SET_EVENT /* Generate an event on some set commands */ |
98 | 103 | ||
99 | /************************* GLOBAL VARIABLES *************************/ | 104 | /************************* GLOBAL VARIABLES *************************/ |
@@ -156,13 +161,18 @@ static const struct iw_ioctl_description standard_ioctl[] = { | |||
156 | .header_type = IW_HEADER_TYPE_NULL, | 161 | .header_type = IW_HEADER_TYPE_NULL, |
157 | }, | 162 | }, |
158 | [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */ | 163 | [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */ |
159 | .header_type = IW_HEADER_TYPE_NULL, | 164 | .header_type = IW_HEADER_TYPE_POINT, |
165 | .token_size = sizeof(struct iw_priv_args), | ||
166 | .max_tokens = 16, | ||
167 | .flags = IW_DESCR_FLAG_NOMAX, | ||
160 | }, | 168 | }, |
161 | [SIOCSIWSTATS - SIOCIWFIRST] = { | 169 | [SIOCSIWSTATS - SIOCIWFIRST] = { |
162 | .header_type = IW_HEADER_TYPE_NULL, | 170 | .header_type = IW_HEADER_TYPE_NULL, |
163 | }, | 171 | }, |
164 | [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */ | 172 | [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */ |
165 | .header_type = IW_HEADER_TYPE_NULL, | 173 | .header_type = IW_HEADER_TYPE_POINT, |
174 | .token_size = 1, | ||
175 | .max_tokens = sizeof(struct iw_statistics), | ||
166 | .flags = IW_DESCR_FLAG_DUMP, | 176 | .flags = IW_DESCR_FLAG_DUMP, |
167 | }, | 177 | }, |
168 | [SIOCSIWSPY - SIOCIWFIRST] = { | 178 | [SIOCSIWSPY - SIOCIWFIRST] = { |
@@ -529,6 +539,70 @@ static inline int adjust_priv_size(__u16 args, | |||
529 | return num * iw_priv_type_size[type]; | 539 | return num * iw_priv_type_size[type]; |
530 | } | 540 | } |
531 | 541 | ||
542 | /* ---------------------------------------------------------------- */ | ||
543 | /* | ||
544 | * Standard Wireless Handler : get wireless stats | ||
545 | * Allow programatic access to /proc/net/wireless even if /proc | ||
546 | * doesn't exist... Also more efficient... | ||
547 | */ | ||
548 | static int iw_handler_get_iwstats(struct net_device * dev, | ||
549 | struct iw_request_info * info, | ||
550 | union iwreq_data * wrqu, | ||
551 | char * extra) | ||
552 | { | ||
553 | /* Get stats from the driver */ | ||
554 | struct iw_statistics *stats; | ||
555 | |||
556 | stats = get_wireless_stats(dev); | ||
557 | if (stats != (struct iw_statistics *) NULL) { | ||
558 | |||
559 | /* Copy statistics to extra */ | ||
560 | memcpy(extra, stats, sizeof(struct iw_statistics)); | ||
561 | wrqu->data.length = sizeof(struct iw_statistics); | ||
562 | |||
563 | /* Check if we need to clear the updated flag */ | ||
564 | if(wrqu->data.flags != 0) | ||
565 | stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; | ||
566 | return 0; | ||
567 | } else | ||
568 | return -EOPNOTSUPP; | ||
569 | } | ||
570 | |||
571 | /* ---------------------------------------------------------------- */ | ||
572 | /* | ||
573 | * Standard Wireless Handler : get iwpriv definitions | ||
574 | * Export the driver private handler definition | ||
575 | * They will be picked up by tools like iwpriv... | ||
576 | */ | ||
577 | static int iw_handler_get_private(struct net_device * dev, | ||
578 | struct iw_request_info * info, | ||
579 | union iwreq_data * wrqu, | ||
580 | char * extra) | ||
581 | { | ||
582 | /* Check if the driver has something to export */ | ||
583 | if((dev->wireless_handlers->num_private_args == 0) || | ||
584 | (dev->wireless_handlers->private_args == NULL)) | ||
585 | return -EOPNOTSUPP; | ||
586 | |||
587 | /* Check if there is enough buffer up there */ | ||
588 | if(wrqu->data.length < dev->wireless_handlers->num_private_args) { | ||
589 | /* User space can't know in advance how large the buffer | ||
590 | * needs to be. Give it a hint, so that we can support | ||
591 | * any size buffer we want somewhat efficiently... */ | ||
592 | wrqu->data.length = dev->wireless_handlers->num_private_args; | ||
593 | return -E2BIG; | ||
594 | } | ||
595 | |||
596 | /* Set the number of available ioctls. */ | ||
597 | wrqu->data.length = dev->wireless_handlers->num_private_args; | ||
598 | |||
599 | /* Copy structure to the user buffer. */ | ||
600 | memcpy(extra, dev->wireless_handlers->private_args, | ||
601 | sizeof(struct iw_priv_args) * wrqu->data.length); | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
532 | 606 | ||
533 | /******************** /proc/net/wireless SUPPORT ********************/ | 607 | /******************** /proc/net/wireless SUPPORT ********************/ |
534 | /* | 608 | /* |
@@ -630,81 +704,14 @@ int __init wireless_proc_init(void) | |||
630 | 704 | ||
631 | /* ---------------------------------------------------------------- */ | 705 | /* ---------------------------------------------------------------- */ |
632 | /* | 706 | /* |
633 | * Allow programatic access to /proc/net/wireless even if /proc | ||
634 | * doesn't exist... Also more efficient... | ||
635 | */ | ||
636 | static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr) | ||
637 | { | ||
638 | /* Get stats from the driver */ | ||
639 | struct iw_statistics *stats; | ||
640 | |||
641 | stats = get_wireless_stats(dev); | ||
642 | if (stats != (struct iw_statistics *) NULL) { | ||
643 | struct iwreq * wrq = (struct iwreq *)ifr; | ||
644 | |||
645 | /* Copy statistics to the user buffer */ | ||
646 | if(copy_to_user(wrq->u.data.pointer, stats, | ||
647 | sizeof(struct iw_statistics))) | ||
648 | return -EFAULT; | ||
649 | |||
650 | /* Check if we need to clear the updated flag */ | ||
651 | if(wrq->u.data.flags != 0) | ||
652 | stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; | ||
653 | return 0; | ||
654 | } else | ||
655 | return -EOPNOTSUPP; | ||
656 | } | ||
657 | |||
658 | /* ---------------------------------------------------------------- */ | ||
659 | /* | ||
660 | * Export the driver private handler definition | ||
661 | * They will be picked up by tools like iwpriv... | ||
662 | */ | ||
663 | static inline int ioctl_export_private(struct net_device * dev, | ||
664 | struct ifreq * ifr) | ||
665 | { | ||
666 | struct iwreq * iwr = (struct iwreq *) ifr; | ||
667 | |||
668 | /* Check if the driver has something to export */ | ||
669 | if((dev->wireless_handlers->num_private_args == 0) || | ||
670 | (dev->wireless_handlers->private_args == NULL)) | ||
671 | return -EOPNOTSUPP; | ||
672 | |||
673 | /* Check NULL pointer */ | ||
674 | if(iwr->u.data.pointer == NULL) | ||
675 | return -EFAULT; | ||
676 | |||
677 | /* Check if there is enough buffer up there */ | ||
678 | if(iwr->u.data.length < dev->wireless_handlers->num_private_args) { | ||
679 | /* User space can't know in advance how large the buffer | ||
680 | * needs to be. Give it a hint, so that we can support | ||
681 | * any size buffer we want somewhat efficiently... */ | ||
682 | iwr->u.data.length = dev->wireless_handlers->num_private_args; | ||
683 | return -E2BIG; | ||
684 | } | ||
685 | |||
686 | /* Set the number of available ioctls. */ | ||
687 | iwr->u.data.length = dev->wireless_handlers->num_private_args; | ||
688 | |||
689 | /* Copy structure to the user buffer. */ | ||
690 | if (copy_to_user(iwr->u.data.pointer, | ||
691 | dev->wireless_handlers->private_args, | ||
692 | sizeof(struct iw_priv_args) * iwr->u.data.length)) | ||
693 | return -EFAULT; | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | /* ---------------------------------------------------------------- */ | ||
699 | /* | ||
700 | * Wrapper to call a standard Wireless Extension handler. | 707 | * Wrapper to call a standard Wireless Extension handler. |
701 | * We do various checks and also take care of moving data between | 708 | * We do various checks and also take care of moving data between |
702 | * user space and kernel space. | 709 | * user space and kernel space. |
703 | */ | 710 | */ |
704 | static inline int ioctl_standard_call(struct net_device * dev, | 711 | static int ioctl_standard_call(struct net_device * dev, |
705 | struct ifreq * ifr, | 712 | struct ifreq * ifr, |
706 | unsigned int cmd, | 713 | unsigned int cmd, |
707 | iw_handler handler) | 714 | iw_handler handler) |
708 | { | 715 | { |
709 | struct iwreq * iwr = (struct iwreq *) ifr; | 716 | struct iwreq * iwr = (struct iwreq *) ifr; |
710 | const struct iw_ioctl_description * descr; | 717 | const struct iw_ioctl_description * descr; |
@@ -1048,14 +1055,20 @@ int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) | |||
1048 | { | 1055 | { |
1049 | case SIOCGIWSTATS: | 1056 | case SIOCGIWSTATS: |
1050 | /* Get Wireless Stats */ | 1057 | /* Get Wireless Stats */ |
1051 | return dev_iwstats(dev, ifr); | 1058 | return ioctl_standard_call(dev, |
1059 | ifr, | ||
1060 | cmd, | ||
1061 | &iw_handler_get_iwstats); | ||
1052 | 1062 | ||
1053 | case SIOCGIWPRIV: | 1063 | case SIOCGIWPRIV: |
1054 | /* Check if we have some wireless handlers defined */ | 1064 | /* Check if we have some wireless handlers defined */ |
1055 | if(dev->wireless_handlers != NULL) { | 1065 | if(dev->wireless_handlers != NULL) { |
1056 | /* We export to user space the definition of | 1066 | /* We export to user space the definition of |
1057 | * the private handler ourselves */ | 1067 | * the private handler ourselves */ |
1058 | return ioctl_export_private(dev, ifr); | 1068 | return ioctl_standard_call(dev, |
1069 | ifr, | ||
1070 | cmd, | ||
1071 | &iw_handler_get_private); | ||
1059 | } | 1072 | } |
1060 | // ## Fall-through for old API ## | 1073 | // ## Fall-through for old API ## |
1061 | default: | 1074 | default: |
@@ -1088,16 +1101,739 @@ int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) | |||
1088 | return -EINVAL; | 1101 | return -EINVAL; |
1089 | } | 1102 | } |
1090 | 1103 | ||
1104 | /********************** RTNETLINK REQUEST API **********************/ | ||
1105 | /* | ||
1106 | * The alternate user space API to configure all those Wireless Extensions | ||
1107 | * is through RtNetlink. | ||
1108 | * This API support only the new driver API (iw_handler). | ||
1109 | * | ||
1110 | * This RtNetlink API use the same query/reply model as the ioctl API. | ||
1111 | * Maximum effort has been done to fit in the RtNetlink model, and | ||
1112 | * we support both RtNetlink Set and RtNelink Get operations. | ||
1113 | * On the other hand, we don't offer Dump operations because of the | ||
1114 | * following reasons : | ||
1115 | * o Large number of parameters, most optional | ||
1116 | * o Large size of some parameters (> 100 bytes) | ||
1117 | * o Each parameters need to be extracted from hardware | ||
1118 | * o Scan requests can take seconds and disable network activity. | ||
1119 | * Because of this high cost/overhead, we want to return only the | ||
1120 | * parameters the user application is really interested in. | ||
1121 | * We could offer partial Dump using the IW_DESCR_FLAG_DUMP flag. | ||
1122 | * | ||
1123 | * The API uses the standard RtNetlink socket. When the RtNetlink code | ||
1124 | * find a IFLA_WIRELESS field in a RtNetlink SET_LINK request, | ||
1125 | * it calls here. | ||
1126 | */ | ||
1127 | |||
1128 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | ||
1129 | /* ---------------------------------------------------------------- */ | ||
1130 | /* | ||
1131 | * Wrapper to call a standard Wireless Extension GET handler. | ||
1132 | * We do various checks and call the handler with the proper args. | ||
1133 | */ | ||
1134 | static int rtnetlink_standard_get(struct net_device * dev, | ||
1135 | struct iw_event * request, | ||
1136 | int request_len, | ||
1137 | iw_handler handler, | ||
1138 | char ** p_buf, | ||
1139 | int * p_len) | ||
1140 | { | ||
1141 | const struct iw_ioctl_description * descr = NULL; | ||
1142 | unsigned int cmd; | ||
1143 | union iwreq_data * wrqu; | ||
1144 | int hdr_len; | ||
1145 | struct iw_request_info info; | ||
1146 | char * buffer = NULL; | ||
1147 | int buffer_size = 0; | ||
1148 | int ret = -EINVAL; | ||
1149 | |||
1150 | /* Get the description of the Request */ | ||
1151 | cmd = request->cmd; | ||
1152 | if((cmd - SIOCIWFIRST) >= standard_ioctl_num) | ||
1153 | return -EOPNOTSUPP; | ||
1154 | descr = &(standard_ioctl[cmd - SIOCIWFIRST]); | ||
1155 | |||
1156 | #ifdef WE_RTNETLINK_DEBUG | ||
1157 | printk(KERN_DEBUG "%s (WE.r) : Found standard handler for 0x%04X\n", | ||
1158 | dev->name, cmd); | ||
1159 | printk(KERN_DEBUG "%s (WE.r) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); | ||
1160 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1161 | |||
1162 | /* Check if wrqu is complete */ | ||
1163 | hdr_len = event_type_size[descr->header_type]; | ||
1164 | if(request_len < hdr_len) { | ||
1165 | #ifdef WE_RTNETLINK_DEBUG | ||
1166 | printk(KERN_DEBUG | ||
1167 | "%s (WE.r) : Wireless request too short (%d)\n", | ||
1168 | dev->name, request_len); | ||
1169 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1170 | return -EINVAL; | ||
1171 | } | ||
1172 | |||
1173 | /* Prepare the call */ | ||
1174 | info.cmd = cmd; | ||
1175 | info.flags = 0; | ||
1176 | |||
1177 | /* Check if we have extra data in the reply or not */ | ||
1178 | if(descr->header_type != IW_HEADER_TYPE_POINT) { | ||
1179 | |||
1180 | /* Create the kernel buffer that we will return. | ||
1181 | * It's at an offset to match the TYPE_POINT case... */ | ||
1182 | buffer_size = request_len + IW_EV_POINT_OFF; | ||
1183 | buffer = kmalloc(buffer_size, GFP_KERNEL); | ||
1184 | if (buffer == NULL) { | ||
1185 | return -ENOMEM; | ||
1186 | } | ||
1187 | /* Copy event data */ | ||
1188 | memcpy(buffer + IW_EV_POINT_OFF, request, request_len); | ||
1189 | /* Use our own copy of wrqu */ | ||
1190 | wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF | ||
1191 | + IW_EV_LCP_LEN); | ||
1192 | |||
1193 | /* No extra arguments. Trivial to handle */ | ||
1194 | ret = handler(dev, &info, wrqu, NULL); | ||
1195 | |||
1196 | } else { | ||
1197 | union iwreq_data wrqu_point; | ||
1198 | char * extra = NULL; | ||
1199 | int extra_size = 0; | ||
1200 | |||
1201 | /* Get a temp copy of wrqu (skip pointer) */ | ||
1202 | memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, | ||
1203 | ((char *) request) + IW_EV_LCP_LEN, | ||
1204 | IW_EV_POINT_LEN - IW_EV_LCP_LEN); | ||
1205 | |||
1206 | /* Calculate space needed by arguments. Always allocate | ||
1207 | * for max space. Easier, and won't last long... */ | ||
1208 | extra_size = descr->max_tokens * descr->token_size; | ||
1209 | /* Support for very large requests */ | ||
1210 | if((descr->flags & IW_DESCR_FLAG_NOMAX) && | ||
1211 | (wrqu_point.data.length > descr->max_tokens)) | ||
1212 | extra_size = (wrqu_point.data.length | ||
1213 | * descr->token_size); | ||
1214 | buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF; | ||
1215 | #ifdef WE_RTNETLINK_DEBUG | ||
1216 | printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n", | ||
1217 | dev->name, extra_size, buffer_size); | ||
1218 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1219 | |||
1220 | /* Create the kernel buffer that we will return */ | ||
1221 | buffer = kmalloc(buffer_size, GFP_KERNEL); | ||
1222 | if (buffer == NULL) { | ||
1223 | return -ENOMEM; | ||
1224 | } | ||
1225 | |||
1226 | /* Put wrqu in the right place (just before extra). | ||
1227 | * Leave space for IWE header and dummy pointer... | ||
1228 | * Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned... | ||
1229 | */ | ||
1230 | memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF, | ||
1231 | ((char *) &wrqu_point) + IW_EV_POINT_OFF, | ||
1232 | IW_EV_POINT_LEN - IW_EV_LCP_LEN); | ||
1233 | wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN); | ||
1234 | |||
1235 | /* Extra comes logically after that. Offset +12 bytes. */ | ||
1236 | extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN; | ||
1237 | |||
1238 | /* Call the handler */ | ||
1239 | ret = handler(dev, &info, wrqu, extra); | ||
1240 | |||
1241 | /* Calculate real returned length */ | ||
1242 | extra_size = (wrqu->data.length * descr->token_size); | ||
1243 | /* Re-adjust reply size */ | ||
1244 | request->len = extra_size + IW_EV_POINT_LEN; | ||
1245 | |||
1246 | /* Put the iwe header where it should, i.e. scrap the | ||
1247 | * dummy pointer. */ | ||
1248 | memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN); | ||
1249 | |||
1250 | #ifdef WE_RTNETLINK_DEBUG | ||
1251 | printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size); | ||
1252 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1253 | |||
1254 | /* Check if there is enough buffer up there */ | ||
1255 | if(wrqu_point.data.length < wrqu->data.length) | ||
1256 | ret = -E2BIG; | ||
1257 | } | ||
1258 | |||
1259 | /* Return the buffer to the caller */ | ||
1260 | if (!ret) { | ||
1261 | *p_buf = buffer; | ||
1262 | *p_len = request->len; | ||
1263 | } else { | ||
1264 | /* Cleanup */ | ||
1265 | if(buffer) | ||
1266 | kfree(buffer); | ||
1267 | } | ||
1268 | |||
1269 | return ret; | ||
1270 | } | ||
1271 | |||
1272 | /* ---------------------------------------------------------------- */ | ||
1273 | /* | ||
1274 | * Wrapper to call a standard Wireless Extension SET handler. | ||
1275 | * We do various checks and call the handler with the proper args. | ||
1276 | */ | ||
1277 | static inline int rtnetlink_standard_set(struct net_device * dev, | ||
1278 | struct iw_event * request, | ||
1279 | int request_len, | ||
1280 | iw_handler handler) | ||
1281 | { | ||
1282 | const struct iw_ioctl_description * descr = NULL; | ||
1283 | unsigned int cmd; | ||
1284 | union iwreq_data * wrqu; | ||
1285 | union iwreq_data wrqu_point; | ||
1286 | int hdr_len; | ||
1287 | char * extra = NULL; | ||
1288 | int extra_size = 0; | ||
1289 | struct iw_request_info info; | ||
1290 | int ret = -EINVAL; | ||
1291 | |||
1292 | /* Get the description of the Request */ | ||
1293 | cmd = request->cmd; | ||
1294 | if((cmd - SIOCIWFIRST) >= standard_ioctl_num) | ||
1295 | return -EOPNOTSUPP; | ||
1296 | descr = &(standard_ioctl[cmd - SIOCIWFIRST]); | ||
1297 | |||
1298 | #ifdef WE_RTNETLINK_DEBUG | ||
1299 | printk(KERN_DEBUG "%s (WE.r) : Found standard SET handler for 0x%04X\n", | ||
1300 | dev->name, cmd); | ||
1301 | printk(KERN_DEBUG "%s (WE.r) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); | ||
1302 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1303 | |||
1304 | /* Extract fixed header from request. This is properly aligned. */ | ||
1305 | wrqu = &request->u; | ||
1306 | |||
1307 | /* Check if wrqu is complete */ | ||
1308 | hdr_len = event_type_size[descr->header_type]; | ||
1309 | if(request_len < hdr_len) { | ||
1310 | #ifdef WE_RTNETLINK_DEBUG | ||
1311 | printk(KERN_DEBUG | ||
1312 | "%s (WE.r) : Wireless request too short (%d)\n", | ||
1313 | dev->name, request_len); | ||
1314 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1315 | return -EINVAL; | ||
1316 | } | ||
1317 | |||
1318 | /* Prepare the call */ | ||
1319 | info.cmd = cmd; | ||
1320 | info.flags = 0; | ||
1321 | |||
1322 | /* Check if we have extra data in the request or not */ | ||
1323 | if(descr->header_type != IW_HEADER_TYPE_POINT) { | ||
1324 | |||
1325 | /* No extra arguments. Trivial to handle */ | ||
1326 | ret = handler(dev, &info, wrqu, NULL); | ||
1327 | |||
1328 | } else { | ||
1329 | int extra_len; | ||
1330 | |||
1331 | /* Put wrqu in the right place (skip pointer) */ | ||
1332 | memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, | ||
1333 | wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN); | ||
1334 | /* Don't forget about the event code... */ | ||
1335 | wrqu = &wrqu_point; | ||
1336 | |||
1337 | /* Check if number of token fits within bounds */ | ||
1338 | if(wrqu_point.data.length > descr->max_tokens) | ||
1339 | return -E2BIG; | ||
1340 | if(wrqu_point.data.length < descr->min_tokens) | ||
1341 | return -EINVAL; | ||
1342 | |||
1343 | /* Real length of payload */ | ||
1344 | extra_len = wrqu_point.data.length * descr->token_size; | ||
1345 | |||
1346 | /* Check if request is self consistent */ | ||
1347 | if((request_len - hdr_len) < extra_len) { | ||
1348 | #ifdef WE_RTNETLINK_DEBUG | ||
1349 | printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n", | ||
1350 | dev->name, extra_size); | ||
1351 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1352 | return -EINVAL; | ||
1353 | } | ||
1354 | |||
1355 | #ifdef WE_RTNETLINK_DEBUG | ||
1356 | printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n", | ||
1357 | dev->name, extra_size); | ||
1358 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1359 | |||
1360 | /* Always allocate for max space. Easier, and won't last | ||
1361 | * long... */ | ||
1362 | extra_size = descr->max_tokens * descr->token_size; | ||
1363 | extra = kmalloc(extra_size, GFP_KERNEL); | ||
1364 | if (extra == NULL) | ||
1365 | return -ENOMEM; | ||
1366 | |||
1367 | /* Copy extra in aligned buffer */ | ||
1368 | memcpy(extra, ((char *) request) + hdr_len, extra_len); | ||
1369 | |||
1370 | /* Call the handler */ | ||
1371 | ret = handler(dev, &info, &wrqu_point, extra); | ||
1372 | } | ||
1373 | |||
1374 | #ifdef WE_SET_EVENT | ||
1375 | /* Generate an event to notify listeners of the change */ | ||
1376 | if((descr->flags & IW_DESCR_FLAG_EVENT) && | ||
1377 | ((ret == 0) || (ret == -EIWCOMMIT))) { | ||
1378 | if(descr->flags & IW_DESCR_FLAG_RESTRICT) | ||
1379 | /* If the event is restricted, don't | ||
1380 | * export the payload */ | ||
1381 | wireless_send_event(dev, cmd, wrqu, NULL); | ||
1382 | else | ||
1383 | wireless_send_event(dev, cmd, wrqu, extra); | ||
1384 | } | ||
1385 | #endif /* WE_SET_EVENT */ | ||
1386 | |||
1387 | /* Cleanup - I told you it wasn't that long ;-) */ | ||
1388 | if(extra) | ||
1389 | kfree(extra); | ||
1390 | |||
1391 | /* Call commit handler if needed and defined */ | ||
1392 | if(ret == -EIWCOMMIT) | ||
1393 | ret = call_commit_handler(dev); | ||
1394 | |||
1395 | return ret; | ||
1396 | } | ||
1397 | |||
1398 | /* ---------------------------------------------------------------- */ | ||
1399 | /* | ||
1400 | * Wrapper to call a private Wireless Extension GET handler. | ||
1401 | * Same as above... | ||
1402 | * It's not as nice and slimline as the standard wrapper. The cause | ||
1403 | * is struct iw_priv_args, which was not really designed for the | ||
1404 | * job we are going here. | ||
1405 | * | ||
1406 | * IMPORTANT : This function prevent to set and get data on the same | ||
1407 | * IOCTL and enforce the SET/GET convention. Not doing it would be | ||
1408 | * far too hairy... | ||
1409 | * If you need to set and get data at the same time, please don't use | ||
1410 | * a iw_handler but process it in your ioctl handler (i.e. use the | ||
1411 | * old driver API). | ||
1412 | */ | ||
1413 | static inline int rtnetlink_private_get(struct net_device * dev, | ||
1414 | struct iw_event * request, | ||
1415 | int request_len, | ||
1416 | iw_handler handler, | ||
1417 | char ** p_buf, | ||
1418 | int * p_len) | ||
1419 | { | ||
1420 | const struct iw_priv_args * descr = NULL; | ||
1421 | unsigned int cmd; | ||
1422 | union iwreq_data * wrqu; | ||
1423 | int hdr_len; | ||
1424 | struct iw_request_info info; | ||
1425 | int extra_size = 0; | ||
1426 | int i; | ||
1427 | char * buffer = NULL; | ||
1428 | int buffer_size = 0; | ||
1429 | int ret = -EINVAL; | ||
1430 | |||
1431 | /* Get the description of the Request */ | ||
1432 | cmd = request->cmd; | ||
1433 | for(i = 0; i < dev->wireless_handlers->num_private_args; i++) | ||
1434 | if(cmd == dev->wireless_handlers->private_args[i].cmd) { | ||
1435 | descr = &(dev->wireless_handlers->private_args[i]); | ||
1436 | break; | ||
1437 | } | ||
1438 | if(descr == NULL) | ||
1439 | return -EOPNOTSUPP; | ||
1440 | |||
1441 | #ifdef WE_RTNETLINK_DEBUG | ||
1442 | printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n", | ||
1443 | dev->name, cmd); | ||
1444 | printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n", | ||
1445 | dev->name, descr->name, descr->set_args, descr->get_args); | ||
1446 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1447 | |||
1448 | /* Compute the max size of the get arguments */ | ||
1449 | extra_size = get_priv_size(descr->get_args); | ||
1450 | |||
1451 | /* Does it fits in wrqu ? */ | ||
1452 | if((descr->get_args & IW_PRIV_SIZE_FIXED) && | ||
1453 | (extra_size <= IFNAMSIZ)) { | ||
1454 | hdr_len = extra_size; | ||
1455 | extra_size = 0; | ||
1456 | } else { | ||
1457 | hdr_len = IW_EV_POINT_LEN; | ||
1458 | } | ||
1459 | |||
1460 | /* Check if wrqu is complete */ | ||
1461 | if(request_len < hdr_len) { | ||
1462 | #ifdef WE_RTNETLINK_DEBUG | ||
1463 | printk(KERN_DEBUG | ||
1464 | "%s (WE.r) : Wireless request too short (%d)\n", | ||
1465 | dev->name, request_len); | ||
1466 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1467 | return -EINVAL; | ||
1468 | } | ||
1469 | |||
1470 | /* Prepare the call */ | ||
1471 | info.cmd = cmd; | ||
1472 | info.flags = 0; | ||
1473 | |||
1474 | /* Check if we have a pointer to user space data or not. */ | ||
1475 | if(extra_size == 0) { | ||
1476 | |||
1477 | /* Create the kernel buffer that we will return. | ||
1478 | * It's at an offset to match the TYPE_POINT case... */ | ||
1479 | buffer_size = request_len + IW_EV_POINT_OFF; | ||
1480 | buffer = kmalloc(buffer_size, GFP_KERNEL); | ||
1481 | if (buffer == NULL) { | ||
1482 | return -ENOMEM; | ||
1483 | } | ||
1484 | /* Copy event data */ | ||
1485 | memcpy(buffer + IW_EV_POINT_OFF, request, request_len); | ||
1486 | /* Use our own copy of wrqu */ | ||
1487 | wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF | ||
1488 | + IW_EV_LCP_LEN); | ||
1489 | |||
1490 | /* No extra arguments. Trivial to handle */ | ||
1491 | ret = handler(dev, &info, wrqu, (char *) wrqu); | ||
1492 | |||
1493 | } else { | ||
1494 | char * extra; | ||
1495 | |||
1496 | /* Buffer for full reply */ | ||
1497 | buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF; | ||
1498 | |||
1499 | #ifdef WE_RTNETLINK_DEBUG | ||
1500 | printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n", | ||
1501 | dev->name, extra_size, buffer_size); | ||
1502 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1503 | |||
1504 | /* Create the kernel buffer that we will return */ | ||
1505 | buffer = kmalloc(buffer_size, GFP_KERNEL); | ||
1506 | if (buffer == NULL) { | ||
1507 | return -ENOMEM; | ||
1508 | } | ||
1509 | |||
1510 | /* Put wrqu in the right place (just before extra). | ||
1511 | * Leave space for IWE header and dummy pointer... | ||
1512 | * Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned... | ||
1513 | */ | ||
1514 | memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF, | ||
1515 | ((char *) request) + IW_EV_LCP_LEN, | ||
1516 | IW_EV_POINT_LEN - IW_EV_LCP_LEN); | ||
1517 | wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN); | ||
1518 | |||
1519 | /* Extra comes logically after that. Offset +12 bytes. */ | ||
1520 | extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN; | ||
1521 | |||
1522 | /* Call the handler */ | ||
1523 | ret = handler(dev, &info, wrqu, extra); | ||
1524 | |||
1525 | /* Adjust for the actual length if it's variable, | ||
1526 | * avoid leaking kernel bits outside. */ | ||
1527 | if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) | ||
1528 | extra_size = adjust_priv_size(descr->get_args, wrqu); | ||
1529 | /* Re-adjust reply size */ | ||
1530 | request->len = extra_size + IW_EV_POINT_LEN; | ||
1531 | |||
1532 | /* Put the iwe header where it should, i.e. scrap the | ||
1533 | * dummy pointer. */ | ||
1534 | memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN); | ||
1535 | |||
1536 | #ifdef WE_RTNETLINK_DEBUG | ||
1537 | printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size); | ||
1538 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1539 | } | ||
1540 | |||
1541 | /* Return the buffer to the caller */ | ||
1542 | if (!ret) { | ||
1543 | *p_buf = buffer; | ||
1544 | *p_len = request->len; | ||
1545 | } else { | ||
1546 | /* Cleanup */ | ||
1547 | if(buffer) | ||
1548 | kfree(buffer); | ||
1549 | } | ||
1550 | |||
1551 | return ret; | ||
1552 | } | ||
1553 | |||
1554 | /* ---------------------------------------------------------------- */ | ||
1555 | /* | ||
1556 | * Wrapper to call a private Wireless Extension SET handler. | ||
1557 | * Same as above... | ||
1558 | * It's not as nice and slimline as the standard wrapper. The cause | ||
1559 | * is struct iw_priv_args, which was not really designed for the | ||
1560 | * job we are going here. | ||
1561 | * | ||
1562 | * IMPORTANT : This function prevent to set and get data on the same | ||
1563 | * IOCTL and enforce the SET/GET convention. Not doing it would be | ||
1564 | * far too hairy... | ||
1565 | * If you need to set and get data at the same time, please don't use | ||
1566 | * a iw_handler but process it in your ioctl handler (i.e. use the | ||
1567 | * old driver API). | ||
1568 | */ | ||
1569 | static inline int rtnetlink_private_set(struct net_device * dev, | ||
1570 | struct iw_event * request, | ||
1571 | int request_len, | ||
1572 | iw_handler handler) | ||
1573 | { | ||
1574 | const struct iw_priv_args * descr = NULL; | ||
1575 | unsigned int cmd; | ||
1576 | union iwreq_data * wrqu; | ||
1577 | union iwreq_data wrqu_point; | ||
1578 | int hdr_len; | ||
1579 | char * extra = NULL; | ||
1580 | int extra_size = 0; | ||
1581 | int offset = 0; /* For sub-ioctls */ | ||
1582 | struct iw_request_info info; | ||
1583 | int i; | ||
1584 | int ret = -EINVAL; | ||
1585 | |||
1586 | /* Get the description of the Request */ | ||
1587 | cmd = request->cmd; | ||
1588 | for(i = 0; i < dev->wireless_handlers->num_private_args; i++) | ||
1589 | if(cmd == dev->wireless_handlers->private_args[i].cmd) { | ||
1590 | descr = &(dev->wireless_handlers->private_args[i]); | ||
1591 | break; | ||
1592 | } | ||
1593 | if(descr == NULL) | ||
1594 | return -EOPNOTSUPP; | ||
1595 | |||
1596 | #ifdef WE_RTNETLINK_DEBUG | ||
1597 | printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n", | ||
1598 | ifr->ifr_name, cmd); | ||
1599 | printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n", | ||
1600 | dev->name, descr->name, descr->set_args, descr->get_args); | ||
1601 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1602 | |||
1603 | /* Compute the size of the set arguments */ | ||
1604 | /* Check for sub-ioctl handler */ | ||
1605 | if(descr->name[0] == '\0') | ||
1606 | /* Reserve one int for sub-ioctl index */ | ||
1607 | offset = sizeof(__u32); | ||
1608 | |||
1609 | /* Size of set arguments */ | ||
1610 | extra_size = get_priv_size(descr->set_args); | ||
1611 | |||
1612 | /* Does it fits in wrqu ? */ | ||
1613 | if((descr->set_args & IW_PRIV_SIZE_FIXED) && | ||
1614 | (extra_size <= IFNAMSIZ)) { | ||
1615 | hdr_len = IW_EV_LCP_LEN + extra_size; | ||
1616 | extra_size = 0; | ||
1617 | } else { | ||
1618 | hdr_len = IW_EV_POINT_LEN; | ||
1619 | } | ||
1620 | |||
1621 | /* Extract fixed header from request. This is properly aligned. */ | ||
1622 | wrqu = &request->u; | ||
1623 | |||
1624 | /* Check if wrqu is complete */ | ||
1625 | if(request_len < hdr_len) { | ||
1626 | #ifdef WE_RTNETLINK_DEBUG | ||
1627 | printk(KERN_DEBUG | ||
1628 | "%s (WE.r) : Wireless request too short (%d)\n", | ||
1629 | dev->name, request_len); | ||
1630 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1631 | return -EINVAL; | ||
1632 | } | ||
1633 | |||
1634 | /* Prepare the call */ | ||
1635 | info.cmd = cmd; | ||
1636 | info.flags = 0; | ||
1637 | |||
1638 | /* Check if we have a pointer to user space data or not. */ | ||
1639 | if(extra_size == 0) { | ||
1640 | |||
1641 | /* No extra arguments. Trivial to handle */ | ||
1642 | ret = handler(dev, &info, wrqu, (char *) wrqu); | ||
1643 | |||
1644 | } else { | ||
1645 | int extra_len; | ||
1646 | |||
1647 | /* Put wrqu in the right place (skip pointer) */ | ||
1648 | memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, | ||
1649 | wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN); | ||
1650 | |||
1651 | /* Does it fits within bounds ? */ | ||
1652 | if(wrqu_point.data.length > (descr->set_args & | ||
1653 | IW_PRIV_SIZE_MASK)) | ||
1654 | return -E2BIG; | ||
1655 | |||
1656 | /* Real length of payload */ | ||
1657 | extra_len = adjust_priv_size(descr->set_args, &wrqu_point); | ||
1658 | |||
1659 | /* Check if request is self consistent */ | ||
1660 | if((request_len - hdr_len) < extra_len) { | ||
1661 | #ifdef WE_RTNETLINK_DEBUG | ||
1662 | printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n", | ||
1663 | dev->name, extra_size); | ||
1664 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1665 | return -EINVAL; | ||
1666 | } | ||
1667 | |||
1668 | #ifdef WE_RTNETLINK_DEBUG | ||
1669 | printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n", | ||
1670 | dev->name, extra_size); | ||
1671 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1672 | |||
1673 | /* Always allocate for max space. Easier, and won't last | ||
1674 | * long... */ | ||
1675 | extra = kmalloc(extra_size, GFP_KERNEL); | ||
1676 | if (extra == NULL) | ||
1677 | return -ENOMEM; | ||
1678 | |||
1679 | /* Copy extra in aligned buffer */ | ||
1680 | memcpy(extra, ((char *) request) + hdr_len, extra_len); | ||
1681 | |||
1682 | /* Call the handler */ | ||
1683 | ret = handler(dev, &info, &wrqu_point, extra); | ||
1684 | |||
1685 | /* Cleanup - I told you it wasn't that long ;-) */ | ||
1686 | kfree(extra); | ||
1687 | } | ||
1688 | |||
1689 | /* Call commit handler if needed and defined */ | ||
1690 | if(ret == -EIWCOMMIT) | ||
1691 | ret = call_commit_handler(dev); | ||
1692 | |||
1693 | return ret; | ||
1694 | } | ||
1695 | |||
1696 | /* ---------------------------------------------------------------- */ | ||
1697 | /* | ||
1698 | * Main RtNetlink dispatcher. Called from the main networking code | ||
1699 | * (do_getlink() in net/core/rtnetlink.c). | ||
1700 | * Check the type of Request and call the appropriate wrapper... | ||
1701 | */ | ||
1702 | int wireless_rtnetlink_get(struct net_device * dev, | ||
1703 | char * data, | ||
1704 | int len, | ||
1705 | char ** p_buf, | ||
1706 | int * p_len) | ||
1707 | { | ||
1708 | struct iw_event * request = (struct iw_event *) data; | ||
1709 | iw_handler handler; | ||
1710 | |||
1711 | /* Check length */ | ||
1712 | if(len < IW_EV_LCP_LEN) { | ||
1713 | printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n", | ||
1714 | dev->name, len); | ||
1715 | return -EINVAL; | ||
1716 | } | ||
1717 | |||
1718 | /* ReCheck length (len may have padding) */ | ||
1719 | if(request->len > len) { | ||
1720 | printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n", | ||
1721 | dev->name, request->len, len); | ||
1722 | return -EINVAL; | ||
1723 | } | ||
1724 | |||
1725 | /* Only accept GET requests in here */ | ||
1726 | if(!IW_IS_GET(request->cmd)) | ||
1727 | return -EOPNOTSUPP; | ||
1728 | |||
1729 | /* Special cases */ | ||
1730 | if(request->cmd == SIOCGIWSTATS) | ||
1731 | /* Get Wireless Stats */ | ||
1732 | return rtnetlink_standard_get(dev, | ||
1733 | request, | ||
1734 | request->len, | ||
1735 | &iw_handler_get_iwstats, | ||
1736 | p_buf, p_len); | ||
1737 | if(request->cmd == SIOCGIWPRIV) { | ||
1738 | /* Check if we have some wireless handlers defined */ | ||
1739 | if(dev->wireless_handlers == NULL) | ||
1740 | return -EOPNOTSUPP; | ||
1741 | /* Get Wireless Stats */ | ||
1742 | return rtnetlink_standard_get(dev, | ||
1743 | request, | ||
1744 | request->len, | ||
1745 | &iw_handler_get_private, | ||
1746 | p_buf, p_len); | ||
1747 | } | ||
1748 | |||
1749 | /* Basic check */ | ||
1750 | if (!netif_device_present(dev)) | ||
1751 | return -ENODEV; | ||
1752 | |||
1753 | /* Try to find the handler */ | ||
1754 | handler = get_handler(dev, request->cmd); | ||
1755 | if(handler != NULL) { | ||
1756 | /* Standard and private are not the same */ | ||
1757 | if(request->cmd < SIOCIWFIRSTPRIV) | ||
1758 | return rtnetlink_standard_get(dev, | ||
1759 | request, | ||
1760 | request->len, | ||
1761 | handler, | ||
1762 | p_buf, p_len); | ||
1763 | else | ||
1764 | return rtnetlink_private_get(dev, | ||
1765 | request, | ||
1766 | request->len, | ||
1767 | handler, | ||
1768 | p_buf, p_len); | ||
1769 | } | ||
1770 | |||
1771 | return -EOPNOTSUPP; | ||
1772 | } | ||
1773 | |||
1774 | /* ---------------------------------------------------------------- */ | ||
1775 | /* | ||
1776 | * Main RtNetlink dispatcher. Called from the main networking code | ||
1777 | * (do_setlink() in net/core/rtnetlink.c). | ||
1778 | * Check the type of Request and call the appropriate wrapper... | ||
1779 | */ | ||
1780 | int wireless_rtnetlink_set(struct net_device * dev, | ||
1781 | char * data, | ||
1782 | int len) | ||
1783 | { | ||
1784 | struct iw_event * request = (struct iw_event *) data; | ||
1785 | iw_handler handler; | ||
1786 | |||
1787 | /* Check length */ | ||
1788 | if(len < IW_EV_LCP_LEN) { | ||
1789 | printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n", | ||
1790 | dev->name, len); | ||
1791 | return -EINVAL; | ||
1792 | } | ||
1793 | |||
1794 | /* ReCheck length (len may have padding) */ | ||
1795 | if(request->len > len) { | ||
1796 | printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n", | ||
1797 | dev->name, request->len, len); | ||
1798 | return -EINVAL; | ||
1799 | } | ||
1800 | |||
1801 | /* Only accept SET requests in here */ | ||
1802 | if(!IW_IS_SET(request->cmd)) | ||
1803 | return -EOPNOTSUPP; | ||
1804 | |||
1805 | /* Basic check */ | ||
1806 | if (!netif_device_present(dev)) | ||
1807 | return -ENODEV; | ||
1808 | |||
1809 | /* New driver API : try to find the handler */ | ||
1810 | handler = get_handler(dev, request->cmd); | ||
1811 | if(handler != NULL) { | ||
1812 | /* Standard and private are not the same */ | ||
1813 | if(request->cmd < SIOCIWFIRSTPRIV) | ||
1814 | return rtnetlink_standard_set(dev, | ||
1815 | request, | ||
1816 | request->len, | ||
1817 | handler); | ||
1818 | else | ||
1819 | return rtnetlink_private_set(dev, | ||
1820 | request, | ||
1821 | request->len, | ||
1822 | handler); | ||
1823 | } | ||
1824 | |||
1825 | return -EOPNOTSUPP; | ||
1826 | } | ||
1827 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | ||
1828 | |||
1829 | |||
1091 | /************************* EVENT PROCESSING *************************/ | 1830 | /************************* EVENT PROCESSING *************************/ |
1092 | /* | 1831 | /* |
1093 | * Process events generated by the wireless layer or the driver. | 1832 | * Process events generated by the wireless layer or the driver. |
1094 | * Most often, the event will be propagated through rtnetlink | 1833 | * Most often, the event will be propagated through rtnetlink |
1095 | */ | 1834 | */ |
1096 | 1835 | ||
1097 | #ifdef WE_EVENT_NETLINK | 1836 | #ifdef WE_EVENT_RTNETLINK |
1098 | /* "rtnl" is defined in net/core/rtnetlink.c, but we need it here. | ||
1099 | * It is declared in <linux/rtnetlink.h> */ | ||
1100 | |||
1101 | /* ---------------------------------------------------------------- */ | 1837 | /* ---------------------------------------------------------------- */ |
1102 | /* | 1838 | /* |
1103 | * Fill a rtnetlink message with our event data. | 1839 | * Fill a rtnetlink message with our event data. |
@@ -1121,12 +1857,11 @@ static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb, | |||
1121 | r->__ifi_pad = 0; | 1857 | r->__ifi_pad = 0; |
1122 | r->ifi_type = dev->type; | 1858 | r->ifi_type = dev->type; |
1123 | r->ifi_index = dev->ifindex; | 1859 | r->ifi_index = dev->ifindex; |
1124 | r->ifi_flags = dev->flags; | 1860 | r->ifi_flags = dev_get_flags(dev); |
1125 | r->ifi_change = 0; /* Wireless changes don't affect those flags */ | 1861 | r->ifi_change = 0; /* Wireless changes don't affect those flags */ |
1126 | 1862 | ||
1127 | /* Add the wireless events in the netlink packet */ | 1863 | /* Add the wireless events in the netlink packet */ |
1128 | RTA_PUT(skb, IFLA_WIRELESS, | 1864 | RTA_PUT(skb, IFLA_WIRELESS, event_len, event); |
1129 | event_len, event); | ||
1130 | 1865 | ||
1131 | nlh->nlmsg_len = skb->tail - b; | 1866 | nlh->nlmsg_len = skb->tail - b; |
1132 | return skb->len; | 1867 | return skb->len; |
@@ -1163,7 +1898,7 @@ static inline void rtmsg_iwinfo(struct net_device * dev, | |||
1163 | NETLINK_CB(skb).dst_group = RTNLGRP_LINK; | 1898 | NETLINK_CB(skb).dst_group = RTNLGRP_LINK; |
1164 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_ATOMIC); | 1899 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_ATOMIC); |
1165 | } | 1900 | } |
1166 | #endif /* WE_EVENT_NETLINK */ | 1901 | #endif /* WE_EVENT_RTNETLINK */ |
1167 | 1902 | ||
1168 | /* ---------------------------------------------------------------- */ | 1903 | /* ---------------------------------------------------------------- */ |
1169 | /* | 1904 | /* |
@@ -1255,10 +1990,10 @@ void wireless_send_event(struct net_device * dev, | |||
1255 | if(extra != NULL) | 1990 | if(extra != NULL) |
1256 | memcpy(((char *) event) + hdr_len, extra, extra_len); | 1991 | memcpy(((char *) event) + hdr_len, extra, extra_len); |
1257 | 1992 | ||
1258 | #ifdef WE_EVENT_NETLINK | 1993 | #ifdef WE_EVENT_RTNETLINK |
1259 | /* rtnetlink event channel */ | 1994 | /* Send via the RtNetlink event channel */ |
1260 | rtmsg_iwinfo(dev, (char *) event, event_len); | 1995 | rtmsg_iwinfo(dev, (char *) event, event_len); |
1261 | #endif /* WE_EVENT_NETLINK */ | 1996 | #endif /* WE_EVENT_RTNETLINK */ |
1262 | 1997 | ||
1263 | /* Cleanup */ | 1998 | /* Cleanup */ |
1264 | kfree(event); | 1999 | kfree(event); |
diff --git a/net/dccp/Kconfig b/net/dccp/Kconfig index 187ac182e24b..7e096ba8454f 100644 --- a/net/dccp/Kconfig +++ b/net/dccp/Kconfig | |||
@@ -24,6 +24,10 @@ config INET_DCCP_DIAG | |||
24 | def_tristate y if (IP_DCCP = y && INET_DIAG = y) | 24 | def_tristate y if (IP_DCCP = y && INET_DIAG = y) |
25 | def_tristate m | 25 | def_tristate m |
26 | 26 | ||
27 | config IP_DCCP_ACKVEC | ||
28 | depends on IP_DCCP | ||
29 | def_bool N | ||
30 | |||
27 | source "net/dccp/ccids/Kconfig" | 31 | source "net/dccp/ccids/Kconfig" |
28 | 32 | ||
29 | menu "DCCP Kernel Hacking" | 33 | menu "DCCP Kernel Hacking" |
@@ -36,15 +40,6 @@ config IP_DCCP_DEBUG | |||
36 | 40 | ||
37 | Just say N. | 41 | Just say N. |
38 | 42 | ||
39 | config IP_DCCP_UNLOAD_HACK | ||
40 | depends on IP_DCCP=m && IP_DCCP_CCID3=m | ||
41 | bool "DCCP control sock unload hack" | ||
42 | ---help--- | ||
43 | Enable this to be able to unload the dccp module when the it | ||
44 | has only one refcount held, the control sock one. Just execute | ||
45 | "rmmod dccp_ccid3 dccp" | ||
46 | |||
47 | Just say N. | ||
48 | endmenu | 43 | endmenu |
49 | 44 | ||
50 | endmenu | 45 | endmenu |
diff --git a/net/dccp/Makefile b/net/dccp/Makefile index 87b27fff6e3b..7696e219b05d 100644 --- a/net/dccp/Makefile +++ b/net/dccp/Makefile | |||
@@ -2,15 +2,18 @@ obj-$(CONFIG_IPV6) += dccp_ipv6.o | |||
2 | 2 | ||
3 | dccp_ipv6-y := ipv6.o | 3 | dccp_ipv6-y := ipv6.o |
4 | 4 | ||
5 | obj-$(CONFIG_IP_DCCP) += dccp.o | 5 | obj-$(CONFIG_IP_DCCP) += dccp.o dccp_ipv4.o |
6 | 6 | ||
7 | dccp-y := ccid.o input.o ipv4.o minisocks.o options.o output.o proto.o \ | 7 | dccp-y := ccid.o feat.o input.o minisocks.o options.o output.o proto.o timer.o |
8 | timer.o | 8 | |
9 | dccp_ipv4-y := ipv4.o | ||
9 | 10 | ||
10 | dccp-$(CONFIG_IP_DCCP_ACKVEC) += ackvec.o | 11 | dccp-$(CONFIG_IP_DCCP_ACKVEC) += ackvec.o |
11 | 12 | ||
12 | obj-$(CONFIG_INET_DCCP_DIAG) += dccp_diag.o | 13 | obj-$(CONFIG_INET_DCCP_DIAG) += dccp_diag.o |
13 | 14 | ||
15 | dccp-$(CONFIG_SYSCTL) += sysctl.o | ||
16 | |||
14 | dccp_diag-y := diag.o | 17 | dccp_diag-y := diag.o |
15 | 18 | ||
16 | obj-y += ccids/ | 19 | obj-y += ccids/ |
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index 2c77dafbd091..b5981e5f6b00 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c | |||
@@ -13,36 +13,83 @@ | |||
13 | #include "dccp.h" | 13 | #include "dccp.h" |
14 | 14 | ||
15 | #include <linux/dccp.h> | 15 | #include <linux/dccp.h> |
16 | #include <linux/init.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/kernel.h> | ||
16 | #include <linux/skbuff.h> | 19 | #include <linux/skbuff.h> |
20 | #include <linux/slab.h> | ||
17 | 21 | ||
18 | #include <net/sock.h> | 22 | #include <net/sock.h> |
19 | 23 | ||
24 | static kmem_cache_t *dccp_ackvec_slab; | ||
25 | static kmem_cache_t *dccp_ackvec_record_slab; | ||
26 | |||
27 | static struct dccp_ackvec_record *dccp_ackvec_record_new(void) | ||
28 | { | ||
29 | struct dccp_ackvec_record *avr = | ||
30 | kmem_cache_alloc(dccp_ackvec_record_slab, GFP_ATOMIC); | ||
31 | |||
32 | if (avr != NULL) | ||
33 | INIT_LIST_HEAD(&avr->dccpavr_node); | ||
34 | |||
35 | return avr; | ||
36 | } | ||
37 | |||
38 | static void dccp_ackvec_record_delete(struct dccp_ackvec_record *avr) | ||
39 | { | ||
40 | if (unlikely(avr == NULL)) | ||
41 | return; | ||
42 | /* Check if deleting a linked record */ | ||
43 | WARN_ON(!list_empty(&avr->dccpavr_node)); | ||
44 | kmem_cache_free(dccp_ackvec_record_slab, avr); | ||
45 | } | ||
46 | |||
47 | static void dccp_ackvec_insert_avr(struct dccp_ackvec *av, | ||
48 | struct dccp_ackvec_record *avr) | ||
49 | { | ||
50 | /* | ||
51 | * AVRs are sorted by seqno. Since we are sending them in order, we | ||
52 | * just add the AVR at the head of the list. | ||
53 | * -sorbo. | ||
54 | */ | ||
55 | if (!list_empty(&av->dccpav_records)) { | ||
56 | const struct dccp_ackvec_record *head = | ||
57 | list_entry(av->dccpav_records.next, | ||
58 | struct dccp_ackvec_record, | ||
59 | dccpavr_node); | ||
60 | BUG_ON(before48(avr->dccpavr_ack_seqno, | ||
61 | head->dccpavr_ack_seqno)); | ||
62 | } | ||
63 | |||
64 | list_add(&avr->dccpavr_node, &av->dccpav_records); | ||
65 | } | ||
66 | |||
20 | int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | 67 | int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) |
21 | { | 68 | { |
22 | struct dccp_sock *dp = dccp_sk(sk); | 69 | struct dccp_sock *dp = dccp_sk(sk); |
70 | #ifdef CONFIG_IP_DCCP_DEBUG | ||
71 | const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? | ||
72 | "CLIENT tx: " : "server tx: "; | ||
73 | #endif | ||
23 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; | 74 | struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; |
24 | int len = av->dccpav_vec_len + 2; | 75 | int len = av->dccpav_vec_len + 2; |
25 | struct timeval now; | 76 | struct timeval now; |
26 | u32 elapsed_time; | 77 | u32 elapsed_time; |
27 | unsigned char *to, *from; | 78 | unsigned char *to, *from; |
79 | struct dccp_ackvec_record *avr; | ||
80 | |||
81 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) | ||
82 | return -1; | ||
28 | 83 | ||
29 | dccp_timestamp(sk, &now); | 84 | dccp_timestamp(sk, &now); |
30 | elapsed_time = timeval_delta(&now, &av->dccpav_time) / 10; | 85 | elapsed_time = timeval_delta(&now, &av->dccpav_time) / 10; |
31 | 86 | ||
32 | if (elapsed_time != 0) | 87 | if (elapsed_time != 0 && |
33 | dccp_insert_option_elapsed_time(sk, skb, elapsed_time); | 88 | dccp_insert_option_elapsed_time(sk, skb, elapsed_time)) |
34 | |||
35 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) | ||
36 | return -1; | 89 | return -1; |
37 | 90 | ||
38 | /* | 91 | avr = dccp_ackvec_record_new(); |
39 | * XXX: now we have just one ack vector sent record, so | 92 | if (avr == NULL) |
40 | * we have to wait for it to be cleared. | ||
41 | * | ||
42 | * Of course this is not acceptable, but this is just for | ||
43 | * basic testing now. | ||
44 | */ | ||
45 | if (av->dccpav_ack_seqno != DCCP_MAX_SEQNO + 1) | ||
46 | return -1; | 93 | return -1; |
47 | 94 | ||
48 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | 95 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; |
@@ -55,8 +102,8 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | |||
55 | from = av->dccpav_buf + av->dccpav_buf_head; | 102 | from = av->dccpav_buf + av->dccpav_buf_head; |
56 | 103 | ||
57 | /* Check if buf_head wraps */ | 104 | /* Check if buf_head wraps */ |
58 | if ((int)av->dccpav_buf_head + len > av->dccpav_vec_len) { | 105 | if ((int)av->dccpav_buf_head + len > DCCP_MAX_ACKVEC_LEN) { |
59 | const u32 tailsize = av->dccpav_vec_len - av->dccpav_buf_head; | 106 | const u32 tailsize = DCCP_MAX_ACKVEC_LEN - av->dccpav_buf_head; |
60 | 107 | ||
61 | memcpy(to, from, tailsize); | 108 | memcpy(to, from, tailsize); |
62 | to += tailsize; | 109 | to += tailsize; |
@@ -73,45 +120,37 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) | |||
73 | * sequence number it used for the ack packet; ack_ptr will equal | 120 | * sequence number it used for the ack packet; ack_ptr will equal |
74 | * buf_head; ack_ackno will equal buf_ackno; and ack_nonce will | 121 | * buf_head; ack_ackno will equal buf_ackno; and ack_nonce will |
75 | * equal buf_nonce. | 122 | * equal buf_nonce. |
76 | * | ||
77 | * This implemention uses just one ack record for now. | ||
78 | */ | 123 | */ |
79 | av->dccpav_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq; | 124 | avr->dccpavr_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq; |
80 | av->dccpav_ack_ptr = av->dccpav_buf_head; | 125 | avr->dccpavr_ack_ptr = av->dccpav_buf_head; |
81 | av->dccpav_ack_ackno = av->dccpav_buf_ackno; | 126 | avr->dccpavr_ack_ackno = av->dccpav_buf_ackno; |
82 | av->dccpav_ack_nonce = av->dccpav_buf_nonce; | 127 | avr->dccpavr_ack_nonce = av->dccpav_buf_nonce; |
83 | av->dccpav_sent_len = av->dccpav_vec_len; | 128 | avr->dccpavr_sent_len = av->dccpav_vec_len; |
129 | |||
130 | dccp_ackvec_insert_avr(av, avr); | ||
84 | 131 | ||
85 | dccp_pr_debug("%sACK Vector 0, len=%d, ack_seqno=%llu, " | 132 | dccp_pr_debug("%sACK Vector 0, len=%d, ack_seqno=%llu, " |
86 | "ack_ackno=%llu\n", | 133 | "ack_ackno=%llu\n", |
87 | debug_prefix, av->dccpav_sent_len, | 134 | debug_prefix, avr->dccpavr_sent_len, |
88 | (unsigned long long)av->dccpav_ack_seqno, | 135 | (unsigned long long)avr->dccpavr_ack_seqno, |
89 | (unsigned long long)av->dccpav_ack_ackno); | 136 | (unsigned long long)avr->dccpavr_ack_ackno); |
90 | return -1; | 137 | return 0; |
91 | } | 138 | } |
92 | 139 | ||
93 | struct dccp_ackvec *dccp_ackvec_alloc(const unsigned int len, | 140 | struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority) |
94 | const gfp_t priority) | ||
95 | { | 141 | { |
96 | struct dccp_ackvec *av; | 142 | struct dccp_ackvec *av = kmem_cache_alloc(dccp_ackvec_slab, priority); |
97 | |||
98 | BUG_ON(len == 0); | ||
99 | 143 | ||
100 | if (len > DCCP_MAX_ACKVEC_LEN) | ||
101 | return NULL; | ||
102 | |||
103 | av = kmalloc(sizeof(*av) + len, priority); | ||
104 | if (av != NULL) { | 144 | if (av != NULL) { |
105 | av->dccpav_buf_len = len; | ||
106 | av->dccpav_buf_head = | 145 | av->dccpav_buf_head = |
107 | av->dccpav_buf_tail = av->dccpav_buf_len - 1; | 146 | av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1; |
108 | av->dccpav_buf_ackno = | 147 | av->dccpav_buf_ackno = DCCP_MAX_SEQNO + 1; |
109 | av->dccpav_ack_ackno = av->dccpav_ack_seqno = ~0LLU; | ||
110 | av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0; | 148 | av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0; |
111 | av->dccpav_ack_ptr = 0; | 149 | av->dccpav_ack_ptr = 0; |
112 | av->dccpav_time.tv_sec = 0; | 150 | av->dccpav_time.tv_sec = 0; |
113 | av->dccpav_time.tv_usec = 0; | 151 | av->dccpav_time.tv_usec = 0; |
114 | av->dccpav_sent_len = av->dccpav_vec_len = 0; | 152 | av->dccpav_sent_len = av->dccpav_vec_len = 0; |
153 | INIT_LIST_HEAD(&av->dccpav_records); | ||
115 | } | 154 | } |
116 | 155 | ||
117 | return av; | 156 | return av; |
@@ -119,7 +158,20 @@ struct dccp_ackvec *dccp_ackvec_alloc(const unsigned int len, | |||
119 | 158 | ||
120 | void dccp_ackvec_free(struct dccp_ackvec *av) | 159 | void dccp_ackvec_free(struct dccp_ackvec *av) |
121 | { | 160 | { |
122 | kfree(av); | 161 | if (unlikely(av == NULL)) |
162 | return; | ||
163 | |||
164 | if (!list_empty(&av->dccpav_records)) { | ||
165 | struct dccp_ackvec_record *avr, *next; | ||
166 | |||
167 | list_for_each_entry_safe(avr, next, &av->dccpav_records, | ||
168 | dccpavr_node) { | ||
169 | list_del_init(&avr->dccpavr_node); | ||
170 | dccp_ackvec_record_delete(avr); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | kmem_cache_free(dccp_ackvec_slab, av); | ||
123 | } | 175 | } |
124 | 176 | ||
125 | static inline u8 dccp_ackvec_state(const struct dccp_ackvec *av, | 177 | static inline u8 dccp_ackvec_state(const struct dccp_ackvec *av, |
@@ -146,7 +198,7 @@ static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av, | |||
146 | unsigned int gap; | 198 | unsigned int gap; |
147 | long new_head; | 199 | long new_head; |
148 | 200 | ||
149 | if (av->dccpav_vec_len + packets > av->dccpav_buf_len) | 201 | if (av->dccpav_vec_len + packets > DCCP_MAX_ACKVEC_LEN) |
150 | return -ENOBUFS; | 202 | return -ENOBUFS; |
151 | 203 | ||
152 | gap = packets - 1; | 204 | gap = packets - 1; |
@@ -158,7 +210,7 @@ static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av, | |||
158 | gap + new_head + 1); | 210 | gap + new_head + 1); |
159 | gap = -new_head; | 211 | gap = -new_head; |
160 | } | 212 | } |
161 | new_head += av->dccpav_buf_len; | 213 | new_head += DCCP_MAX_ACKVEC_LEN; |
162 | } | 214 | } |
163 | 215 | ||
164 | av->dccpav_buf_head = new_head; | 216 | av->dccpav_buf_head = new_head; |
@@ -251,7 +303,7 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, | |||
251 | goto out_duplicate; | 303 | goto out_duplicate; |
252 | 304 | ||
253 | delta -= len + 1; | 305 | delta -= len + 1; |
254 | if (++index == av->dccpav_buf_len) | 306 | if (++index == DCCP_MAX_ACKVEC_LEN) |
255 | index = 0; | 307 | index = 0; |
256 | } | 308 | } |
257 | } | 309 | } |
@@ -259,7 +311,6 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, | |||
259 | av->dccpav_buf_ackno = ackno; | 311 | av->dccpav_buf_ackno = ackno; |
260 | dccp_timestamp(sk, &av->dccpav_time); | 312 | dccp_timestamp(sk, &av->dccpav_time); |
261 | out: | 313 | out: |
262 | dccp_pr_debug(""); | ||
263 | return 0; | 314 | return 0; |
264 | 315 | ||
265 | out_duplicate: | 316 | out_duplicate: |
@@ -297,44 +348,50 @@ void dccp_ackvec_print(const struct dccp_ackvec *av) | |||
297 | } | 348 | } |
298 | #endif | 349 | #endif |
299 | 350 | ||
300 | static void dccp_ackvec_throw_away_ack_record(struct dccp_ackvec *av) | 351 | static void dccp_ackvec_throw_record(struct dccp_ackvec *av, |
352 | struct dccp_ackvec_record *avr) | ||
301 | { | 353 | { |
302 | /* | 354 | struct dccp_ackvec_record *next; |
303 | * As we're keeping track of the ack vector size (dccpav_vec_len) and | 355 | |
304 | * the sent ack vector size (dccpav_sent_len) we don't need | 356 | av->dccpav_buf_tail = avr->dccpavr_ack_ptr - 1; |
305 | * dccpav_buf_tail at all, but keep this code here as in the future | 357 | if (av->dccpav_buf_tail == 0) |
306 | * we'll implement a vector of ack records, as suggested in | 358 | av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1; |
307 | * draft-ietf-dccp-spec-11.txt Appendix A. -acme | 359 | |
308 | */ | 360 | av->dccpav_vec_len -= avr->dccpavr_sent_len; |
309 | #if 0 | 361 | |
310 | u32 new_buf_tail = av->dccpav_ack_ptr + 1; | 362 | /* free records */ |
311 | if (new_buf_tail >= av->dccpav_vec_len) | 363 | list_for_each_entry_safe_from(avr, next, &av->dccpav_records, |
312 | new_buf_tail -= av->dccpav_vec_len; | 364 | dccpavr_node) { |
313 | av->dccpav_buf_tail = new_buf_tail; | 365 | list_del_init(&avr->dccpavr_node); |
314 | #endif | 366 | dccp_ackvec_record_delete(avr); |
315 | av->dccpav_vec_len -= av->dccpav_sent_len; | 367 | } |
316 | } | 368 | } |
317 | 369 | ||
318 | void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, struct sock *sk, | 370 | void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, struct sock *sk, |
319 | const u64 ackno) | 371 | const u64 ackno) |
320 | { | 372 | { |
321 | /* Check if we actually sent an ACK vector */ | 373 | struct dccp_ackvec_record *avr; |
322 | if (av->dccpav_ack_seqno == DCCP_MAX_SEQNO + 1) | ||
323 | return; | ||
324 | 374 | ||
325 | if (ackno == av->dccpav_ack_seqno) { | 375 | /* |
376 | * If we traverse backwards, it should be faster when we have large | ||
377 | * windows. We will be receiving ACKs for stuff we sent a while back | ||
378 | * -sorbo. | ||
379 | */ | ||
380 | list_for_each_entry_reverse(avr, &av->dccpav_records, dccpavr_node) { | ||
381 | if (ackno == avr->dccpavr_ack_seqno) { | ||
326 | #ifdef CONFIG_IP_DCCP_DEBUG | 382 | #ifdef CONFIG_IP_DCCP_DEBUG |
327 | struct dccp_sock *dp = dccp_sk(sk); | 383 | struct dccp_sock *dp = dccp_sk(sk); |
328 | const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? | 384 | const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? |
329 | "CLIENT rx ack: " : "server rx ack: "; | 385 | "CLIENT rx ack: " : "server rx ack: "; |
330 | #endif | 386 | #endif |
331 | dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, " | 387 | dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, " |
332 | "ack_ackno=%llu, ACKED!\n", | 388 | "ack_ackno=%llu, ACKED!\n", |
333 | debug_prefix, 1, | 389 | debug_prefix, 1, |
334 | (unsigned long long)av->dccpav_ack_seqno, | 390 | (unsigned long long)avr->dccpavr_ack_seqno, |
335 | (unsigned long long)av->dccpav_ack_ackno); | 391 | (unsigned long long)avr->dccpavr_ack_ackno); |
336 | dccp_ackvec_throw_away_ack_record(av); | 392 | dccp_ackvec_throw_record(av, avr); |
337 | av->dccpav_ack_seqno = DCCP_MAX_SEQNO + 1; | 393 | break; |
394 | } | ||
338 | } | 395 | } |
339 | } | 396 | } |
340 | 397 | ||
@@ -344,28 +401,20 @@ static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av, | |||
344 | const unsigned char *vector) | 401 | const unsigned char *vector) |
345 | { | 402 | { |
346 | unsigned char i; | 403 | unsigned char i; |
404 | struct dccp_ackvec_record *avr; | ||
347 | 405 | ||
348 | /* Check if we actually sent an ACK vector */ | 406 | /* Check if we actually sent an ACK vector */ |
349 | if (av->dccpav_ack_seqno == DCCP_MAX_SEQNO + 1) | 407 | if (list_empty(&av->dccpav_records)) |
350 | return; | ||
351 | /* | ||
352 | * We're in the receiver half connection, so if the received an ACK | ||
353 | * vector ackno (e.g. 50) before dccpav_ack_seqno (e.g. 52), we're | ||
354 | * not interested. | ||
355 | * | ||
356 | * Extra explanation with example: | ||
357 | * | ||
358 | * if we received an ACK vector with ackno 50, it can only be acking | ||
359 | * 50, 49, 48, etc, not 52 (the seqno for the ACK vector we sent). | ||
360 | */ | ||
361 | /* dccp_pr_debug("is %llu < %llu? ", ackno, av->dccpav_ack_seqno); */ | ||
362 | if (before48(ackno, av->dccpav_ack_seqno)) { | ||
363 | /* dccp_pr_debug_cat("yes\n"); */ | ||
364 | return; | 408 | return; |
365 | } | ||
366 | /* dccp_pr_debug_cat("no\n"); */ | ||
367 | 409 | ||
368 | i = len; | 410 | i = len; |
411 | /* | ||
412 | * XXX | ||
413 | * I think it might be more efficient to work backwards. See comment on | ||
414 | * rcv_ackno. -sorbo. | ||
415 | */ | ||
416 | avr = list_entry(av->dccpav_records.next, struct dccp_ackvec_record, | ||
417 | dccpavr_node); | ||
369 | while (i--) { | 418 | while (i--) { |
370 | const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK; | 419 | const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK; |
371 | u64 ackno_end_rl; | 420 | u64 ackno_end_rl; |
@@ -373,14 +422,20 @@ static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av, | |||
373 | dccp_set_seqno(&ackno_end_rl, ackno - rl); | 422 | dccp_set_seqno(&ackno_end_rl, ackno - rl); |
374 | 423 | ||
375 | /* | 424 | /* |
376 | * dccp_pr_debug("is %llu <= %llu <= %llu? ", ackno_end_rl, | 425 | * If our AVR sequence number is greater than the ack, go |
377 | * av->dccpav_ack_seqno, ackno); | 426 | * forward in the AVR list until it is not so. |
378 | */ | 427 | */ |
379 | if (between48(av->dccpav_ack_seqno, ackno_end_rl, ackno)) { | 428 | list_for_each_entry_from(avr, &av->dccpav_records, |
429 | dccpavr_node) { | ||
430 | if (!after48(avr->dccpavr_ack_seqno, ackno)) | ||
431 | goto found; | ||
432 | } | ||
433 | /* End of the dccpav_records list, not found, exit */ | ||
434 | break; | ||
435 | found: | ||
436 | if (between48(avr->dccpavr_ack_seqno, ackno_end_rl, ackno)) { | ||
380 | const u8 state = (*vector & | 437 | const u8 state = (*vector & |
381 | DCCP_ACKVEC_STATE_MASK) >> 6; | 438 | DCCP_ACKVEC_STATE_MASK) >> 6; |
382 | /* dccp_pr_debug_cat("yes\n"); */ | ||
383 | |||
384 | if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) { | 439 | if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) { |
385 | #ifdef CONFIG_IP_DCCP_DEBUG | 440 | #ifdef CONFIG_IP_DCCP_DEBUG |
386 | struct dccp_sock *dp = dccp_sk(sk); | 441 | struct dccp_sock *dp = dccp_sk(sk); |
@@ -393,19 +448,16 @@ static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av, | |||
393 | "ACKED!\n", | 448 | "ACKED!\n", |
394 | debug_prefix, len, | 449 | debug_prefix, len, |
395 | (unsigned long long) | 450 | (unsigned long long) |
396 | av->dccpav_ack_seqno, | 451 | avr->dccpavr_ack_seqno, |
397 | (unsigned long long) | 452 | (unsigned long long) |
398 | av->dccpav_ack_ackno); | 453 | avr->dccpavr_ack_ackno); |
399 | dccp_ackvec_throw_away_ack_record(av); | 454 | dccp_ackvec_throw_record(av, avr); |
400 | } | 455 | } |
401 | /* | 456 | /* |
402 | * If dccpav_ack_seqno was not received, no problem | 457 | * If it wasn't received, continue scanning... we might |
403 | * we'll send another ACK vector. | 458 | * find another one. |
404 | */ | 459 | */ |
405 | av->dccpav_ack_seqno = DCCP_MAX_SEQNO + 1; | ||
406 | break; | ||
407 | } | 460 | } |
408 | /* dccp_pr_debug_cat("no\n"); */ | ||
409 | 461 | ||
410 | dccp_set_seqno(&ackno, ackno_end_rl - 1); | 462 | dccp_set_seqno(&ackno, ackno_end_rl - 1); |
411 | ++vector; | 463 | ++vector; |
@@ -424,3 +476,43 @@ int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, | |||
424 | len, value); | 476 | len, value); |
425 | return 0; | 477 | return 0; |
426 | } | 478 | } |
479 | |||
480 | static char dccp_ackvec_slab_msg[] __initdata = | ||
481 | KERN_CRIT "DCCP: Unable to create ack vectors slab caches\n"; | ||
482 | |||
483 | int __init dccp_ackvec_init(void) | ||
484 | { | ||
485 | dccp_ackvec_slab = kmem_cache_create("dccp_ackvec", | ||
486 | sizeof(struct dccp_ackvec), 0, | ||
487 | SLAB_HWCACHE_ALIGN, NULL, NULL); | ||
488 | if (dccp_ackvec_slab == NULL) | ||
489 | goto out_err; | ||
490 | |||
491 | dccp_ackvec_record_slab = | ||
492 | kmem_cache_create("dccp_ackvec_record", | ||
493 | sizeof(struct dccp_ackvec_record), | ||
494 | 0, SLAB_HWCACHE_ALIGN, NULL, NULL); | ||
495 | if (dccp_ackvec_record_slab == NULL) | ||
496 | goto out_destroy_slab; | ||
497 | |||
498 | return 0; | ||
499 | |||
500 | out_destroy_slab: | ||
501 | kmem_cache_destroy(dccp_ackvec_slab); | ||
502 | dccp_ackvec_slab = NULL; | ||
503 | out_err: | ||
504 | printk(dccp_ackvec_slab_msg); | ||
505 | return -ENOBUFS; | ||
506 | } | ||
507 | |||
508 | void dccp_ackvec_exit(void) | ||
509 | { | ||
510 | if (dccp_ackvec_slab != NULL) { | ||
511 | kmem_cache_destroy(dccp_ackvec_slab); | ||
512 | dccp_ackvec_slab = NULL; | ||
513 | } | ||
514 | if (dccp_ackvec_record_slab != NULL) { | ||
515 | kmem_cache_destroy(dccp_ackvec_record_slab); | ||
516 | dccp_ackvec_record_slab = NULL; | ||
517 | } | ||
518 | } | ||
diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h index f7dfb5f67b87..ec7a89bb7b39 100644 --- a/net/dccp/ackvec.h +++ b/net/dccp/ackvec.h | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #include <linux/config.h> | 14 | #include <linux/config.h> |
15 | #include <linux/compiler.h> | 15 | #include <linux/compiler.h> |
16 | #include <linux/list.h> | ||
16 | #include <linux/time.h> | 17 | #include <linux/time.h> |
17 | #include <linux/types.h> | 18 | #include <linux/types.h> |
18 | 19 | ||
@@ -42,39 +43,57 @@ | |||
42 | * Ack Vectors it has recently sent. For each packet sent carrying an | 43 | * Ack Vectors it has recently sent. For each packet sent carrying an |
43 | * Ack Vector, it remembers four variables: | 44 | * Ack Vector, it remembers four variables: |
44 | * | 45 | * |
45 | * @dccpav_ack_seqno - the Sequence Number used for the packet | ||
46 | * (HC-Receiver seqno) | ||
47 | * @dccpav_ack_ptr - the value of buf_head at the time of acknowledgement. | 46 | * @dccpav_ack_ptr - the value of buf_head at the time of acknowledgement. |
48 | * @dccpav_ack_ackno - the Acknowledgement Number used for the packet | 47 | * @dccpav_records - list of dccp_ackvec_record |
49 | * (HC-Sender seqno) | ||
50 | * @dccpav_ack_nonce - the one-bit sum of the ECN Nonces for all State 0. | 48 | * @dccpav_ack_nonce - the one-bit sum of the ECN Nonces for all State 0. |
51 | * | 49 | * |
52 | * @dccpav_buf_len - circular buffer length | ||
53 | * @dccpav_time - the time in usecs | 50 | * @dccpav_time - the time in usecs |
54 | * @dccpav_buf - circular buffer of acknowledgeable packets | 51 | * @dccpav_buf - circular buffer of acknowledgeable packets |
55 | */ | 52 | */ |
56 | struct dccp_ackvec { | 53 | struct dccp_ackvec { |
57 | u64 dccpav_buf_ackno; | 54 | u64 dccpav_buf_ackno; |
58 | u64 dccpav_ack_seqno; | 55 | struct list_head dccpav_records; |
59 | u64 dccpav_ack_ackno; | ||
60 | struct timeval dccpav_time; | 56 | struct timeval dccpav_time; |
61 | u8 dccpav_buf_head; | 57 | u8 dccpav_buf_head; |
62 | u8 dccpav_buf_tail; | 58 | u8 dccpav_buf_tail; |
63 | u8 dccpav_ack_ptr; | 59 | u8 dccpav_ack_ptr; |
64 | u8 dccpav_sent_len; | 60 | u8 dccpav_sent_len; |
65 | u8 dccpav_vec_len; | 61 | u8 dccpav_vec_len; |
66 | u8 dccpav_buf_len; | ||
67 | u8 dccpav_buf_nonce; | 62 | u8 dccpav_buf_nonce; |
68 | u8 dccpav_ack_nonce; | 63 | u8 dccpav_ack_nonce; |
69 | u8 dccpav_buf[0]; | 64 | u8 dccpav_buf[DCCP_MAX_ACKVEC_LEN]; |
65 | }; | ||
66 | |||
67 | /** struct dccp_ackvec_record - ack vector record | ||
68 | * | ||
69 | * ACK vector record as defined in Appendix A of spec. | ||
70 | * | ||
71 | * The list is sorted by dccpavr_ack_seqno | ||
72 | * | ||
73 | * @dccpavr_node - node in dccpav_records | ||
74 | * @dccpavr_ack_seqno - sequence number of the packet this record was sent on | ||
75 | * @dccpavr_ack_ackno - sequence number being acknowledged | ||
76 | * @dccpavr_ack_ptr - pointer into dccpav_buf where this record starts | ||
77 | * @dccpavr_ack_nonce - dccpav_ack_nonce at the time this record was sent | ||
78 | * @dccpavr_sent_len - lenght of the record in dccpav_buf | ||
79 | */ | ||
80 | struct dccp_ackvec_record { | ||
81 | struct list_head dccpavr_node; | ||
82 | u64 dccpavr_ack_seqno; | ||
83 | u64 dccpavr_ack_ackno; | ||
84 | u8 dccpavr_ack_ptr; | ||
85 | u8 dccpavr_ack_nonce; | ||
86 | u8 dccpavr_sent_len; | ||
70 | }; | 87 | }; |
71 | 88 | ||
72 | struct sock; | 89 | struct sock; |
73 | struct sk_buff; | 90 | struct sk_buff; |
74 | 91 | ||
75 | #ifdef CONFIG_IP_DCCP_ACKVEC | 92 | #ifdef CONFIG_IP_DCCP_ACKVEC |
76 | extern struct dccp_ackvec *dccp_ackvec_alloc(unsigned int len, | 93 | extern int dccp_ackvec_init(void); |
77 | const gfp_t priority); | 94 | extern void dccp_ackvec_exit(void); |
95 | |||
96 | extern struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority); | ||
78 | extern void dccp_ackvec_free(struct dccp_ackvec *av); | 97 | extern void dccp_ackvec_free(struct dccp_ackvec *av); |
79 | 98 | ||
80 | extern int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, | 99 | extern int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, |
@@ -92,8 +111,16 @@ static inline int dccp_ackvec_pending(const struct dccp_ackvec *av) | |||
92 | return av->dccpav_sent_len != av->dccpav_vec_len; | 111 | return av->dccpav_sent_len != av->dccpav_vec_len; |
93 | } | 112 | } |
94 | #else /* CONFIG_IP_DCCP_ACKVEC */ | 113 | #else /* CONFIG_IP_DCCP_ACKVEC */ |
95 | static inline struct dccp_ackvec *dccp_ackvec_alloc(unsigned int len, | 114 | static inline int dccp_ackvec_init(void) |
96 | const gfp_t priority) | 115 | { |
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static inline void dccp_ackvec_exit(void) | ||
120 | { | ||
121 | } | ||
122 | |||
123 | static inline struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority) | ||
97 | { | 124 | { |
98 | return NULL; | 125 | return NULL; |
99 | } | 126 | } |
diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c index 9d8fc0e289ea..ff05e59043cd 100644 --- a/net/dccp/ccid.c +++ b/net/dccp/ccid.c | |||
@@ -13,7 +13,7 @@ | |||
13 | 13 | ||
14 | #include "ccid.h" | 14 | #include "ccid.h" |
15 | 15 | ||
16 | static struct ccid *ccids[CCID_MAX]; | 16 | static struct ccid_operations *ccids[CCID_MAX]; |
17 | #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) | 17 | #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) |
18 | static atomic_t ccids_lockct = ATOMIC_INIT(0); | 18 | static atomic_t ccids_lockct = ATOMIC_INIT(0); |
19 | static DEFINE_SPINLOCK(ccids_lock); | 19 | static DEFINE_SPINLOCK(ccids_lock); |
@@ -55,85 +55,202 @@ static inline void ccids_read_unlock(void) | |||
55 | #define ccids_read_unlock() do { } while(0) | 55 | #define ccids_read_unlock() do { } while(0) |
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | int ccid_register(struct ccid *ccid) | 58 | static kmem_cache_t *ccid_kmem_cache_create(int obj_size, const char *fmt,...) |
59 | { | 59 | { |
60 | int err; | 60 | kmem_cache_t *slab; |
61 | char slab_name_fmt[32], *slab_name; | ||
62 | va_list args; | ||
61 | 63 | ||
62 | if (ccid->ccid_init == NULL) | 64 | va_start(args, fmt); |
63 | return -1; | 65 | vsnprintf(slab_name_fmt, sizeof(slab_name_fmt), fmt, args); |
66 | va_end(args); | ||
67 | |||
68 | slab_name = kstrdup(slab_name_fmt, GFP_KERNEL); | ||
69 | if (slab_name == NULL) | ||
70 | return NULL; | ||
71 | slab = kmem_cache_create(slab_name, sizeof(struct ccid) + obj_size, 0, | ||
72 | SLAB_HWCACHE_ALIGN, NULL, NULL); | ||
73 | if (slab == NULL) | ||
74 | kfree(slab_name); | ||
75 | return slab; | ||
76 | } | ||
77 | |||
78 | static void ccid_kmem_cache_destroy(kmem_cache_t *slab) | ||
79 | { | ||
80 | if (slab != NULL) { | ||
81 | const char *name = kmem_cache_name(slab); | ||
82 | |||
83 | kmem_cache_destroy(slab); | ||
84 | kfree(name); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | int ccid_register(struct ccid_operations *ccid_ops) | ||
89 | { | ||
90 | int err = -ENOBUFS; | ||
91 | |||
92 | ccid_ops->ccid_hc_rx_slab = | ||
93 | ccid_kmem_cache_create(ccid_ops->ccid_hc_rx_obj_size, | ||
94 | "%s_hc_rx_sock", | ||
95 | ccid_ops->ccid_name); | ||
96 | if (ccid_ops->ccid_hc_rx_slab == NULL) | ||
97 | goto out; | ||
98 | |||
99 | ccid_ops->ccid_hc_tx_slab = | ||
100 | ccid_kmem_cache_create(ccid_ops->ccid_hc_tx_obj_size, | ||
101 | "%s_hc_tx_sock", | ||
102 | ccid_ops->ccid_name); | ||
103 | if (ccid_ops->ccid_hc_tx_slab == NULL) | ||
104 | goto out_free_rx_slab; | ||
64 | 105 | ||
65 | ccids_write_lock(); | 106 | ccids_write_lock(); |
66 | err = -EEXIST; | 107 | err = -EEXIST; |
67 | if (ccids[ccid->ccid_id] == NULL) { | 108 | if (ccids[ccid_ops->ccid_id] == NULL) { |
68 | ccids[ccid->ccid_id] = ccid; | 109 | ccids[ccid_ops->ccid_id] = ccid_ops; |
69 | err = 0; | 110 | err = 0; |
70 | } | 111 | } |
71 | ccids_write_unlock(); | 112 | ccids_write_unlock(); |
72 | if (err == 0) | 113 | if (err != 0) |
73 | pr_info("CCID: Registered CCID %d (%s)\n", | 114 | goto out_free_tx_slab; |
74 | ccid->ccid_id, ccid->ccid_name); | 115 | |
116 | pr_info("CCID: Registered CCID %d (%s)\n", | ||
117 | ccid_ops->ccid_id, ccid_ops->ccid_name); | ||
118 | out: | ||
75 | return err; | 119 | return err; |
120 | out_free_tx_slab: | ||
121 | ccid_kmem_cache_destroy(ccid_ops->ccid_hc_tx_slab); | ||
122 | ccid_ops->ccid_hc_tx_slab = NULL; | ||
123 | goto out; | ||
124 | out_free_rx_slab: | ||
125 | ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab); | ||
126 | ccid_ops->ccid_hc_rx_slab = NULL; | ||
127 | goto out; | ||
76 | } | 128 | } |
77 | 129 | ||
78 | EXPORT_SYMBOL_GPL(ccid_register); | 130 | EXPORT_SYMBOL_GPL(ccid_register); |
79 | 131 | ||
80 | int ccid_unregister(struct ccid *ccid) | 132 | int ccid_unregister(struct ccid_operations *ccid_ops) |
81 | { | 133 | { |
82 | ccids_write_lock(); | 134 | ccids_write_lock(); |
83 | ccids[ccid->ccid_id] = NULL; | 135 | ccids[ccid_ops->ccid_id] = NULL; |
84 | ccids_write_unlock(); | 136 | ccids_write_unlock(); |
137 | |||
138 | ccid_kmem_cache_destroy(ccid_ops->ccid_hc_tx_slab); | ||
139 | ccid_ops->ccid_hc_tx_slab = NULL; | ||
140 | ccid_kmem_cache_destroy(ccid_ops->ccid_hc_rx_slab); | ||
141 | ccid_ops->ccid_hc_rx_slab = NULL; | ||
142 | |||
85 | pr_info("CCID: Unregistered CCID %d (%s)\n", | 143 | pr_info("CCID: Unregistered CCID %d (%s)\n", |
86 | ccid->ccid_id, ccid->ccid_name); | 144 | ccid_ops->ccid_id, ccid_ops->ccid_name); |
87 | return 0; | 145 | return 0; |
88 | } | 146 | } |
89 | 147 | ||
90 | EXPORT_SYMBOL_GPL(ccid_unregister); | 148 | EXPORT_SYMBOL_GPL(ccid_unregister); |
91 | 149 | ||
92 | struct ccid *ccid_init(unsigned char id, struct sock *sk) | 150 | struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp) |
93 | { | 151 | { |
94 | struct ccid *ccid; | 152 | struct ccid_operations *ccid_ops; |
153 | struct ccid *ccid = NULL; | ||
95 | 154 | ||
155 | ccids_read_lock(); | ||
96 | #ifdef CONFIG_KMOD | 156 | #ifdef CONFIG_KMOD |
97 | if (ccids[id] == NULL) | 157 | if (ccids[id] == NULL) { |
158 | /* We only try to load if in process context */ | ||
159 | ccids_read_unlock(); | ||
160 | if (gfp & GFP_ATOMIC) | ||
161 | goto out; | ||
98 | request_module("net-dccp-ccid-%d", id); | 162 | request_module("net-dccp-ccid-%d", id); |
163 | ccids_read_lock(); | ||
164 | } | ||
99 | #endif | 165 | #endif |
100 | ccids_read_lock(); | 166 | ccid_ops = ccids[id]; |
167 | if (ccid_ops == NULL) | ||
168 | goto out_unlock; | ||
101 | 169 | ||
102 | ccid = ccids[id]; | 170 | if (!try_module_get(ccid_ops->ccid_owner)) |
103 | if (ccid == NULL) | 171 | goto out_unlock; |
104 | goto out; | ||
105 | 172 | ||
106 | if (!try_module_get(ccid->ccid_owner)) | 173 | ccids_read_unlock(); |
107 | goto out_err; | ||
108 | 174 | ||
109 | if (ccid->ccid_init(sk) != 0) | 175 | ccid = kmem_cache_alloc(rx ? ccid_ops->ccid_hc_rx_slab : |
176 | ccid_ops->ccid_hc_tx_slab, gfp); | ||
177 | if (ccid == NULL) | ||
110 | goto out_module_put; | 178 | goto out_module_put; |
179 | ccid->ccid_ops = ccid_ops; | ||
180 | if (rx) { | ||
181 | memset(ccid + 1, 0, ccid_ops->ccid_hc_rx_obj_size); | ||
182 | if (ccid->ccid_ops->ccid_hc_rx_init != NULL && | ||
183 | ccid->ccid_ops->ccid_hc_rx_init(ccid, sk) != 0) | ||
184 | goto out_free_ccid; | ||
185 | } else { | ||
186 | memset(ccid + 1, 0, ccid_ops->ccid_hc_tx_obj_size); | ||
187 | if (ccid->ccid_ops->ccid_hc_tx_init != NULL && | ||
188 | ccid->ccid_ops->ccid_hc_tx_init(ccid, sk) != 0) | ||
189 | goto out_free_ccid; | ||
190 | } | ||
111 | out: | 191 | out: |
112 | ccids_read_unlock(); | ||
113 | return ccid; | 192 | return ccid; |
114 | out_module_put: | 193 | out_unlock: |
115 | module_put(ccid->ccid_owner); | 194 | ccids_read_unlock(); |
116 | out_err: | 195 | goto out; |
196 | out_free_ccid: | ||
197 | kmem_cache_free(rx ? ccid_ops->ccid_hc_rx_slab : | ||
198 | ccid_ops->ccid_hc_tx_slab, ccid); | ||
117 | ccid = NULL; | 199 | ccid = NULL; |
200 | out_module_put: | ||
201 | module_put(ccid_ops->ccid_owner); | ||
118 | goto out; | 202 | goto out; |
119 | } | 203 | } |
120 | 204 | ||
121 | EXPORT_SYMBOL_GPL(ccid_init); | 205 | EXPORT_SYMBOL_GPL(ccid_new); |
206 | |||
207 | struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk, gfp_t gfp) | ||
208 | { | ||
209 | return ccid_new(id, sk, 1, gfp); | ||
210 | } | ||
211 | |||
212 | EXPORT_SYMBOL_GPL(ccid_hc_rx_new); | ||
213 | |||
214 | struct ccid *ccid_hc_tx_new(unsigned char id,struct sock *sk, gfp_t gfp) | ||
215 | { | ||
216 | return ccid_new(id, sk, 0, gfp); | ||
217 | } | ||
218 | |||
219 | EXPORT_SYMBOL_GPL(ccid_hc_tx_new); | ||
122 | 220 | ||
123 | void ccid_exit(struct ccid *ccid, struct sock *sk) | 221 | static void ccid_delete(struct ccid *ccid, struct sock *sk, int rx) |
124 | { | 222 | { |
223 | struct ccid_operations *ccid_ops; | ||
224 | |||
125 | if (ccid == NULL) | 225 | if (ccid == NULL) |
126 | return; | 226 | return; |
127 | 227 | ||
228 | ccid_ops = ccid->ccid_ops; | ||
229 | if (rx) { | ||
230 | if (ccid_ops->ccid_hc_rx_exit != NULL) | ||
231 | ccid_ops->ccid_hc_rx_exit(sk); | ||
232 | kmem_cache_free(ccid_ops->ccid_hc_rx_slab, ccid); | ||
233 | } else { | ||
234 | if (ccid_ops->ccid_hc_tx_exit != NULL) | ||
235 | ccid_ops->ccid_hc_tx_exit(sk); | ||
236 | kmem_cache_free(ccid_ops->ccid_hc_tx_slab, ccid); | ||
237 | } | ||
128 | ccids_read_lock(); | 238 | ccids_read_lock(); |
239 | if (ccids[ccid_ops->ccid_id] != NULL) | ||
240 | module_put(ccid_ops->ccid_owner); | ||
241 | ccids_read_unlock(); | ||
242 | } | ||
129 | 243 | ||
130 | if (ccids[ccid->ccid_id] != NULL) { | 244 | void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk) |
131 | if (ccid->ccid_exit != NULL) | 245 | { |
132 | ccid->ccid_exit(sk); | 246 | ccid_delete(ccid, sk, 1); |
133 | module_put(ccid->ccid_owner); | 247 | } |
134 | } | ||
135 | 248 | ||
136 | ccids_read_unlock(); | 249 | EXPORT_SYMBOL_GPL(ccid_hc_rx_delete); |
250 | |||
251 | void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk) | ||
252 | { | ||
253 | ccid_delete(ccid, sk, 0); | ||
137 | } | 254 | } |
138 | 255 | ||
139 | EXPORT_SYMBOL_GPL(ccid_exit); | 256 | EXPORT_SYMBOL_GPL(ccid_hc_tx_delete); |
diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h index de681c6ad081..f7eb6c613414 100644 --- a/net/dccp/ccid.h +++ b/net/dccp/ccid.h | |||
@@ -23,14 +23,16 @@ | |||
23 | 23 | ||
24 | struct tcp_info; | 24 | struct tcp_info; |
25 | 25 | ||
26 | struct ccid { | 26 | struct ccid_operations { |
27 | unsigned char ccid_id; | 27 | unsigned char ccid_id; |
28 | const char *ccid_name; | 28 | const char *ccid_name; |
29 | struct module *ccid_owner; | 29 | struct module *ccid_owner; |
30 | int (*ccid_init)(struct sock *sk); | 30 | kmem_cache_t *ccid_hc_rx_slab; |
31 | void (*ccid_exit)(struct sock *sk); | 31 | __u32 ccid_hc_rx_obj_size; |
32 | int (*ccid_hc_rx_init)(struct sock *sk); | 32 | kmem_cache_t *ccid_hc_tx_slab; |
33 | int (*ccid_hc_tx_init)(struct sock *sk); | 33 | __u32 ccid_hc_tx_obj_size; |
34 | int (*ccid_hc_rx_init)(struct ccid *ccid, struct sock *sk); | ||
35 | int (*ccid_hc_tx_init)(struct ccid *ccid, struct sock *sk); | ||
34 | void (*ccid_hc_rx_exit)(struct sock *sk); | 36 | void (*ccid_hc_rx_exit)(struct sock *sk); |
35 | void (*ccid_hc_tx_exit)(struct sock *sk); | 37 | void (*ccid_hc_tx_exit)(struct sock *sk); |
36 | void (*ccid_hc_rx_packet_recv)(struct sock *sk, | 38 | void (*ccid_hc_rx_packet_recv)(struct sock *sk, |
@@ -39,9 +41,9 @@ struct ccid { | |||
39 | unsigned char option, | 41 | unsigned char option, |
40 | unsigned char len, u16 idx, | 42 | unsigned char len, u16 idx, |
41 | unsigned char* value); | 43 | unsigned char* value); |
42 | void (*ccid_hc_rx_insert_options)(struct sock *sk, | 44 | int (*ccid_hc_rx_insert_options)(struct sock *sk, |
43 | struct sk_buff *skb); | 45 | struct sk_buff *skb); |
44 | void (*ccid_hc_tx_insert_options)(struct sock *sk, | 46 | int (*ccid_hc_tx_insert_options)(struct sock *sk, |
45 | struct sk_buff *skb); | 47 | struct sk_buff *skb); |
46 | void (*ccid_hc_tx_packet_recv)(struct sock *sk, | 48 | void (*ccid_hc_tx_packet_recv)(struct sock *sk, |
47 | struct sk_buff *skb); | 49 | struct sk_buff *skb); |
@@ -67,75 +69,58 @@ struct ccid { | |||
67 | int __user *optlen); | 69 | int __user *optlen); |
68 | }; | 70 | }; |
69 | 71 | ||
70 | extern int ccid_register(struct ccid *ccid); | 72 | extern int ccid_register(struct ccid_operations *ccid_ops); |
71 | extern int ccid_unregister(struct ccid *ccid); | 73 | extern int ccid_unregister(struct ccid_operations *ccid_ops); |
72 | 74 | ||
73 | extern struct ccid *ccid_init(unsigned char id, struct sock *sk); | 75 | struct ccid { |
74 | extern void ccid_exit(struct ccid *ccid, struct sock *sk); | 76 | struct ccid_operations *ccid_ops; |
77 | char ccid_priv[0]; | ||
78 | }; | ||
75 | 79 | ||
76 | static inline void __ccid_get(struct ccid *ccid) | 80 | static inline void *ccid_priv(const struct ccid *ccid) |
77 | { | 81 | { |
78 | __module_get(ccid->ccid_owner); | 82 | return (void *)ccid->ccid_priv; |
79 | } | 83 | } |
80 | 84 | ||
85 | extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, | ||
86 | gfp_t gfp); | ||
87 | |||
88 | extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk, | ||
89 | gfp_t gfp); | ||
90 | extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk, | ||
91 | gfp_t gfp); | ||
92 | |||
93 | extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk); | ||
94 | extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk); | ||
95 | |||
81 | static inline int ccid_hc_tx_send_packet(struct ccid *ccid, struct sock *sk, | 96 | static inline int ccid_hc_tx_send_packet(struct ccid *ccid, struct sock *sk, |
82 | struct sk_buff *skb, int len) | 97 | struct sk_buff *skb, int len) |
83 | { | 98 | { |
84 | int rc = 0; | 99 | int rc = 0; |
85 | if (ccid->ccid_hc_tx_send_packet != NULL) | 100 | if (ccid->ccid_ops->ccid_hc_tx_send_packet != NULL) |
86 | rc = ccid->ccid_hc_tx_send_packet(sk, skb, len); | 101 | rc = ccid->ccid_ops->ccid_hc_tx_send_packet(sk, skb, len); |
87 | return rc; | 102 | return rc; |
88 | } | 103 | } |
89 | 104 | ||
90 | static inline void ccid_hc_tx_packet_sent(struct ccid *ccid, struct sock *sk, | 105 | static inline void ccid_hc_tx_packet_sent(struct ccid *ccid, struct sock *sk, |
91 | int more, int len) | 106 | int more, int len) |
92 | { | 107 | { |
93 | if (ccid->ccid_hc_tx_packet_sent != NULL) | 108 | if (ccid->ccid_ops->ccid_hc_tx_packet_sent != NULL) |
94 | ccid->ccid_hc_tx_packet_sent(sk, more, len); | 109 | ccid->ccid_ops->ccid_hc_tx_packet_sent(sk, more, len); |
95 | } | ||
96 | |||
97 | static inline int ccid_hc_rx_init(struct ccid *ccid, struct sock *sk) | ||
98 | { | ||
99 | int rc = 0; | ||
100 | if (ccid->ccid_hc_rx_init != NULL) | ||
101 | rc = ccid->ccid_hc_rx_init(sk); | ||
102 | return rc; | ||
103 | } | ||
104 | |||
105 | static inline int ccid_hc_tx_init(struct ccid *ccid, struct sock *sk) | ||
106 | { | ||
107 | int rc = 0; | ||
108 | if (ccid->ccid_hc_tx_init != NULL) | ||
109 | rc = ccid->ccid_hc_tx_init(sk); | ||
110 | return rc; | ||
111 | } | ||
112 | |||
113 | static inline void ccid_hc_rx_exit(struct ccid *ccid, struct sock *sk) | ||
114 | { | ||
115 | if (ccid != NULL && ccid->ccid_hc_rx_exit != NULL && | ||
116 | dccp_sk(sk)->dccps_hc_rx_ccid_private != NULL) | ||
117 | ccid->ccid_hc_rx_exit(sk); | ||
118 | } | ||
119 | |||
120 | static inline void ccid_hc_tx_exit(struct ccid *ccid, struct sock *sk) | ||
121 | { | ||
122 | if (ccid != NULL && ccid->ccid_hc_tx_exit != NULL && | ||
123 | dccp_sk(sk)->dccps_hc_tx_ccid_private != NULL) | ||
124 | ccid->ccid_hc_tx_exit(sk); | ||
125 | } | 110 | } |
126 | 111 | ||
127 | static inline void ccid_hc_rx_packet_recv(struct ccid *ccid, struct sock *sk, | 112 | static inline void ccid_hc_rx_packet_recv(struct ccid *ccid, struct sock *sk, |
128 | struct sk_buff *skb) | 113 | struct sk_buff *skb) |
129 | { | 114 | { |
130 | if (ccid->ccid_hc_rx_packet_recv != NULL) | 115 | if (ccid->ccid_ops->ccid_hc_rx_packet_recv != NULL) |
131 | ccid->ccid_hc_rx_packet_recv(sk, skb); | 116 | ccid->ccid_ops->ccid_hc_rx_packet_recv(sk, skb); |
132 | } | 117 | } |
133 | 118 | ||
134 | static inline void ccid_hc_tx_packet_recv(struct ccid *ccid, struct sock *sk, | 119 | static inline void ccid_hc_tx_packet_recv(struct ccid *ccid, struct sock *sk, |
135 | struct sk_buff *skb) | 120 | struct sk_buff *skb) |
136 | { | 121 | { |
137 | if (ccid->ccid_hc_tx_packet_recv != NULL) | 122 | if (ccid->ccid_ops->ccid_hc_tx_packet_recv != NULL) |
138 | ccid->ccid_hc_tx_packet_recv(sk, skb); | 123 | ccid->ccid_ops->ccid_hc_tx_packet_recv(sk, skb); |
139 | } | 124 | } |
140 | 125 | ||
141 | static inline int ccid_hc_tx_parse_options(struct ccid *ccid, struct sock *sk, | 126 | static inline int ccid_hc_tx_parse_options(struct ccid *ccid, struct sock *sk, |
@@ -144,8 +129,8 @@ static inline int ccid_hc_tx_parse_options(struct ccid *ccid, struct sock *sk, | |||
144 | unsigned char* value) | 129 | unsigned char* value) |
145 | { | 130 | { |
146 | int rc = 0; | 131 | int rc = 0; |
147 | if (ccid->ccid_hc_tx_parse_options != NULL) | 132 | if (ccid->ccid_ops->ccid_hc_tx_parse_options != NULL) |
148 | rc = ccid->ccid_hc_tx_parse_options(sk, option, len, idx, | 133 | rc = ccid->ccid_ops->ccid_hc_tx_parse_options(sk, option, len, idx, |
149 | value); | 134 | value); |
150 | return rc; | 135 | return rc; |
151 | } | 136 | } |
@@ -156,37 +141,39 @@ static inline int ccid_hc_rx_parse_options(struct ccid *ccid, struct sock *sk, | |||
156 | unsigned char* value) | 141 | unsigned char* value) |
157 | { | 142 | { |
158 | int rc = 0; | 143 | int rc = 0; |
159 | if (ccid->ccid_hc_rx_parse_options != NULL) | 144 | if (ccid->ccid_ops->ccid_hc_rx_parse_options != NULL) |
160 | rc = ccid->ccid_hc_rx_parse_options(sk, option, len, idx, value); | 145 | rc = ccid->ccid_ops->ccid_hc_rx_parse_options(sk, option, len, idx, value); |
161 | return rc; | 146 | return rc; |
162 | } | 147 | } |
163 | 148 | ||
164 | static inline void ccid_hc_tx_insert_options(struct ccid *ccid, struct sock *sk, | 149 | static inline int ccid_hc_tx_insert_options(struct ccid *ccid, struct sock *sk, |
165 | struct sk_buff *skb) | 150 | struct sk_buff *skb) |
166 | { | 151 | { |
167 | if (ccid->ccid_hc_tx_insert_options != NULL) | 152 | if (ccid->ccid_ops->ccid_hc_tx_insert_options != NULL) |
168 | ccid->ccid_hc_tx_insert_options(sk, skb); | 153 | return ccid->ccid_ops->ccid_hc_tx_insert_options(sk, skb); |
154 | return 0; | ||
169 | } | 155 | } |
170 | 156 | ||
171 | static inline void ccid_hc_rx_insert_options(struct ccid *ccid, struct sock *sk, | 157 | static inline int ccid_hc_rx_insert_options(struct ccid *ccid, struct sock *sk, |
172 | struct sk_buff *skb) | 158 | struct sk_buff *skb) |
173 | { | 159 | { |
174 | if (ccid->ccid_hc_rx_insert_options != NULL) | 160 | if (ccid->ccid_ops->ccid_hc_rx_insert_options != NULL) |
175 | ccid->ccid_hc_rx_insert_options(sk, skb); | 161 | return ccid->ccid_ops->ccid_hc_rx_insert_options(sk, skb); |
162 | return 0; | ||
176 | } | 163 | } |
177 | 164 | ||
178 | static inline void ccid_hc_rx_get_info(struct ccid *ccid, struct sock *sk, | 165 | static inline void ccid_hc_rx_get_info(struct ccid *ccid, struct sock *sk, |
179 | struct tcp_info *info) | 166 | struct tcp_info *info) |
180 | { | 167 | { |
181 | if (ccid->ccid_hc_rx_get_info != NULL) | 168 | if (ccid->ccid_ops->ccid_hc_rx_get_info != NULL) |
182 | ccid->ccid_hc_rx_get_info(sk, info); | 169 | ccid->ccid_ops->ccid_hc_rx_get_info(sk, info); |
183 | } | 170 | } |
184 | 171 | ||
185 | static inline void ccid_hc_tx_get_info(struct ccid *ccid, struct sock *sk, | 172 | static inline void ccid_hc_tx_get_info(struct ccid *ccid, struct sock *sk, |
186 | struct tcp_info *info) | 173 | struct tcp_info *info) |
187 | { | 174 | { |
188 | if (ccid->ccid_hc_tx_get_info != NULL) | 175 | if (ccid->ccid_ops->ccid_hc_tx_get_info != NULL) |
189 | ccid->ccid_hc_tx_get_info(sk, info); | 176 | ccid->ccid_ops->ccid_hc_tx_get_info(sk, info); |
190 | } | 177 | } |
191 | 178 | ||
192 | static inline int ccid_hc_rx_getsockopt(struct ccid *ccid, struct sock *sk, | 179 | static inline int ccid_hc_rx_getsockopt(struct ccid *ccid, struct sock *sk, |
@@ -194,8 +181,8 @@ static inline int ccid_hc_rx_getsockopt(struct ccid *ccid, struct sock *sk, | |||
194 | u32 __user *optval, int __user *optlen) | 181 | u32 __user *optval, int __user *optlen) |
195 | { | 182 | { |
196 | int rc = -ENOPROTOOPT; | 183 | int rc = -ENOPROTOOPT; |
197 | if (ccid->ccid_hc_rx_getsockopt != NULL) | 184 | if (ccid->ccid_ops->ccid_hc_rx_getsockopt != NULL) |
198 | rc = ccid->ccid_hc_rx_getsockopt(sk, optname, len, | 185 | rc = ccid->ccid_ops->ccid_hc_rx_getsockopt(sk, optname, len, |
199 | optval, optlen); | 186 | optval, optlen); |
200 | return rc; | 187 | return rc; |
201 | } | 188 | } |
@@ -205,8 +192,8 @@ static inline int ccid_hc_tx_getsockopt(struct ccid *ccid, struct sock *sk, | |||
205 | u32 __user *optval, int __user *optlen) | 192 | u32 __user *optval, int __user *optlen) |
206 | { | 193 | { |
207 | int rc = -ENOPROTOOPT; | 194 | int rc = -ENOPROTOOPT; |
208 | if (ccid->ccid_hc_tx_getsockopt != NULL) | 195 | if (ccid->ccid_ops->ccid_hc_tx_getsockopt != NULL) |
209 | rc = ccid->ccid_hc_tx_getsockopt(sk, optname, len, | 196 | rc = ccid->ccid_ops->ccid_hc_tx_getsockopt(sk, optname, len, |
210 | optval, optlen); | 197 | optval, optlen); |
211 | return rc; | 198 | return rc; |
212 | } | 199 | } |
diff --git a/net/dccp/ccids/Kconfig b/net/dccp/ccids/Kconfig index 7684d83946a4..ca00191628f7 100644 --- a/net/dccp/ccids/Kconfig +++ b/net/dccp/ccids/Kconfig | |||
@@ -1,9 +1,39 @@ | |||
1 | menu "DCCP CCIDs Configuration (EXPERIMENTAL)" | 1 | menu "DCCP CCIDs Configuration (EXPERIMENTAL)" |
2 | depends on IP_DCCP && EXPERIMENTAL | 2 | depends on IP_DCCP && EXPERIMENTAL |
3 | 3 | ||
4 | config IP_DCCP_CCID2 | ||
5 | tristate "CCID2 (TCP-Like) (EXPERIMENTAL)" | ||
6 | depends on IP_DCCP | ||
7 | def_tristate IP_DCCP | ||
8 | select IP_DCCP_ACKVEC | ||
9 | ---help--- | ||
10 | CCID 2, TCP-like Congestion Control, denotes Additive Increase, | ||
11 | Multiplicative Decrease (AIMD) congestion control with behavior | ||
12 | modelled directly on TCP, including congestion window, slow start, | ||
13 | timeouts, and so forth [RFC 2581]. CCID 2 achieves maximum | ||
14 | bandwidth over the long term, consistent with the use of end-to-end | ||
15 | congestion control, but halves its congestion window in response to | ||
16 | each congestion event. This leads to the abrupt rate changes | ||
17 | typical of TCP. Applications should use CCID 2 if they prefer | ||
18 | maximum bandwidth utilization to steadiness of rate. This is often | ||
19 | the case for applications that are not playing their data directly | ||
20 | to the user. For example, a hypothetical application that | ||
21 | transferred files over DCCP, using application-level retransmissions | ||
22 | for lost packets, would prefer CCID 2 to CCID 3. On-line games may | ||
23 | also prefer CCID 2. | ||
24 | |||
25 | CCID 2 is further described in: | ||
26 | http://www.icir.org/kohler/dccp/draft-ietf-dccp-ccid2-10.txt | ||
27 | |||
28 | This text was extracted from: | ||
29 | http://www.icir.org/kohler/dccp/draft-ietf-dccp-spec-13.txt | ||
30 | |||
31 | If in doubt, say M. | ||
32 | |||
4 | config IP_DCCP_CCID3 | 33 | config IP_DCCP_CCID3 |
5 | tristate "CCID3 (TFRC) (EXPERIMENTAL)" | 34 | tristate "CCID3 (TCP-Friendly) (EXPERIMENTAL)" |
6 | depends on IP_DCCP | 35 | depends on IP_DCCP |
36 | def_tristate IP_DCCP | ||
7 | ---help--- | 37 | ---help--- |
8 | CCID 3 denotes TCP-Friendly Rate Control (TFRC), an equation-based | 38 | CCID 3 denotes TCP-Friendly Rate Control (TFRC), an equation-based |
9 | rate-controlled congestion control mechanism. TFRC is designed to | 39 | rate-controlled congestion control mechanism. TFRC is designed to |
@@ -15,10 +45,15 @@ config IP_DCCP_CCID3 | |||
15 | suitable than CCID 2 for applications such streaming media where a | 45 | suitable than CCID 2 for applications such streaming media where a |
16 | relatively smooth sending rate is of importance. | 46 | relatively smooth sending rate is of importance. |
17 | 47 | ||
18 | CCID 3 is further described in [CCID 3 PROFILE]. The TFRC | 48 | CCID 3 is further described in: |
19 | congestion control algorithms were initially described in RFC 3448. | 49 | |
50 | http://www.icir.org/kohler/dccp/draft-ietf-dccp-ccid3-11.txt. | ||
51 | |||
52 | The TFRC congestion control algorithms were initially described in | ||
53 | RFC 3448. | ||
20 | 54 | ||
21 | This text was extracted from draft-ietf-dccp-spec-11.txt. | 55 | This text was extracted from: |
56 | http://www.icir.org/kohler/dccp/draft-ietf-dccp-spec-13.txt | ||
22 | 57 | ||
23 | If in doubt, say M. | 58 | If in doubt, say M. |
24 | 59 | ||
diff --git a/net/dccp/ccids/Makefile b/net/dccp/ccids/Makefile index 956f79f50743..438f20bccff7 100644 --- a/net/dccp/ccids/Makefile +++ b/net/dccp/ccids/Makefile | |||
@@ -2,4 +2,8 @@ obj-$(CONFIG_IP_DCCP_CCID3) += dccp_ccid3.o | |||
2 | 2 | ||
3 | dccp_ccid3-y := ccid3.o | 3 | dccp_ccid3-y := ccid3.o |
4 | 4 | ||
5 | obj-$(CONFIG_IP_DCCP_CCID2) += dccp_ccid2.o | ||
6 | |||
7 | dccp_ccid2-y := ccid2.o | ||
8 | |||
5 | obj-y += lib/ | 9 | obj-y += lib/ |
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c new file mode 100644 index 000000000000..d4f9e2d33453 --- /dev/null +++ b/net/dccp/ccids/ccid2.c | |||
@@ -0,0 +1,779 @@ | |||
1 | /* | ||
2 | * net/dccp/ccids/ccid2.c | ||
3 | * | ||
4 | * Copyright (c) 2005, 2006 Andrea Bittau <a.bittau@cs.ucl.ac.uk> | ||
5 | * | ||
6 | * Changes to meet Linux coding standards, and DCCP infrastructure fixes. | ||
7 | * | ||
8 | * Copyright (c) 2006 Arnaldo Carvalho de Melo <acme@conectiva.com.br> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | */ | ||
24 | |||
25 | /* | ||
26 | * This implementation should follow: draft-ietf-dccp-ccid2-10.txt | ||
27 | * | ||
28 | * BUGS: | ||
29 | * - sequence number wrapping | ||
30 | * - jiffies wrapping | ||
31 | */ | ||
32 | |||
33 | #include <linux/config.h> | ||
34 | #include "../ccid.h" | ||
35 | #include "../dccp.h" | ||
36 | #include "ccid2.h" | ||
37 | |||
38 | static int ccid2_debug; | ||
39 | |||
40 | #undef CCID2_DEBUG | ||
41 | #ifdef CCID2_DEBUG | ||
42 | #define ccid2_pr_debug(format, a...) \ | ||
43 | do { if (ccid2_debug) \ | ||
44 | printk(KERN_DEBUG "%s: " format, __FUNCTION__, ##a); \ | ||
45 | } while (0) | ||
46 | #else | ||
47 | #define ccid2_pr_debug(format, a...) | ||
48 | #endif | ||
49 | |||
50 | static const int ccid2_seq_len = 128; | ||
51 | |||
52 | #ifdef CCID2_DEBUG | ||
53 | static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx) | ||
54 | { | ||
55 | int len = 0; | ||
56 | int pipe = 0; | ||
57 | struct ccid2_seq *seqp = hctx->ccid2hctx_seqh; | ||
58 | |||
59 | /* there is data in the chain */ | ||
60 | if (seqp != hctx->ccid2hctx_seqt) { | ||
61 | seqp = seqp->ccid2s_prev; | ||
62 | len++; | ||
63 | if (!seqp->ccid2s_acked) | ||
64 | pipe++; | ||
65 | |||
66 | while (seqp != hctx->ccid2hctx_seqt) { | ||
67 | struct ccid2_seq *prev = seqp->ccid2s_prev; | ||
68 | |||
69 | len++; | ||
70 | if (!prev->ccid2s_acked) | ||
71 | pipe++; | ||
72 | |||
73 | /* packets are sent sequentially */ | ||
74 | BUG_ON(seqp->ccid2s_seq <= prev->ccid2s_seq); | ||
75 | BUG_ON(seqp->ccid2s_sent < prev->ccid2s_sent); | ||
76 | BUG_ON(len > ccid2_seq_len); | ||
77 | |||
78 | seqp = prev; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | BUG_ON(pipe != hctx->ccid2hctx_pipe); | ||
83 | ccid2_pr_debug("len of chain=%d\n", len); | ||
84 | |||
85 | do { | ||
86 | seqp = seqp->ccid2s_prev; | ||
87 | len++; | ||
88 | BUG_ON(len > ccid2_seq_len); | ||
89 | } while (seqp != hctx->ccid2hctx_seqh); | ||
90 | |||
91 | BUG_ON(len != ccid2_seq_len); | ||
92 | ccid2_pr_debug("total len=%d\n", len); | ||
93 | } | ||
94 | #else | ||
95 | #define ccid2_hc_tx_check_sanity(hctx) do {} while (0) | ||
96 | #endif | ||
97 | |||
98 | static int ccid2_hc_tx_send_packet(struct sock *sk, | ||
99 | struct sk_buff *skb, int len) | ||
100 | { | ||
101 | struct ccid2_hc_tx_sock *hctx; | ||
102 | |||
103 | switch (DCCP_SKB_CB(skb)->dccpd_type) { | ||
104 | case 0: /* XXX data packets from userland come through like this */ | ||
105 | case DCCP_PKT_DATA: | ||
106 | case DCCP_PKT_DATAACK: | ||
107 | break; | ||
108 | /* No congestion control on other packets */ | ||
109 | default: | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | hctx = ccid2_hc_tx_sk(sk); | ||
114 | |||
115 | ccid2_pr_debug("pipe=%d cwnd=%d\n", hctx->ccid2hctx_pipe, | ||
116 | hctx->ccid2hctx_cwnd); | ||
117 | |||
118 | if (hctx->ccid2hctx_pipe < hctx->ccid2hctx_cwnd) { | ||
119 | /* OK we can send... make sure previous packet was sent off */ | ||
120 | if (!hctx->ccid2hctx_sendwait) { | ||
121 | hctx->ccid2hctx_sendwait = 1; | ||
122 | return 0; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | return 100; /* XXX */ | ||
127 | } | ||
128 | |||
129 | static void ccid2_change_l_ack_ratio(struct sock *sk, int val) | ||
130 | { | ||
131 | struct dccp_sock *dp = dccp_sk(sk); | ||
132 | /* | ||
133 | * XXX I don't really agree with val != 2. If cwnd is 1, ack ratio | ||
134 | * should be 1... it shouldn't be allowed to become 2. | ||
135 | * -sorbo. | ||
136 | */ | ||
137 | if (val != 2) { | ||
138 | const struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | ||
139 | int max = hctx->ccid2hctx_cwnd / 2; | ||
140 | |||
141 | /* round up */ | ||
142 | if (hctx->ccid2hctx_cwnd & 1) | ||
143 | max++; | ||
144 | |||
145 | if (val > max) | ||
146 | val = max; | ||
147 | } | ||
148 | |||
149 | ccid2_pr_debug("changing local ack ratio to %d\n", val); | ||
150 | WARN_ON(val <= 0); | ||
151 | dp->dccps_l_ack_ratio = val; | ||
152 | } | ||
153 | |||
154 | static void ccid2_change_cwnd(struct sock *sk, int val) | ||
155 | { | ||
156 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | ||
157 | |||
158 | if (val == 0) | ||
159 | val = 1; | ||
160 | |||
161 | /* XXX do we need to change ack ratio? */ | ||
162 | ccid2_pr_debug("change cwnd to %d\n", val); | ||
163 | |||
164 | BUG_ON(val < 1); | ||
165 | hctx->ccid2hctx_cwnd = val; | ||
166 | } | ||
167 | |||
168 | static void ccid2_start_rto_timer(struct sock *sk); | ||
169 | |||
170 | static void ccid2_hc_tx_rto_expire(unsigned long data) | ||
171 | { | ||
172 | struct sock *sk = (struct sock *)data; | ||
173 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | ||
174 | long s; | ||
175 | |||
176 | bh_lock_sock(sk); | ||
177 | if (sock_owned_by_user(sk)) { | ||
178 | sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer, | ||
179 | jiffies + HZ / 5); | ||
180 | goto out; | ||
181 | } | ||
182 | |||
183 | ccid2_pr_debug("RTO_EXPIRE\n"); | ||
184 | |||
185 | ccid2_hc_tx_check_sanity(hctx); | ||
186 | |||
187 | /* back-off timer */ | ||
188 | hctx->ccid2hctx_rto <<= 1; | ||
189 | |||
190 | s = hctx->ccid2hctx_rto / HZ; | ||
191 | if (s > 60) | ||
192 | hctx->ccid2hctx_rto = 60 * HZ; | ||
193 | |||
194 | ccid2_start_rto_timer(sk); | ||
195 | |||
196 | /* adjust pipe, cwnd etc */ | ||
197 | hctx->ccid2hctx_pipe = 0; | ||
198 | hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd >> 1; | ||
199 | if (hctx->ccid2hctx_ssthresh < 2) | ||
200 | hctx->ccid2hctx_ssthresh = 2; | ||
201 | ccid2_change_cwnd(sk, 1); | ||
202 | |||
203 | /* clear state about stuff we sent */ | ||
204 | hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqh; | ||
205 | hctx->ccid2hctx_ssacks = 0; | ||
206 | hctx->ccid2hctx_acks = 0; | ||
207 | hctx->ccid2hctx_sent = 0; | ||
208 | |||
209 | /* clear ack ratio state. */ | ||
210 | hctx->ccid2hctx_arsent = 0; | ||
211 | hctx->ccid2hctx_ackloss = 0; | ||
212 | hctx->ccid2hctx_rpseq = 0; | ||
213 | hctx->ccid2hctx_rpdupack = -1; | ||
214 | ccid2_change_l_ack_ratio(sk, 1); | ||
215 | ccid2_hc_tx_check_sanity(hctx); | ||
216 | out: | ||
217 | bh_unlock_sock(sk); | ||
218 | sock_put(sk); | ||
219 | } | ||
220 | |||
221 | static void ccid2_start_rto_timer(struct sock *sk) | ||
222 | { | ||
223 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | ||
224 | |||
225 | ccid2_pr_debug("setting RTO timeout=%ld\n", hctx->ccid2hctx_rto); | ||
226 | |||
227 | BUG_ON(timer_pending(&hctx->ccid2hctx_rtotimer)); | ||
228 | sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer, | ||
229 | jiffies + hctx->ccid2hctx_rto); | ||
230 | } | ||
231 | |||
232 | static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, int len) | ||
233 | { | ||
234 | struct dccp_sock *dp = dccp_sk(sk); | ||
235 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | ||
236 | u64 seq; | ||
237 | |||
238 | ccid2_hc_tx_check_sanity(hctx); | ||
239 | |||
240 | BUG_ON(!hctx->ccid2hctx_sendwait); | ||
241 | hctx->ccid2hctx_sendwait = 0; | ||
242 | hctx->ccid2hctx_pipe++; | ||
243 | BUG_ON(hctx->ccid2hctx_pipe < 0); | ||
244 | |||
245 | /* There is an issue. What if another packet is sent between | ||
246 | * packet_send() and packet_sent(). Then the sequence number would be | ||
247 | * wrong. | ||
248 | * -sorbo. | ||
249 | */ | ||
250 | seq = dp->dccps_gss; | ||
251 | |||
252 | hctx->ccid2hctx_seqh->ccid2s_seq = seq; | ||
253 | hctx->ccid2hctx_seqh->ccid2s_acked = 0; | ||
254 | hctx->ccid2hctx_seqh->ccid2s_sent = jiffies; | ||
255 | hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqh->ccid2s_next; | ||
256 | |||
257 | ccid2_pr_debug("cwnd=%d pipe=%d\n", hctx->ccid2hctx_cwnd, | ||
258 | hctx->ccid2hctx_pipe); | ||
259 | |||
260 | if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt) { | ||
261 | /* XXX allocate more space */ | ||
262 | WARN_ON(1); | ||
263 | } | ||
264 | |||
265 | hctx->ccid2hctx_sent++; | ||
266 | |||
267 | /* Ack Ratio. Need to maintain a concept of how many windows we sent */ | ||
268 | hctx->ccid2hctx_arsent++; | ||
269 | /* We had an ack loss in this window... */ | ||
270 | if (hctx->ccid2hctx_ackloss) { | ||
271 | if (hctx->ccid2hctx_arsent >= hctx->ccid2hctx_cwnd) { | ||
272 | hctx->ccid2hctx_arsent = 0; | ||
273 | hctx->ccid2hctx_ackloss = 0; | ||
274 | } | ||
275 | } else { | ||
276 | /* No acks lost up to now... */ | ||
277 | /* decrease ack ratio if enough packets were sent */ | ||
278 | if (dp->dccps_l_ack_ratio > 1) { | ||
279 | /* XXX don't calculate denominator each time */ | ||
280 | int denom = dp->dccps_l_ack_ratio * dp->dccps_l_ack_ratio - | ||
281 | dp->dccps_l_ack_ratio; | ||
282 | |||
283 | denom = hctx->ccid2hctx_cwnd * hctx->ccid2hctx_cwnd / denom; | ||
284 | |||
285 | if (hctx->ccid2hctx_arsent >= denom) { | ||
286 | ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio - 1); | ||
287 | hctx->ccid2hctx_arsent = 0; | ||
288 | } | ||
289 | } else { | ||
290 | /* we can't increase ack ratio further [1] */ | ||
291 | hctx->ccid2hctx_arsent = 0; /* or maybe set it to cwnd*/ | ||
292 | } | ||
293 | } | ||
294 | |||
295 | /* setup RTO timer */ | ||
296 | if (!timer_pending(&hctx->ccid2hctx_rtotimer)) | ||
297 | ccid2_start_rto_timer(sk); | ||
298 | |||
299 | #ifdef CCID2_DEBUG | ||
300 | ccid2_pr_debug("pipe=%d\n", hctx->ccid2hctx_pipe); | ||
301 | ccid2_pr_debug("Sent: seq=%llu\n", seq); | ||
302 | do { | ||
303 | struct ccid2_seq *seqp = hctx->ccid2hctx_seqt; | ||
304 | |||
305 | while (seqp != hctx->ccid2hctx_seqh) { | ||
306 | ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n", | ||
307 | seqp->ccid2s_seq, seqp->ccid2s_acked, | ||
308 | seqp->ccid2s_sent); | ||
309 | seqp = seqp->ccid2s_next; | ||
310 | } | ||
311 | } while (0); | ||
312 | ccid2_pr_debug("=========\n"); | ||
313 | ccid2_hc_tx_check_sanity(hctx); | ||
314 | #endif | ||
315 | } | ||
316 | |||
317 | /* XXX Lame code duplication! | ||
318 | * returns -1 if none was found. | ||
319 | * else returns the next offset to use in the function call. | ||
320 | */ | ||
321 | static int ccid2_ackvector(struct sock *sk, struct sk_buff *skb, int offset, | ||
322 | unsigned char **vec, unsigned char *veclen) | ||
323 | { | ||
324 | const struct dccp_hdr *dh = dccp_hdr(skb); | ||
325 | unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); | ||
326 | unsigned char *opt_ptr; | ||
327 | const unsigned char *opt_end = (unsigned char *)dh + | ||
328 | (dh->dccph_doff * 4); | ||
329 | unsigned char opt, len; | ||
330 | unsigned char *value; | ||
331 | |||
332 | BUG_ON(offset < 0); | ||
333 | options += offset; | ||
334 | opt_ptr = options; | ||
335 | if (opt_ptr >= opt_end) | ||
336 | return -1; | ||
337 | |||
338 | while (opt_ptr != opt_end) { | ||
339 | opt = *opt_ptr++; | ||
340 | len = 0; | ||
341 | value = NULL; | ||
342 | |||
343 | /* Check if this isn't a single byte option */ | ||
344 | if (opt > DCCPO_MAX_RESERVED) { | ||
345 | if (opt_ptr == opt_end) | ||
346 | goto out_invalid_option; | ||
347 | |||
348 | len = *opt_ptr++; | ||
349 | if (len < 3) | ||
350 | goto out_invalid_option; | ||
351 | /* | ||
352 | * Remove the type and len fields, leaving | ||
353 | * just the value size | ||
354 | */ | ||
355 | len -= 2; | ||
356 | value = opt_ptr; | ||
357 | opt_ptr += len; | ||
358 | |||
359 | if (opt_ptr > opt_end) | ||
360 | goto out_invalid_option; | ||
361 | } | ||
362 | |||
363 | switch (opt) { | ||
364 | case DCCPO_ACK_VECTOR_0: | ||
365 | case DCCPO_ACK_VECTOR_1: | ||
366 | *vec = value; | ||
367 | *veclen = len; | ||
368 | return offset + (opt_ptr - options); | ||
369 | } | ||
370 | } | ||
371 | |||
372 | return -1; | ||
373 | |||
374 | out_invalid_option: | ||
375 | BUG_ON(1); /* should never happen... options were previously parsed ! */ | ||
376 | return -1; | ||
377 | } | ||
378 | |||
379 | static void ccid2_hc_tx_kill_rto_timer(struct sock *sk) | ||
380 | { | ||
381 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | ||
382 | |||
383 | sk_stop_timer(sk, &hctx->ccid2hctx_rtotimer); | ||
384 | ccid2_pr_debug("deleted RTO timer\n"); | ||
385 | } | ||
386 | |||
387 | static inline void ccid2_new_ack(struct sock *sk, | ||
388 | struct ccid2_seq *seqp, | ||
389 | unsigned int *maxincr) | ||
390 | { | ||
391 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | ||
392 | |||
393 | /* slow start */ | ||
394 | if (hctx->ccid2hctx_cwnd < hctx->ccid2hctx_ssthresh) { | ||
395 | hctx->ccid2hctx_acks = 0; | ||
396 | |||
397 | /* We can increase cwnd at most maxincr [ack_ratio/2] */ | ||
398 | if (*maxincr) { | ||
399 | /* increase every 2 acks */ | ||
400 | hctx->ccid2hctx_ssacks++; | ||
401 | if (hctx->ccid2hctx_ssacks == 2) { | ||
402 | ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1); | ||
403 | hctx->ccid2hctx_ssacks = 0; | ||
404 | *maxincr = *maxincr - 1; | ||
405 | } | ||
406 | } else { | ||
407 | /* increased cwnd enough for this single ack */ | ||
408 | hctx->ccid2hctx_ssacks = 0; | ||
409 | } | ||
410 | } else { | ||
411 | hctx->ccid2hctx_ssacks = 0; | ||
412 | hctx->ccid2hctx_acks++; | ||
413 | |||
414 | if (hctx->ccid2hctx_acks >= hctx->ccid2hctx_cwnd) { | ||
415 | ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1); | ||
416 | hctx->ccid2hctx_acks = 0; | ||
417 | } | ||
418 | } | ||
419 | |||
420 | /* update RTO */ | ||
421 | if (hctx->ccid2hctx_srtt == -1 || | ||
422 | (jiffies - hctx->ccid2hctx_lastrtt) >= hctx->ccid2hctx_srtt) { | ||
423 | unsigned long r = jiffies - seqp->ccid2s_sent; | ||
424 | int s; | ||
425 | |||
426 | /* first measurement */ | ||
427 | if (hctx->ccid2hctx_srtt == -1) { | ||
428 | ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n", | ||
429 | r, jiffies, seqp->ccid2s_seq); | ||
430 | hctx->ccid2hctx_srtt = r; | ||
431 | hctx->ccid2hctx_rttvar = r >> 1; | ||
432 | } else { | ||
433 | /* RTTVAR */ | ||
434 | long tmp = hctx->ccid2hctx_srtt - r; | ||
435 | if (tmp < 0) | ||
436 | tmp *= -1; | ||
437 | |||
438 | tmp >>= 2; | ||
439 | hctx->ccid2hctx_rttvar *= 3; | ||
440 | hctx->ccid2hctx_rttvar >>= 2; | ||
441 | hctx->ccid2hctx_rttvar += tmp; | ||
442 | |||
443 | /* SRTT */ | ||
444 | hctx->ccid2hctx_srtt *= 7; | ||
445 | hctx->ccid2hctx_srtt >>= 3; | ||
446 | tmp = r >> 3; | ||
447 | hctx->ccid2hctx_srtt += tmp; | ||
448 | } | ||
449 | s = hctx->ccid2hctx_rttvar << 2; | ||
450 | /* clock granularity is 1 when based on jiffies */ | ||
451 | if (!s) | ||
452 | s = 1; | ||
453 | hctx->ccid2hctx_rto = hctx->ccid2hctx_srtt + s; | ||
454 | |||
455 | /* must be at least a second */ | ||
456 | s = hctx->ccid2hctx_rto / HZ; | ||
457 | /* DCCP doesn't require this [but I like it cuz my code sux] */ | ||
458 | #if 1 | ||
459 | if (s < 1) | ||
460 | hctx->ccid2hctx_rto = HZ; | ||
461 | #endif | ||
462 | /* max 60 seconds */ | ||
463 | if (s > 60) | ||
464 | hctx->ccid2hctx_rto = HZ * 60; | ||
465 | |||
466 | hctx->ccid2hctx_lastrtt = jiffies; | ||
467 | |||
468 | ccid2_pr_debug("srtt: %ld rttvar: %ld rto: %ld (HZ=%d) R=%lu\n", | ||
469 | hctx->ccid2hctx_srtt, hctx->ccid2hctx_rttvar, | ||
470 | hctx->ccid2hctx_rto, HZ, r); | ||
471 | hctx->ccid2hctx_sent = 0; | ||
472 | } | ||
473 | |||
474 | /* we got a new ack, so re-start RTO timer */ | ||
475 | ccid2_hc_tx_kill_rto_timer(sk); | ||
476 | ccid2_start_rto_timer(sk); | ||
477 | } | ||
478 | |||
479 | static void ccid2_hc_tx_dec_pipe(struct sock *sk) | ||
480 | { | ||
481 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | ||
482 | |||
483 | hctx->ccid2hctx_pipe--; | ||
484 | BUG_ON(hctx->ccid2hctx_pipe < 0); | ||
485 | |||
486 | if (hctx->ccid2hctx_pipe == 0) | ||
487 | ccid2_hc_tx_kill_rto_timer(sk); | ||
488 | } | ||
489 | |||
490 | static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | ||
491 | { | ||
492 | struct dccp_sock *dp = dccp_sk(sk); | ||
493 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | ||
494 | u64 ackno, seqno; | ||
495 | struct ccid2_seq *seqp; | ||
496 | unsigned char *vector; | ||
497 | unsigned char veclen; | ||
498 | int offset = 0; | ||
499 | int done = 0; | ||
500 | int loss = 0; | ||
501 | unsigned int maxincr = 0; | ||
502 | |||
503 | ccid2_hc_tx_check_sanity(hctx); | ||
504 | /* check reverse path congestion */ | ||
505 | seqno = DCCP_SKB_CB(skb)->dccpd_seq; | ||
506 | |||
507 | /* XXX this whole "algorithm" is broken. Need to fix it to keep track | ||
508 | * of the seqnos of the dupacks so that rpseq and rpdupack are correct | ||
509 | * -sorbo. | ||
510 | */ | ||
511 | /* need to bootstrap */ | ||
512 | if (hctx->ccid2hctx_rpdupack == -1) { | ||
513 | hctx->ccid2hctx_rpdupack = 0; | ||
514 | hctx->ccid2hctx_rpseq = seqno; | ||
515 | } else { | ||
516 | /* check if packet is consecutive */ | ||
517 | if ((hctx->ccid2hctx_rpseq + 1) == seqno) | ||
518 | hctx->ccid2hctx_rpseq++; | ||
519 | /* it's a later packet */ | ||
520 | else if (after48(seqno, hctx->ccid2hctx_rpseq)) { | ||
521 | hctx->ccid2hctx_rpdupack++; | ||
522 | |||
523 | /* check if we got enough dupacks */ | ||
524 | if (hctx->ccid2hctx_rpdupack >= | ||
525 | hctx->ccid2hctx_numdupack) { | ||
526 | hctx->ccid2hctx_rpdupack = -1; /* XXX lame */ | ||
527 | hctx->ccid2hctx_rpseq = 0; | ||
528 | |||
529 | ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio << 1); | ||
530 | } | ||
531 | } | ||
532 | } | ||
533 | |||
534 | /* check forward path congestion */ | ||
535 | /* still didn't send out new data packets */ | ||
536 | if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt) | ||
537 | return; | ||
538 | |||
539 | switch (DCCP_SKB_CB(skb)->dccpd_type) { | ||
540 | case DCCP_PKT_ACK: | ||
541 | case DCCP_PKT_DATAACK: | ||
542 | break; | ||
543 | default: | ||
544 | return; | ||
545 | } | ||
546 | |||
547 | ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq; | ||
548 | seqp = hctx->ccid2hctx_seqh->ccid2s_prev; | ||
549 | |||
550 | /* If in slow-start, cwnd can increase at most Ack Ratio / 2 packets for | ||
551 | * this single ack. I round up. | ||
552 | * -sorbo. | ||
553 | */ | ||
554 | maxincr = dp->dccps_l_ack_ratio >> 1; | ||
555 | maxincr++; | ||
556 | |||
557 | /* go through all ack vectors */ | ||
558 | while ((offset = ccid2_ackvector(sk, skb, offset, | ||
559 | &vector, &veclen)) != -1) { | ||
560 | /* go through this ack vector */ | ||
561 | while (veclen--) { | ||
562 | const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK; | ||
563 | u64 ackno_end_rl; | ||
564 | |||
565 | dccp_set_seqno(&ackno_end_rl, ackno - rl); | ||
566 | ccid2_pr_debug("ackvec start:%llu end:%llu\n", ackno, | ||
567 | ackno_end_rl); | ||
568 | /* if the seqno we are analyzing is larger than the | ||
569 | * current ackno, then move towards the tail of our | ||
570 | * seqnos. | ||
571 | */ | ||
572 | while (after48(seqp->ccid2s_seq, ackno)) { | ||
573 | if (seqp == hctx->ccid2hctx_seqt) { | ||
574 | done = 1; | ||
575 | break; | ||
576 | } | ||
577 | seqp = seqp->ccid2s_prev; | ||
578 | } | ||
579 | if (done) | ||
580 | break; | ||
581 | |||
582 | /* check all seqnos in the range of the vector | ||
583 | * run length | ||
584 | */ | ||
585 | while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) { | ||
586 | const u8 state = (*vector & | ||
587 | DCCP_ACKVEC_STATE_MASK) >> 6; | ||
588 | |||
589 | /* new packet received or marked */ | ||
590 | if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED && | ||
591 | !seqp->ccid2s_acked) { | ||
592 | if (state == | ||
593 | DCCP_ACKVEC_STATE_ECN_MARKED) { | ||
594 | loss = 1; | ||
595 | } else | ||
596 | ccid2_new_ack(sk, seqp, | ||
597 | &maxincr); | ||
598 | |||
599 | seqp->ccid2s_acked = 1; | ||
600 | ccid2_pr_debug("Got ack for %llu\n", | ||
601 | seqp->ccid2s_seq); | ||
602 | ccid2_hc_tx_dec_pipe(sk); | ||
603 | } | ||
604 | if (seqp == hctx->ccid2hctx_seqt) { | ||
605 | done = 1; | ||
606 | break; | ||
607 | } | ||
608 | seqp = seqp->ccid2s_next; | ||
609 | } | ||
610 | if (done) | ||
611 | break; | ||
612 | |||
613 | |||
614 | dccp_set_seqno(&ackno, ackno_end_rl - 1); | ||
615 | vector++; | ||
616 | } | ||
617 | if (done) | ||
618 | break; | ||
619 | } | ||
620 | |||
621 | /* The state about what is acked should be correct now | ||
622 | * Check for NUMDUPACK | ||
623 | */ | ||
624 | seqp = hctx->ccid2hctx_seqh->ccid2s_prev; | ||
625 | done = 0; | ||
626 | while (1) { | ||
627 | if (seqp->ccid2s_acked) { | ||
628 | done++; | ||
629 | if (done == hctx->ccid2hctx_numdupack) | ||
630 | break; | ||
631 | } | ||
632 | if (seqp == hctx->ccid2hctx_seqt) | ||
633 | break; | ||
634 | seqp = seqp->ccid2s_prev; | ||
635 | } | ||
636 | |||
637 | /* If there are at least 3 acknowledgements, anything unacknowledged | ||
638 | * below the last sequence number is considered lost | ||
639 | */ | ||
640 | if (done == hctx->ccid2hctx_numdupack) { | ||
641 | struct ccid2_seq *last_acked = seqp; | ||
642 | |||
643 | /* check for lost packets */ | ||
644 | while (1) { | ||
645 | if (!seqp->ccid2s_acked) { | ||
646 | loss = 1; | ||
647 | ccid2_hc_tx_dec_pipe(sk); | ||
648 | } | ||
649 | if (seqp == hctx->ccid2hctx_seqt) | ||
650 | break; | ||
651 | seqp = seqp->ccid2s_prev; | ||
652 | } | ||
653 | |||
654 | hctx->ccid2hctx_seqt = last_acked; | ||
655 | } | ||
656 | |||
657 | /* trim acked packets in tail */ | ||
658 | while (hctx->ccid2hctx_seqt != hctx->ccid2hctx_seqh) { | ||
659 | if (!hctx->ccid2hctx_seqt->ccid2s_acked) | ||
660 | break; | ||
661 | |||
662 | hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqt->ccid2s_next; | ||
663 | } | ||
664 | |||
665 | if (loss) { | ||
666 | /* XXX do bit shifts guarantee a 0 as the new bit? */ | ||
667 | ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd >> 1); | ||
668 | hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd; | ||
669 | if (hctx->ccid2hctx_ssthresh < 2) | ||
670 | hctx->ccid2hctx_ssthresh = 2; | ||
671 | } | ||
672 | |||
673 | ccid2_hc_tx_check_sanity(hctx); | ||
674 | } | ||
675 | |||
676 | static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) | ||
677 | { | ||
678 | struct ccid2_hc_tx_sock *hctx = ccid_priv(ccid); | ||
679 | int seqcount = ccid2_seq_len; | ||
680 | int i; | ||
681 | |||
682 | /* XXX init variables with proper values */ | ||
683 | hctx->ccid2hctx_cwnd = 1; | ||
684 | hctx->ccid2hctx_ssthresh = 10; | ||
685 | hctx->ccid2hctx_numdupack = 3; | ||
686 | |||
687 | /* XXX init ~ to window size... */ | ||
688 | hctx->ccid2hctx_seqbuf = kmalloc(sizeof(*hctx->ccid2hctx_seqbuf) * | ||
689 | seqcount, gfp_any()); | ||
690 | if (hctx->ccid2hctx_seqbuf == NULL) | ||
691 | return -ENOMEM; | ||
692 | |||
693 | for (i = 0; i < (seqcount - 1); i++) { | ||
694 | hctx->ccid2hctx_seqbuf[i].ccid2s_next = | ||
695 | &hctx->ccid2hctx_seqbuf[i + 1]; | ||
696 | hctx->ccid2hctx_seqbuf[i + 1].ccid2s_prev = | ||
697 | &hctx->ccid2hctx_seqbuf[i]; | ||
698 | } | ||
699 | hctx->ccid2hctx_seqbuf[seqcount - 1].ccid2s_next = | ||
700 | hctx->ccid2hctx_seqbuf; | ||
701 | hctx->ccid2hctx_seqbuf->ccid2s_prev = | ||
702 | &hctx->ccid2hctx_seqbuf[seqcount - 1]; | ||
703 | |||
704 | hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqbuf; | ||
705 | hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqh; | ||
706 | hctx->ccid2hctx_sent = 0; | ||
707 | hctx->ccid2hctx_rto = 3 * HZ; | ||
708 | hctx->ccid2hctx_srtt = -1; | ||
709 | hctx->ccid2hctx_rttvar = -1; | ||
710 | hctx->ccid2hctx_lastrtt = 0; | ||
711 | hctx->ccid2hctx_rpdupack = -1; | ||
712 | |||
713 | hctx->ccid2hctx_rtotimer.function = &ccid2_hc_tx_rto_expire; | ||
714 | hctx->ccid2hctx_rtotimer.data = (unsigned long)sk; | ||
715 | init_timer(&hctx->ccid2hctx_rtotimer); | ||
716 | |||
717 | ccid2_hc_tx_check_sanity(hctx); | ||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | static void ccid2_hc_tx_exit(struct sock *sk) | ||
722 | { | ||
723 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | ||
724 | |||
725 | ccid2_hc_tx_kill_rto_timer(sk); | ||
726 | kfree(hctx->ccid2hctx_seqbuf); | ||
727 | hctx->ccid2hctx_seqbuf = NULL; | ||
728 | } | ||
729 | |||
730 | static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) | ||
731 | { | ||
732 | const struct dccp_sock *dp = dccp_sk(sk); | ||
733 | struct ccid2_hc_rx_sock *hcrx = ccid2_hc_rx_sk(sk); | ||
734 | |||
735 | switch (DCCP_SKB_CB(skb)->dccpd_type) { | ||
736 | case DCCP_PKT_DATA: | ||
737 | case DCCP_PKT_DATAACK: | ||
738 | hcrx->ccid2hcrx_data++; | ||
739 | if (hcrx->ccid2hcrx_data >= dp->dccps_r_ack_ratio) { | ||
740 | dccp_send_ack(sk); | ||
741 | hcrx->ccid2hcrx_data = 0; | ||
742 | } | ||
743 | break; | ||
744 | } | ||
745 | } | ||
746 | |||
747 | static struct ccid_operations ccid2 = { | ||
748 | .ccid_id = 2, | ||
749 | .ccid_name = "ccid2", | ||
750 | .ccid_owner = THIS_MODULE, | ||
751 | .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock), | ||
752 | .ccid_hc_tx_init = ccid2_hc_tx_init, | ||
753 | .ccid_hc_tx_exit = ccid2_hc_tx_exit, | ||
754 | .ccid_hc_tx_send_packet = ccid2_hc_tx_send_packet, | ||
755 | .ccid_hc_tx_packet_sent = ccid2_hc_tx_packet_sent, | ||
756 | .ccid_hc_tx_packet_recv = ccid2_hc_tx_packet_recv, | ||
757 | .ccid_hc_rx_obj_size = sizeof(struct ccid2_hc_rx_sock), | ||
758 | .ccid_hc_rx_packet_recv = ccid2_hc_rx_packet_recv, | ||
759 | }; | ||
760 | |||
761 | module_param(ccid2_debug, int, 0444); | ||
762 | MODULE_PARM_DESC(ccid2_debug, "Enable debug messages"); | ||
763 | |||
764 | static __init int ccid2_module_init(void) | ||
765 | { | ||
766 | return ccid_register(&ccid2); | ||
767 | } | ||
768 | module_init(ccid2_module_init); | ||
769 | |||
770 | static __exit void ccid2_module_exit(void) | ||
771 | { | ||
772 | ccid_unregister(&ccid2); | ||
773 | } | ||
774 | module_exit(ccid2_module_exit); | ||
775 | |||
776 | MODULE_AUTHOR("Andrea Bittau <a.bittau@cs.ucl.ac.uk>"); | ||
777 | MODULE_DESCRIPTION("DCCP TCP-Like (CCID2) CCID"); | ||
778 | MODULE_LICENSE("GPL"); | ||
779 | MODULE_ALIAS("net-dccp-ccid-2"); | ||
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h new file mode 100644 index 000000000000..451a87464fa5 --- /dev/null +++ b/net/dccp/ccids/ccid2.h | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * net/dccp/ccids/ccid2.h | ||
3 | * | ||
4 | * Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | #ifndef _DCCP_CCID2_H_ | ||
21 | #define _DCCP_CCID2_H_ | ||
22 | |||
23 | #include <linux/dccp.h> | ||
24 | #include <linux/timer.h> | ||
25 | #include <linux/types.h> | ||
26 | #include "../ccid.h" | ||
27 | |||
28 | struct sock; | ||
29 | |||
30 | struct ccid2_seq { | ||
31 | u64 ccid2s_seq; | ||
32 | unsigned long ccid2s_sent; | ||
33 | int ccid2s_acked; | ||
34 | struct ccid2_seq *ccid2s_prev; | ||
35 | struct ccid2_seq *ccid2s_next; | ||
36 | }; | ||
37 | |||
38 | /** struct ccid2_hc_tx_sock - CCID2 TX half connection | ||
39 | * | ||
40 | * @ccid2hctx_ssacks - ACKs recv in slow start | ||
41 | * @ccid2hctx_acks - ACKS recv in AI phase | ||
42 | * @ccid2hctx_sent - packets sent in this window | ||
43 | * @ccid2hctx_lastrtt -time RTT was last measured | ||
44 | * @ccid2hctx_arsent - packets sent [ack ratio] | ||
45 | * @ccid2hctx_ackloss - ack was lost in this win | ||
46 | * @ccid2hctx_rpseq - last consecutive seqno | ||
47 | * @ccid2hctx_rpdupack - dupacks since rpseq | ||
48 | */ | ||
49 | struct ccid2_hc_tx_sock { | ||
50 | int ccid2hctx_cwnd; | ||
51 | int ccid2hctx_ssacks; | ||
52 | int ccid2hctx_acks; | ||
53 | int ccid2hctx_ssthresh; | ||
54 | int ccid2hctx_pipe; | ||
55 | int ccid2hctx_numdupack; | ||
56 | struct ccid2_seq *ccid2hctx_seqbuf; | ||
57 | struct ccid2_seq *ccid2hctx_seqh; | ||
58 | struct ccid2_seq *ccid2hctx_seqt; | ||
59 | long ccid2hctx_rto; | ||
60 | long ccid2hctx_srtt; | ||
61 | long ccid2hctx_rttvar; | ||
62 | int ccid2hctx_sent; | ||
63 | unsigned long ccid2hctx_lastrtt; | ||
64 | struct timer_list ccid2hctx_rtotimer; | ||
65 | unsigned long ccid2hctx_arsent; | ||
66 | int ccid2hctx_ackloss; | ||
67 | u64 ccid2hctx_rpseq; | ||
68 | int ccid2hctx_rpdupack; | ||
69 | int ccid2hctx_sendwait; | ||
70 | }; | ||
71 | |||
72 | struct ccid2_hc_rx_sock { | ||
73 | int ccid2hcrx_data; | ||
74 | }; | ||
75 | |||
76 | static inline struct ccid2_hc_tx_sock *ccid2_hc_tx_sk(const struct sock *sk) | ||
77 | { | ||
78 | return ccid_priv(dccp_sk(sk)->dccps_hc_tx_ccid); | ||
79 | } | ||
80 | |||
81 | static inline struct ccid2_hc_rx_sock *ccid2_hc_rx_sk(const struct sock *sk) | ||
82 | { | ||
83 | return ccid_priv(dccp_sk(sk)->dccps_hc_rx_ccid); | ||
84 | } | ||
85 | #endif /* _DCCP_CCID2_H_ */ | ||
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 35d1d347541c..b4a51d0355a5 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c | |||
@@ -46,7 +46,7 @@ | |||
46 | * Reason for maths here is to avoid 32 bit overflow when a is big. | 46 | * Reason for maths here is to avoid 32 bit overflow when a is big. |
47 | * With this we get close to the limit. | 47 | * With this we get close to the limit. |
48 | */ | 48 | */ |
49 | static inline u32 usecs_div(const u32 a, const u32 b) | 49 | static u32 usecs_div(const u32 a, const u32 b) |
50 | { | 50 | { |
51 | const u32 div = a < (UINT_MAX / (USEC_PER_SEC / 10)) ? 10 : | 51 | const u32 div = a < (UINT_MAX / (USEC_PER_SEC / 10)) ? 10 : |
52 | a < (UINT_MAX / (USEC_PER_SEC / 50)) ? 50 : | 52 | a < (UINT_MAX / (USEC_PER_SEC / 50)) ? 50 : |
@@ -76,15 +76,6 @@ static struct dccp_tx_hist *ccid3_tx_hist; | |||
76 | static struct dccp_rx_hist *ccid3_rx_hist; | 76 | static struct dccp_rx_hist *ccid3_rx_hist; |
77 | static struct dccp_li_hist *ccid3_li_hist; | 77 | static struct dccp_li_hist *ccid3_li_hist; |
78 | 78 | ||
79 | static int ccid3_init(struct sock *sk) | ||
80 | { | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static void ccid3_exit(struct sock *sk) | ||
85 | { | ||
86 | } | ||
87 | |||
88 | /* TFRC sender states */ | 79 | /* TFRC sender states */ |
89 | enum ccid3_hc_tx_states { | 80 | enum ccid3_hc_tx_states { |
90 | TFRC_SSTATE_NO_SENT = 1, | 81 | TFRC_SSTATE_NO_SENT = 1, |
@@ -107,8 +98,8 @@ static const char *ccid3_tx_state_name(enum ccid3_hc_tx_states state) | |||
107 | } | 98 | } |
108 | #endif | 99 | #endif |
109 | 100 | ||
110 | static inline void ccid3_hc_tx_set_state(struct sock *sk, | 101 | static void ccid3_hc_tx_set_state(struct sock *sk, |
111 | enum ccid3_hc_tx_states state) | 102 | enum ccid3_hc_tx_states state) |
112 | { | 103 | { |
113 | struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); | 104 | struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); |
114 | enum ccid3_hc_tx_states oldstate = hctx->ccid3hctx_state; | 105 | enum ccid3_hc_tx_states oldstate = hctx->ccid3hctx_state; |
@@ -316,8 +307,6 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, | |||
316 | 307 | ||
317 | switch (hctx->ccid3hctx_state) { | 308 | switch (hctx->ccid3hctx_state) { |
318 | case TFRC_SSTATE_NO_SENT: | 309 | case TFRC_SSTATE_NO_SENT: |
319 | hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer; | ||
320 | hctx->ccid3hctx_no_feedback_timer.data = (unsigned long)sk; | ||
321 | sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, | 310 | sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, |
322 | jiffies + usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)); | 311 | jiffies + usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)); |
323 | hctx->ccid3hctx_last_win_count = 0; | 312 | hctx->ccid3hctx_last_win_count = 0; |
@@ -585,16 +574,15 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
585 | } | 574 | } |
586 | } | 575 | } |
587 | 576 | ||
588 | static void ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb) | 577 | static int ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb) |
589 | { | 578 | { |
590 | const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); | 579 | const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); |
591 | 580 | ||
592 | BUG_ON(hctx == NULL); | 581 | BUG_ON(hctx == NULL); |
593 | 582 | ||
594 | if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN)) | 583 | if (sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN) |
595 | return; | 584 | DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count; |
596 | 585 | return 0; | |
597 | DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count; | ||
598 | } | 586 | } |
599 | 587 | ||
600 | static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option, | 588 | static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option, |
@@ -626,7 +614,7 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option, | |||
626 | __FUNCTION__, dccp_role(sk), sk); | 614 | __FUNCTION__, dccp_role(sk), sk); |
627 | rc = -EINVAL; | 615 | rc = -EINVAL; |
628 | } else { | 616 | } else { |
629 | opt_recv->ccid3or_loss_event_rate = ntohl(*(u32 *)value); | 617 | opt_recv->ccid3or_loss_event_rate = ntohl(*(__be32 *)value); |
630 | ccid3_pr_debug("%s, sk=%p, LOSS_EVENT_RATE=%u\n", | 618 | ccid3_pr_debug("%s, sk=%p, LOSS_EVENT_RATE=%u\n", |
631 | dccp_role(sk), sk, | 619 | dccp_role(sk), sk, |
632 | opt_recv->ccid3or_loss_event_rate); | 620 | opt_recv->ccid3or_loss_event_rate); |
@@ -647,7 +635,7 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option, | |||
647 | __FUNCTION__, dccp_role(sk), sk); | 635 | __FUNCTION__, dccp_role(sk), sk); |
648 | rc = -EINVAL; | 636 | rc = -EINVAL; |
649 | } else { | 637 | } else { |
650 | opt_recv->ccid3or_receive_rate = ntohl(*(u32 *)value); | 638 | opt_recv->ccid3or_receive_rate = ntohl(*(__be32 *)value); |
651 | ccid3_pr_debug("%s, sk=%p, RECEIVE_RATE=%u\n", | 639 | ccid3_pr_debug("%s, sk=%p, RECEIVE_RATE=%u\n", |
652 | dccp_role(sk), sk, | 640 | dccp_role(sk), sk, |
653 | opt_recv->ccid3or_receive_rate); | 641 | opt_recv->ccid3or_receive_rate); |
@@ -658,17 +646,10 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option, | |||
658 | return rc; | 646 | return rc; |
659 | } | 647 | } |
660 | 648 | ||
661 | static int ccid3_hc_tx_init(struct sock *sk) | 649 | static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk) |
662 | { | 650 | { |
663 | struct dccp_sock *dp = dccp_sk(sk); | 651 | struct dccp_sock *dp = dccp_sk(sk); |
664 | struct ccid3_hc_tx_sock *hctx; | 652 | struct ccid3_hc_tx_sock *hctx = ccid_priv(ccid); |
665 | |||
666 | dp->dccps_hc_tx_ccid_private = kmalloc(sizeof(*hctx), gfp_any()); | ||
667 | if (dp->dccps_hc_tx_ccid_private == NULL) | ||
668 | return -ENOMEM; | ||
669 | |||
670 | hctx = ccid3_hc_tx_sk(sk); | ||
671 | memset(hctx, 0, sizeof(*hctx)); | ||
672 | 653 | ||
673 | if (dp->dccps_packet_size >= TFRC_MIN_PACKET_SIZE && | 654 | if (dp->dccps_packet_size >= TFRC_MIN_PACKET_SIZE && |
674 | dp->dccps_packet_size <= TFRC_MAX_PACKET_SIZE) | 655 | dp->dccps_packet_size <= TFRC_MAX_PACKET_SIZE) |
@@ -681,6 +662,9 @@ static int ccid3_hc_tx_init(struct sock *sk) | |||
681 | hctx->ccid3hctx_t_rto = USEC_PER_SEC; | 662 | hctx->ccid3hctx_t_rto = USEC_PER_SEC; |
682 | hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT; | 663 | hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT; |
683 | INIT_LIST_HEAD(&hctx->ccid3hctx_hist); | 664 | INIT_LIST_HEAD(&hctx->ccid3hctx_hist); |
665 | |||
666 | hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer; | ||
667 | hctx->ccid3hctx_no_feedback_timer.data = (unsigned long)sk; | ||
684 | init_timer(&hctx->ccid3hctx_no_feedback_timer); | 668 | init_timer(&hctx->ccid3hctx_no_feedback_timer); |
685 | 669 | ||
686 | return 0; | 670 | return 0; |
@@ -688,7 +672,6 @@ static int ccid3_hc_tx_init(struct sock *sk) | |||
688 | 672 | ||
689 | static void ccid3_hc_tx_exit(struct sock *sk) | 673 | static void ccid3_hc_tx_exit(struct sock *sk) |
690 | { | 674 | { |
691 | struct dccp_sock *dp = dccp_sk(sk); | ||
692 | struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); | 675 | struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); |
693 | 676 | ||
694 | BUG_ON(hctx == NULL); | 677 | BUG_ON(hctx == NULL); |
@@ -698,9 +681,6 @@ static void ccid3_hc_tx_exit(struct sock *sk) | |||
698 | 681 | ||
699 | /* Empty packet history */ | 682 | /* Empty packet history */ |
700 | dccp_tx_hist_purge(ccid3_tx_hist, &hctx->ccid3hctx_hist); | 683 | dccp_tx_hist_purge(ccid3_tx_hist, &hctx->ccid3hctx_hist); |
701 | |||
702 | kfree(dp->dccps_hc_tx_ccid_private); | ||
703 | dp->dccps_hc_tx_ccid_private = NULL; | ||
704 | } | 684 | } |
705 | 685 | ||
706 | /* | 686 | /* |
@@ -727,8 +707,8 @@ static const char *ccid3_rx_state_name(enum ccid3_hc_rx_states state) | |||
727 | } | 707 | } |
728 | #endif | 708 | #endif |
729 | 709 | ||
730 | static inline void ccid3_hc_rx_set_state(struct sock *sk, | 710 | static void ccid3_hc_rx_set_state(struct sock *sk, |
731 | enum ccid3_hc_rx_states state) | 711 | enum ccid3_hc_rx_states state) |
732 | { | 712 | { |
733 | struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); | 713 | struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); |
734 | enum ccid3_hc_rx_states oldstate = hcrx->ccid3hcrx_state; | 714 | enum ccid3_hc_rx_states oldstate = hcrx->ccid3hcrx_state; |
@@ -793,31 +773,35 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk) | |||
793 | dccp_send_ack(sk); | 773 | dccp_send_ack(sk); |
794 | } | 774 | } |
795 | 775 | ||
796 | static void ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb) | 776 | static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb) |
797 | { | 777 | { |
798 | const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); | 778 | const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); |
799 | u32 x_recv, pinv; | 779 | __be32 x_recv, pinv; |
800 | 780 | ||
801 | BUG_ON(hcrx == NULL); | 781 | BUG_ON(hcrx == NULL); |
802 | 782 | ||
803 | if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN)) | 783 | if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN)) |
804 | return; | 784 | return 0; |
805 | 785 | ||
806 | DCCP_SKB_CB(skb)->dccpd_ccval = hcrx->ccid3hcrx_last_counter; | 786 | DCCP_SKB_CB(skb)->dccpd_ccval = hcrx->ccid3hcrx_last_counter; |
807 | 787 | ||
808 | if (dccp_packet_without_ack(skb)) | 788 | if (dccp_packet_without_ack(skb)) |
809 | return; | 789 | return 0; |
810 | 790 | ||
811 | if (hcrx->ccid3hcrx_elapsed_time != 0) | ||
812 | dccp_insert_option_elapsed_time(sk, skb, | ||
813 | hcrx->ccid3hcrx_elapsed_time); | ||
814 | dccp_insert_option_timestamp(sk, skb); | ||
815 | x_recv = htonl(hcrx->ccid3hcrx_x_recv); | 791 | x_recv = htonl(hcrx->ccid3hcrx_x_recv); |
816 | pinv = htonl(hcrx->ccid3hcrx_pinv); | 792 | pinv = htonl(hcrx->ccid3hcrx_pinv); |
817 | dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE, | 793 | |
818 | &pinv, sizeof(pinv)); | 794 | if ((hcrx->ccid3hcrx_elapsed_time != 0 && |
819 | dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE, | 795 | dccp_insert_option_elapsed_time(sk, skb, |
820 | &x_recv, sizeof(x_recv)); | 796 | hcrx->ccid3hcrx_elapsed_time)) || |
797 | dccp_insert_option_timestamp(sk, skb) || | ||
798 | dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE, | ||
799 | &pinv, sizeof(pinv)) || | ||
800 | dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE, | ||
801 | &x_recv, sizeof(x_recv))) | ||
802 | return -1; | ||
803 | |||
804 | return 0; | ||
821 | } | 805 | } |
822 | 806 | ||
823 | /* calculate first loss interval | 807 | /* calculate first loss interval |
@@ -1047,20 +1031,13 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
1047 | } | 1031 | } |
1048 | } | 1032 | } |
1049 | 1033 | ||
1050 | static int ccid3_hc_rx_init(struct sock *sk) | 1034 | static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk) |
1051 | { | 1035 | { |
1052 | struct dccp_sock *dp = dccp_sk(sk); | 1036 | struct dccp_sock *dp = dccp_sk(sk); |
1053 | struct ccid3_hc_rx_sock *hcrx; | 1037 | struct ccid3_hc_rx_sock *hcrx = ccid_priv(ccid); |
1054 | 1038 | ||
1055 | ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk); | 1039 | ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk); |
1056 | 1040 | ||
1057 | dp->dccps_hc_rx_ccid_private = kmalloc(sizeof(*hcrx), gfp_any()); | ||
1058 | if (dp->dccps_hc_rx_ccid_private == NULL) | ||
1059 | return -ENOMEM; | ||
1060 | |||
1061 | hcrx = ccid3_hc_rx_sk(sk); | ||
1062 | memset(hcrx, 0, sizeof(*hcrx)); | ||
1063 | |||
1064 | if (dp->dccps_packet_size >= TFRC_MIN_PACKET_SIZE && | 1041 | if (dp->dccps_packet_size >= TFRC_MIN_PACKET_SIZE && |
1065 | dp->dccps_packet_size <= TFRC_MAX_PACKET_SIZE) | 1042 | dp->dccps_packet_size <= TFRC_MAX_PACKET_SIZE) |
1066 | hcrx->ccid3hcrx_s = dp->dccps_packet_size; | 1043 | hcrx->ccid3hcrx_s = dp->dccps_packet_size; |
@@ -1079,7 +1056,6 @@ static int ccid3_hc_rx_init(struct sock *sk) | |||
1079 | static void ccid3_hc_rx_exit(struct sock *sk) | 1056 | static void ccid3_hc_rx_exit(struct sock *sk) |
1080 | { | 1057 | { |
1081 | struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); | 1058 | struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); |
1082 | struct dccp_sock *dp = dccp_sk(sk); | ||
1083 | 1059 | ||
1084 | BUG_ON(hcrx == NULL); | 1060 | BUG_ON(hcrx == NULL); |
1085 | 1061 | ||
@@ -1090,9 +1066,6 @@ static void ccid3_hc_rx_exit(struct sock *sk) | |||
1090 | 1066 | ||
1091 | /* Empty loss interval history */ | 1067 | /* Empty loss interval history */ |
1092 | dccp_li_hist_purge(ccid3_li_hist, &hcrx->ccid3hcrx_li_hist); | 1068 | dccp_li_hist_purge(ccid3_li_hist, &hcrx->ccid3hcrx_li_hist); |
1093 | |||
1094 | kfree(dp->dccps_hc_rx_ccid_private); | ||
1095 | dp->dccps_hc_rx_ccid_private = NULL; | ||
1096 | } | 1069 | } |
1097 | 1070 | ||
1098 | static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info) | 1071 | static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info) |
@@ -1178,12 +1151,11 @@ static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len, | |||
1178 | return 0; | 1151 | return 0; |
1179 | } | 1152 | } |
1180 | 1153 | ||
1181 | static struct ccid ccid3 = { | 1154 | static struct ccid_operations ccid3 = { |
1182 | .ccid_id = 3, | 1155 | .ccid_id = 3, |
1183 | .ccid_name = "ccid3", | 1156 | .ccid_name = "ccid3", |
1184 | .ccid_owner = THIS_MODULE, | 1157 | .ccid_owner = THIS_MODULE, |
1185 | .ccid_init = ccid3_init, | 1158 | .ccid_hc_tx_obj_size = sizeof(struct ccid3_hc_tx_sock), |
1186 | .ccid_exit = ccid3_exit, | ||
1187 | .ccid_hc_tx_init = ccid3_hc_tx_init, | 1159 | .ccid_hc_tx_init = ccid3_hc_tx_init, |
1188 | .ccid_hc_tx_exit = ccid3_hc_tx_exit, | 1160 | .ccid_hc_tx_exit = ccid3_hc_tx_exit, |
1189 | .ccid_hc_tx_send_packet = ccid3_hc_tx_send_packet, | 1161 | .ccid_hc_tx_send_packet = ccid3_hc_tx_send_packet, |
@@ -1191,6 +1163,7 @@ static struct ccid ccid3 = { | |||
1191 | .ccid_hc_tx_packet_recv = ccid3_hc_tx_packet_recv, | 1163 | .ccid_hc_tx_packet_recv = ccid3_hc_tx_packet_recv, |
1192 | .ccid_hc_tx_insert_options = ccid3_hc_tx_insert_options, | 1164 | .ccid_hc_tx_insert_options = ccid3_hc_tx_insert_options, |
1193 | .ccid_hc_tx_parse_options = ccid3_hc_tx_parse_options, | 1165 | .ccid_hc_tx_parse_options = ccid3_hc_tx_parse_options, |
1166 | .ccid_hc_rx_obj_size = sizeof(struct ccid3_hc_rx_sock), | ||
1194 | .ccid_hc_rx_init = ccid3_hc_rx_init, | 1167 | .ccid_hc_rx_init = ccid3_hc_rx_init, |
1195 | .ccid_hc_rx_exit = ccid3_hc_rx_exit, | 1168 | .ccid_hc_rx_exit = ccid3_hc_rx_exit, |
1196 | .ccid_hc_rx_insert_options = ccid3_hc_rx_insert_options, | 1169 | .ccid_hc_rx_insert_options = ccid3_hc_rx_insert_options, |
@@ -1241,15 +1214,6 @@ module_init(ccid3_module_init); | |||
1241 | 1214 | ||
1242 | static __exit void ccid3_module_exit(void) | 1215 | static __exit void ccid3_module_exit(void) |
1243 | { | 1216 | { |
1244 | #ifdef CONFIG_IP_DCCP_UNLOAD_HACK | ||
1245 | /* | ||
1246 | * Hack to use while developing, so that we get rid of the control | ||
1247 | * sock, that is what keeps a refcount on dccp.ko -acme | ||
1248 | */ | ||
1249 | extern void dccp_ctl_sock_exit(void); | ||
1250 | |||
1251 | dccp_ctl_sock_exit(); | ||
1252 | #endif | ||
1253 | ccid_unregister(&ccid3); | 1217 | ccid_unregister(&ccid3); |
1254 | 1218 | ||
1255 | if (ccid3_tx_hist != NULL) { | 1219 | if (ccid3_tx_hist != NULL) { |
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index 0bde4583d091..f18b96d4e5a2 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/time.h> | 41 | #include <linux/time.h> |
42 | #include <linux/types.h> | 42 | #include <linux/types.h> |
43 | #include <linux/tfrc.h> | 43 | #include <linux/tfrc.h> |
44 | #include "../ccid.h" | ||
44 | 45 | ||
45 | #define TFRC_MIN_PACKET_SIZE 16 | 46 | #define TFRC_MIN_PACKET_SIZE 16 |
46 | #define TFRC_STD_PACKET_SIZE 256 | 47 | #define TFRC_STD_PACKET_SIZE 256 |
@@ -135,12 +136,12 @@ struct ccid3_hc_rx_sock { | |||
135 | 136 | ||
136 | static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk) | 137 | static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk) |
137 | { | 138 | { |
138 | return dccp_sk(sk)->dccps_hc_tx_ccid_private; | 139 | return ccid_priv(dccp_sk(sk)->dccps_hc_tx_ccid); |
139 | } | 140 | } |
140 | 141 | ||
141 | static inline struct ccid3_hc_rx_sock *ccid3_hc_rx_sk(const struct sock *sk) | 142 | static inline struct ccid3_hc_rx_sock *ccid3_hc_rx_sk(const struct sock *sk) |
142 | { | 143 | { |
143 | return dccp_sk(sk)->dccps_hc_rx_ccid_private; | 144 | return ccid_priv(dccp_sk(sk)->dccps_hc_rx_ccid); |
144 | } | 145 | } |
145 | 146 | ||
146 | #endif /* _DCCP_CCID3_H_ */ | 147 | #endif /* _DCCP_CCID3_H_ */ |
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 93f26dd6e6cb..1fe509148689 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h | |||
@@ -59,8 +59,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo); | |||
59 | 59 | ||
60 | #define DCCP_RTO_MAX ((unsigned)(120 * HZ)) /* FIXME: using TCP value */ | 60 | #define DCCP_RTO_MAX ((unsigned)(120 * HZ)) /* FIXME: using TCP value */ |
61 | 61 | ||
62 | extern struct proto dccp_prot; | ||
63 | |||
64 | /* is seq1 < seq2 ? */ | 62 | /* is seq1 < seq2 ? */ |
65 | static inline int before48(const u64 seq1, const u64 seq2) | 63 | static inline int before48(const u64 seq1, const u64 seq2) |
66 | { | 64 | { |
@@ -120,7 +118,6 @@ DECLARE_SNMP_STAT(struct dccp_mib, dccp_statistics); | |||
120 | 118 | ||
121 | extern int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb); | 119 | extern int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb); |
122 | 120 | ||
123 | extern int dccp_send_response(struct sock *sk); | ||
124 | extern void dccp_send_ack(struct sock *sk); | 121 | extern void dccp_send_ack(struct sock *sk); |
125 | extern void dccp_send_delayed_ack(struct sock *sk); | 122 | extern void dccp_send_delayed_ack(struct sock *sk); |
126 | extern void dccp_send_sync(struct sock *sk, const u64 seq, | 123 | extern void dccp_send_sync(struct sock *sk, const u64 seq, |
@@ -140,53 +137,8 @@ extern unsigned int dccp_sync_mss(struct sock *sk, u32 pmtu); | |||
140 | extern const char *dccp_packet_name(const int type); | 137 | extern const char *dccp_packet_name(const int type); |
141 | extern const char *dccp_state_name(const int state); | 138 | extern const char *dccp_state_name(const int state); |
142 | 139 | ||
143 | static inline void dccp_set_state(struct sock *sk, const int state) | 140 | extern void dccp_set_state(struct sock *sk, const int state); |
144 | { | 141 | extern void dccp_done(struct sock *sk); |
145 | const int oldstate = sk->sk_state; | ||
146 | |||
147 | dccp_pr_debug("%s(%p) %-10.10s -> %s\n", | ||
148 | dccp_role(sk), sk, | ||
149 | dccp_state_name(oldstate), dccp_state_name(state)); | ||
150 | WARN_ON(state == oldstate); | ||
151 | |||
152 | switch (state) { | ||
153 | case DCCP_OPEN: | ||
154 | if (oldstate != DCCP_OPEN) | ||
155 | DCCP_INC_STATS(DCCP_MIB_CURRESTAB); | ||
156 | break; | ||
157 | |||
158 | case DCCP_CLOSED: | ||
159 | if (oldstate == DCCP_CLOSING || oldstate == DCCP_OPEN) | ||
160 | DCCP_INC_STATS(DCCP_MIB_ESTABRESETS); | ||
161 | |||
162 | sk->sk_prot->unhash(sk); | ||
163 | if (inet_csk(sk)->icsk_bind_hash != NULL && | ||
164 | !(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) | ||
165 | inet_put_port(&dccp_hashinfo, sk); | ||
166 | /* fall through */ | ||
167 | default: | ||
168 | if (oldstate == DCCP_OPEN) | ||
169 | DCCP_DEC_STATS(DCCP_MIB_CURRESTAB); | ||
170 | } | ||
171 | |||
172 | /* Change state AFTER socket is unhashed to avoid closed | ||
173 | * socket sitting in hash tables. | ||
174 | */ | ||
175 | sk->sk_state = state; | ||
176 | } | ||
177 | |||
178 | static inline void dccp_done(struct sock *sk) | ||
179 | { | ||
180 | dccp_set_state(sk, DCCP_CLOSED); | ||
181 | dccp_clear_xmit_timers(sk); | ||
182 | |||
183 | sk->sk_shutdown = SHUTDOWN_MASK; | ||
184 | |||
185 | if (!sock_flag(sk, SOCK_DEAD)) | ||
186 | sk->sk_state_change(sk); | ||
187 | else | ||
188 | inet_csk_destroy_sock(sk); | ||
189 | } | ||
190 | 142 | ||
191 | static inline void dccp_openreq_init(struct request_sock *req, | 143 | static inline void dccp_openreq_init(struct request_sock *req, |
192 | struct dccp_sock *dp, | 144 | struct dccp_sock *dp, |
@@ -209,10 +161,6 @@ extern struct sock *dccp_create_openreq_child(struct sock *sk, | |||
209 | 161 | ||
210 | extern int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb); | 162 | extern int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb); |
211 | 163 | ||
212 | extern void dccp_v4_err(struct sk_buff *skb, u32); | ||
213 | |||
214 | extern int dccp_v4_rcv(struct sk_buff *skb); | ||
215 | |||
216 | extern struct sock *dccp_v4_request_recv_sock(struct sock *sk, | 164 | extern struct sock *dccp_v4_request_recv_sock(struct sock *sk, |
217 | struct sk_buff *skb, | 165 | struct sk_buff *skb, |
218 | struct request_sock *req, | 166 | struct request_sock *req, |
@@ -228,24 +176,30 @@ extern int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
228 | extern int dccp_rcv_established(struct sock *sk, struct sk_buff *skb, | 176 | extern int dccp_rcv_established(struct sock *sk, struct sk_buff *skb, |
229 | const struct dccp_hdr *dh, const unsigned len); | 177 | const struct dccp_hdr *dh, const unsigned len); |
230 | 178 | ||
231 | extern int dccp_v4_init_sock(struct sock *sk); | 179 | extern int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized); |
232 | extern int dccp_v4_destroy_sock(struct sock *sk); | 180 | extern int dccp_destroy_sock(struct sock *sk); |
233 | 181 | ||
234 | extern void dccp_close(struct sock *sk, long timeout); | 182 | extern void dccp_close(struct sock *sk, long timeout); |
235 | extern struct sk_buff *dccp_make_response(struct sock *sk, | 183 | extern struct sk_buff *dccp_make_response(struct sock *sk, |
236 | struct dst_entry *dst, | 184 | struct dst_entry *dst, |
237 | struct request_sock *req); | 185 | struct request_sock *req); |
238 | extern struct sk_buff *dccp_make_reset(struct sock *sk, | ||
239 | struct dst_entry *dst, | ||
240 | enum dccp_reset_codes code); | ||
241 | 186 | ||
242 | extern int dccp_connect(struct sock *sk); | 187 | extern int dccp_connect(struct sock *sk); |
243 | extern int dccp_disconnect(struct sock *sk, int flags); | 188 | extern int dccp_disconnect(struct sock *sk, int flags); |
189 | extern void dccp_hash(struct sock *sk); | ||
244 | extern void dccp_unhash(struct sock *sk); | 190 | extern void dccp_unhash(struct sock *sk); |
245 | extern int dccp_getsockopt(struct sock *sk, int level, int optname, | 191 | extern int dccp_getsockopt(struct sock *sk, int level, int optname, |
246 | char __user *optval, int __user *optlen); | 192 | char __user *optval, int __user *optlen); |
247 | extern int dccp_setsockopt(struct sock *sk, int level, int optname, | 193 | extern int dccp_setsockopt(struct sock *sk, int level, int optname, |
248 | char __user *optval, int optlen); | 194 | char __user *optval, int optlen); |
195 | #ifdef CONFIG_COMPAT | ||
196 | extern int compat_dccp_getsockopt(struct sock *sk, | ||
197 | int level, int optname, | ||
198 | char __user *optval, int __user *optlen); | ||
199 | extern int compat_dccp_setsockopt(struct sock *sk, | ||
200 | int level, int optname, | ||
201 | char __user *optval, int optlen); | ||
202 | #endif | ||
249 | extern int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg); | 203 | extern int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg); |
250 | extern int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, | 204 | extern int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, |
251 | struct msghdr *msg, size_t size); | 205 | struct msghdr *msg, size_t size); |
@@ -262,15 +216,14 @@ extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, | |||
262 | int addr_len); | 216 | int addr_len); |
263 | 217 | ||
264 | extern int dccp_v4_checksum(const struct sk_buff *skb, | 218 | extern int dccp_v4_checksum(const struct sk_buff *skb, |
265 | const u32 saddr, const u32 daddr); | 219 | const __be32 saddr, const __be32 daddr); |
266 | 220 | ||
267 | extern int dccp_v4_send_reset(struct sock *sk, | 221 | extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code); |
268 | enum dccp_reset_codes code); | ||
269 | extern void dccp_send_close(struct sock *sk, const int active); | 222 | extern void dccp_send_close(struct sock *sk, const int active); |
270 | extern int dccp_invalid_packet(struct sk_buff *skb); | 223 | extern int dccp_invalid_packet(struct sk_buff *skb); |
271 | 224 | ||
272 | static inline int dccp_bad_service_code(const struct sock *sk, | 225 | static inline int dccp_bad_service_code(const struct sock *sk, |
273 | const __u32 service) | 226 | const __be32 service) |
274 | { | 227 | { |
275 | const struct dccp_sock *dp = dccp_sk(sk); | 228 | const struct dccp_sock *dp = dccp_sk(sk); |
276 | 229 | ||
@@ -334,41 +287,29 @@ static inline void dccp_hdr_set_seq(struct dccp_hdr *dh, const u64 gss) | |||
334 | { | 287 | { |
335 | struct dccp_hdr_ext *dhx = (struct dccp_hdr_ext *)((void *)dh + | 288 | struct dccp_hdr_ext *dhx = (struct dccp_hdr_ext *)((void *)dh + |
336 | sizeof(*dh)); | 289 | sizeof(*dh)); |
337 | 290 | dh->dccph_seq2 = 0; | |
338 | #if defined(__LITTLE_ENDIAN_BITFIELD) | 291 | dh->dccph_seq = htons((gss >> 32) & 0xfffff); |
339 | dh->dccph_seq = htonl((gss >> 32)) >> 8; | ||
340 | #elif defined(__BIG_ENDIAN_BITFIELD) | ||
341 | dh->dccph_seq = htonl((gss >> 32)); | ||
342 | #else | ||
343 | #error "Adjust your <asm/byteorder.h> defines" | ||
344 | #endif | ||
345 | dhx->dccph_seq_low = htonl(gss & 0xffffffff); | 292 | dhx->dccph_seq_low = htonl(gss & 0xffffffff); |
346 | } | 293 | } |
347 | 294 | ||
348 | static inline void dccp_hdr_set_ack(struct dccp_hdr_ack_bits *dhack, | 295 | static inline void dccp_hdr_set_ack(struct dccp_hdr_ack_bits *dhack, |
349 | const u64 gsr) | 296 | const u64 gsr) |
350 | { | 297 | { |
351 | #if defined(__LITTLE_ENDIAN_BITFIELD) | 298 | dhack->dccph_reserved1 = 0; |
352 | dhack->dccph_ack_nr_high = htonl((gsr >> 32)) >> 8; | 299 | dhack->dccph_ack_nr_high = htons(gsr >> 32); |
353 | #elif defined(__BIG_ENDIAN_BITFIELD) | ||
354 | dhack->dccph_ack_nr_high = htonl((gsr >> 32)); | ||
355 | #else | ||
356 | #error "Adjust your <asm/byteorder.h> defines" | ||
357 | #endif | ||
358 | dhack->dccph_ack_nr_low = htonl(gsr & 0xffffffff); | 300 | dhack->dccph_ack_nr_low = htonl(gsr & 0xffffffff); |
359 | } | 301 | } |
360 | 302 | ||
361 | static inline void dccp_update_gsr(struct sock *sk, u64 seq) | 303 | static inline void dccp_update_gsr(struct sock *sk, u64 seq) |
362 | { | 304 | { |
363 | struct dccp_sock *dp = dccp_sk(sk); | 305 | struct dccp_sock *dp = dccp_sk(sk); |
306 | const struct dccp_minisock *dmsk = dccp_msk(sk); | ||
364 | 307 | ||
365 | dp->dccps_gsr = seq; | 308 | dp->dccps_gsr = seq; |
366 | dccp_set_seqno(&dp->dccps_swl, | 309 | dccp_set_seqno(&dp->dccps_swl, |
367 | (dp->dccps_gsr + 1 - | 310 | dp->dccps_gsr + 1 - (dmsk->dccpms_sequence_window / 4)); |
368 | (dp->dccps_options.dccpo_sequence_window / 4))); | ||
369 | dccp_set_seqno(&dp->dccps_swh, | 311 | dccp_set_seqno(&dp->dccps_swh, |
370 | (dp->dccps_gsr + | 312 | dp->dccps_gsr + (3 * dmsk->dccpms_sequence_window) / 4); |
371 | (3 * dp->dccps_options.dccpo_sequence_window) / 4)); | ||
372 | } | 313 | } |
373 | 314 | ||
374 | static inline void dccp_update_gss(struct sock *sk, u64 seq) | 315 | static inline void dccp_update_gss(struct sock *sk, u64 seq) |
@@ -378,7 +319,7 @@ static inline void dccp_update_gss(struct sock *sk, u64 seq) | |||
378 | dp->dccps_awh = dp->dccps_gss = seq; | 319 | dp->dccps_awh = dp->dccps_gss = seq; |
379 | dccp_set_seqno(&dp->dccps_awl, | 320 | dccp_set_seqno(&dp->dccps_awl, |
380 | (dp->dccps_gss - | 321 | (dp->dccps_gss - |
381 | dp->dccps_options.dccpo_sequence_window + 1)); | 322 | dccp_msk(sk)->dccpms_sequence_window + 1)); |
382 | } | 323 | } |
383 | 324 | ||
384 | static inline int dccp_ack_pending(const struct sock *sk) | 325 | static inline int dccp_ack_pending(const struct sock *sk) |
@@ -386,24 +327,22 @@ static inline int dccp_ack_pending(const struct sock *sk) | |||
386 | const struct dccp_sock *dp = dccp_sk(sk); | 327 | const struct dccp_sock *dp = dccp_sk(sk); |
387 | return dp->dccps_timestamp_echo != 0 || | 328 | return dp->dccps_timestamp_echo != 0 || |
388 | #ifdef CONFIG_IP_DCCP_ACKVEC | 329 | #ifdef CONFIG_IP_DCCP_ACKVEC |
389 | (dp->dccps_options.dccpo_send_ack_vector && | 330 | (dccp_msk(sk)->dccpms_send_ack_vector && |
390 | dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) || | 331 | dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) || |
391 | #endif | 332 | #endif |
392 | inet_csk_ack_scheduled(sk); | 333 | inet_csk_ack_scheduled(sk); |
393 | } | 334 | } |
394 | 335 | ||
395 | extern void dccp_insert_options(struct sock *sk, struct sk_buff *skb); | 336 | extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb); |
396 | extern void dccp_insert_option_elapsed_time(struct sock *sk, | 337 | extern int dccp_insert_option_elapsed_time(struct sock *sk, |
397 | struct sk_buff *skb, | 338 | struct sk_buff *skb, |
398 | u32 elapsed_time); | 339 | u32 elapsed_time); |
399 | extern void dccp_insert_option_timestamp(struct sock *sk, | 340 | extern int dccp_insert_option_timestamp(struct sock *sk, |
400 | struct sk_buff *skb); | 341 | struct sk_buff *skb); |
401 | extern void dccp_insert_option(struct sock *sk, struct sk_buff *skb, | 342 | extern int dccp_insert_option(struct sock *sk, struct sk_buff *skb, |
402 | unsigned char option, | 343 | unsigned char option, |
403 | const void *value, unsigned char len); | 344 | const void *value, unsigned char len); |
404 | 345 | ||
405 | extern struct socket *dccp_ctl_socket; | ||
406 | |||
407 | extern void dccp_timestamp(const struct sock *sk, struct timeval *tv); | 346 | extern void dccp_timestamp(const struct sock *sk, struct timeval *tv); |
408 | 347 | ||
409 | static inline suseconds_t timeval_usecs(const struct timeval *tv) | 348 | static inline suseconds_t timeval_usecs(const struct timeval *tv) |
@@ -444,4 +383,18 @@ static inline void timeval_sub_usecs(struct timeval *tv, | |||
444 | } | 383 | } |
445 | } | 384 | } |
446 | 385 | ||
386 | #ifdef CONFIG_SYSCTL | ||
387 | extern int dccp_sysctl_init(void); | ||
388 | extern void dccp_sysctl_exit(void); | ||
389 | #else | ||
390 | static inline int dccp_sysctl_init(void) | ||
391 | { | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | static inline void dccp_sysctl_exit(void) | ||
396 | { | ||
397 | } | ||
398 | #endif | ||
399 | |||
447 | #endif /* _DCCP_H */ | 400 | #endif /* _DCCP_H */ |
diff --git a/net/dccp/diag.c b/net/dccp/diag.c index 3f78c00e3822..0f25dc395967 100644 --- a/net/dccp/diag.c +++ b/net/dccp/diag.c | |||
@@ -30,7 +30,7 @@ static void dccp_get_info(struct sock *sk, struct tcp_info *info) | |||
30 | info->tcpi_backoff = icsk->icsk_backoff; | 30 | info->tcpi_backoff = icsk->icsk_backoff; |
31 | info->tcpi_pmtu = icsk->icsk_pmtu_cookie; | 31 | info->tcpi_pmtu = icsk->icsk_pmtu_cookie; |
32 | 32 | ||
33 | if (dp->dccps_options.dccpo_send_ack_vector) | 33 | if (dccp_msk(sk)->dccpms_send_ack_vector) |
34 | info->tcpi_options |= TCPI_OPT_SACK; | 34 | info->tcpi_options |= TCPI_OPT_SACK; |
35 | 35 | ||
36 | ccid_hc_rx_get_info(dp->dccps_hc_rx_ccid, sk, info); | 36 | ccid_hc_rx_get_info(dp->dccps_hc_rx_ccid, sk, info); |
diff --git a/net/dccp/feat.c b/net/dccp/feat.c new file mode 100644 index 000000000000..e3dd30d36c8a --- /dev/null +++ b/net/dccp/feat.c | |||
@@ -0,0 +1,586 @@ | |||
1 | /* | ||
2 | * net/dccp/feat.c | ||
3 | * | ||
4 | * An implementation of the DCCP protocol | ||
5 | * Andrea Bittau <a.bittau@cs.ucl.ac.uk> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/module.h> | ||
15 | |||
16 | #include "dccp.h" | ||
17 | #include "ccid.h" | ||
18 | #include "feat.h" | ||
19 | |||
20 | #define DCCP_FEAT_SP_NOAGREE (-123) | ||
21 | |||
22 | int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, | ||
23 | u8 *val, u8 len, gfp_t gfp) | ||
24 | { | ||
25 | struct dccp_opt_pend *opt; | ||
26 | |||
27 | dccp_pr_debug("feat change type=%d feat=%d\n", type, feature); | ||
28 | |||
29 | /* XXX sanity check feat change request */ | ||
30 | |||
31 | /* check if that feature is already being negotiated */ | ||
32 | list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { | ||
33 | /* ok we found a negotiation for this option already */ | ||
34 | if (opt->dccpop_feat == feature && opt->dccpop_type == type) { | ||
35 | dccp_pr_debug("Replacing old\n"); | ||
36 | /* replace */ | ||
37 | BUG_ON(opt->dccpop_val == NULL); | ||
38 | kfree(opt->dccpop_val); | ||
39 | opt->dccpop_val = val; | ||
40 | opt->dccpop_len = len; | ||
41 | opt->dccpop_conf = 0; | ||
42 | return 0; | ||
43 | } | ||
44 | } | ||
45 | |||
46 | /* negotiation for a new feature */ | ||
47 | opt = kmalloc(sizeof(*opt), gfp); | ||
48 | if (opt == NULL) | ||
49 | return -ENOMEM; | ||
50 | |||
51 | opt->dccpop_type = type; | ||
52 | opt->dccpop_feat = feature; | ||
53 | opt->dccpop_len = len; | ||
54 | opt->dccpop_val = val; | ||
55 | opt->dccpop_conf = 0; | ||
56 | opt->dccpop_sc = NULL; | ||
57 | |||
58 | BUG_ON(opt->dccpop_val == NULL); | ||
59 | |||
60 | list_add_tail(&opt->dccpop_node, &dmsk->dccpms_pending); | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | EXPORT_SYMBOL_GPL(dccp_feat_change); | ||
65 | |||
66 | static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) | ||
67 | { | ||
68 | struct dccp_sock *dp = dccp_sk(sk); | ||
69 | struct dccp_minisock *dmsk = dccp_msk(sk); | ||
70 | /* figure out if we are changing our CCID or the peer's */ | ||
71 | const int rx = type == DCCPO_CHANGE_R; | ||
72 | const u8 ccid_nr = rx ? dmsk->dccpms_rx_ccid : dmsk->dccpms_tx_ccid; | ||
73 | struct ccid *new_ccid; | ||
74 | |||
75 | /* Check if nothing is being changed. */ | ||
76 | if (ccid_nr == new_ccid_nr) | ||
77 | return 0; | ||
78 | |||
79 | new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC); | ||
80 | if (new_ccid == NULL) | ||
81 | return -ENOMEM; | ||
82 | |||
83 | if (rx) { | ||
84 | ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); | ||
85 | dp->dccps_hc_rx_ccid = new_ccid; | ||
86 | dmsk->dccpms_rx_ccid = new_ccid_nr; | ||
87 | } else { | ||
88 | ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); | ||
89 | dp->dccps_hc_tx_ccid = new_ccid; | ||
90 | dmsk->dccpms_tx_ccid = new_ccid_nr; | ||
91 | } | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | /* XXX taking only u8 vals */ | ||
97 | static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val) | ||
98 | { | ||
99 | dccp_pr_debug("changing [%d] feat %d to %d\n", type, feat, val); | ||
100 | |||
101 | switch (feat) { | ||
102 | case DCCPF_CCID: | ||
103 | return dccp_feat_update_ccid(sk, type, val); | ||
104 | default: | ||
105 | dccp_pr_debug("IMPLEMENT changing [%d] feat %d to %d\n", | ||
106 | type, feat, val); | ||
107 | break; | ||
108 | } | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt, | ||
113 | u8 *rpref, u8 rlen) | ||
114 | { | ||
115 | struct dccp_sock *dp = dccp_sk(sk); | ||
116 | u8 *spref, slen, *res = NULL; | ||
117 | int i, j, rc, agree = 1; | ||
118 | |||
119 | BUG_ON(rpref == NULL); | ||
120 | |||
121 | /* check if we are the black sheep */ | ||
122 | if (dp->dccps_role == DCCP_ROLE_CLIENT) { | ||
123 | spref = rpref; | ||
124 | slen = rlen; | ||
125 | rpref = opt->dccpop_val; | ||
126 | rlen = opt->dccpop_len; | ||
127 | } else { | ||
128 | spref = opt->dccpop_val; | ||
129 | slen = opt->dccpop_len; | ||
130 | } | ||
131 | /* | ||
132 | * Now we have server preference list in spref and client preference in | ||
133 | * rpref | ||
134 | */ | ||
135 | BUG_ON(spref == NULL); | ||
136 | BUG_ON(rpref == NULL); | ||
137 | |||
138 | /* FIXME sanity check vals */ | ||
139 | |||
140 | /* Are values in any order? XXX Lame "algorithm" here */ | ||
141 | /* XXX assume values are 1 byte */ | ||
142 | for (i = 0; i < slen; i++) { | ||
143 | for (j = 0; j < rlen; j++) { | ||
144 | if (spref[i] == rpref[j]) { | ||
145 | res = &spref[i]; | ||
146 | break; | ||
147 | } | ||
148 | } | ||
149 | if (res) | ||
150 | break; | ||
151 | } | ||
152 | |||
153 | /* we didn't agree on anything */ | ||
154 | if (res == NULL) { | ||
155 | /* confirm previous value */ | ||
156 | switch (opt->dccpop_feat) { | ||
157 | case DCCPF_CCID: | ||
158 | /* XXX did i get this right? =P */ | ||
159 | if (opt->dccpop_type == DCCPO_CHANGE_L) | ||
160 | res = &dccp_msk(sk)->dccpms_tx_ccid; | ||
161 | else | ||
162 | res = &dccp_msk(sk)->dccpms_rx_ccid; | ||
163 | break; | ||
164 | |||
165 | default: | ||
166 | WARN_ON(1); /* XXX implement res */ | ||
167 | return -EFAULT; | ||
168 | } | ||
169 | |||
170 | dccp_pr_debug("Don't agree... reconfirming %d\n", *res); | ||
171 | agree = 0; /* this is used for mandatory options... */ | ||
172 | } | ||
173 | |||
174 | /* need to put result and our preference list */ | ||
175 | /* XXX assume 1 byte vals */ | ||
176 | rlen = 1 + opt->dccpop_len; | ||
177 | rpref = kmalloc(rlen, GFP_ATOMIC); | ||
178 | if (rpref == NULL) | ||
179 | return -ENOMEM; | ||
180 | |||
181 | *rpref = *res; | ||
182 | memcpy(&rpref[1], opt->dccpop_val, opt->dccpop_len); | ||
183 | |||
184 | /* put it in the "confirm queue" */ | ||
185 | if (opt->dccpop_sc == NULL) { | ||
186 | opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC); | ||
187 | if (opt->dccpop_sc == NULL) { | ||
188 | kfree(rpref); | ||
189 | return -ENOMEM; | ||
190 | } | ||
191 | } else { | ||
192 | /* recycle the confirm slot */ | ||
193 | BUG_ON(opt->dccpop_sc->dccpoc_val == NULL); | ||
194 | kfree(opt->dccpop_sc->dccpoc_val); | ||
195 | dccp_pr_debug("recycling confirm slot\n"); | ||
196 | } | ||
197 | memset(opt->dccpop_sc, 0, sizeof(*opt->dccpop_sc)); | ||
198 | |||
199 | opt->dccpop_sc->dccpoc_val = rpref; | ||
200 | opt->dccpop_sc->dccpoc_len = rlen; | ||
201 | |||
202 | /* update the option on our side [we are about to send the confirm] */ | ||
203 | rc = dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *res); | ||
204 | if (rc) { | ||
205 | kfree(opt->dccpop_sc->dccpoc_val); | ||
206 | kfree(opt->dccpop_sc); | ||
207 | opt->dccpop_sc = 0; | ||
208 | return rc; | ||
209 | } | ||
210 | |||
211 | dccp_pr_debug("Will confirm %d\n", *rpref); | ||
212 | |||
213 | /* say we want to change to X but we just got a confirm X, suppress our | ||
214 | * change | ||
215 | */ | ||
216 | if (!opt->dccpop_conf) { | ||
217 | if (*opt->dccpop_val == *res) | ||
218 | opt->dccpop_conf = 1; | ||
219 | dccp_pr_debug("won't ask for change of same feature\n"); | ||
220 | } | ||
221 | |||
222 | return agree ? 0 : DCCP_FEAT_SP_NOAGREE; /* used for mandatory opts */ | ||
223 | } | ||
224 | |||
225 | static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) | ||
226 | { | ||
227 | struct dccp_minisock *dmsk = dccp_msk(sk); | ||
228 | struct dccp_opt_pend *opt; | ||
229 | int rc = 1; | ||
230 | u8 t; | ||
231 | |||
232 | /* | ||
233 | * We received a CHANGE. We gotta match it against our own preference | ||
234 | * list. If we got a CHANGE_R it means it's a change for us, so we need | ||
235 | * to compare our CHANGE_L list. | ||
236 | */ | ||
237 | if (type == DCCPO_CHANGE_L) | ||
238 | t = DCCPO_CHANGE_R; | ||
239 | else | ||
240 | t = DCCPO_CHANGE_L; | ||
241 | |||
242 | /* find our preference list for this feature */ | ||
243 | list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { | ||
244 | if (opt->dccpop_type != t || opt->dccpop_feat != feature) | ||
245 | continue; | ||
246 | |||
247 | /* find the winner from the two preference lists */ | ||
248 | rc = dccp_feat_reconcile(sk, opt, val, len); | ||
249 | break; | ||
250 | } | ||
251 | |||
252 | /* We didn't deal with the change. This can happen if we have no | ||
253 | * preference list for the feature. In fact, it just shouldn't | ||
254 | * happen---if we understand a feature, we should have a preference list | ||
255 | * with at least the default value. | ||
256 | */ | ||
257 | BUG_ON(rc == 1); | ||
258 | |||
259 | return rc; | ||
260 | } | ||
261 | |||
262 | static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) | ||
263 | { | ||
264 | struct dccp_opt_pend *opt; | ||
265 | struct dccp_minisock *dmsk = dccp_msk(sk); | ||
266 | u8 *copy; | ||
267 | int rc; | ||
268 | |||
269 | /* NN features must be change L */ | ||
270 | if (type == DCCPO_CHANGE_R) { | ||
271 | dccp_pr_debug("received CHANGE_R %d for NN feat %d\n", | ||
272 | type, feature); | ||
273 | return -EFAULT; | ||
274 | } | ||
275 | |||
276 | /* XXX sanity check opt val */ | ||
277 | |||
278 | /* copy option so we can confirm it */ | ||
279 | opt = kzalloc(sizeof(*opt), GFP_ATOMIC); | ||
280 | if (opt == NULL) | ||
281 | return -ENOMEM; | ||
282 | |||
283 | copy = kmalloc(len, GFP_ATOMIC); | ||
284 | if (copy == NULL) { | ||
285 | kfree(opt); | ||
286 | return -ENOMEM; | ||
287 | } | ||
288 | memcpy(copy, val, len); | ||
289 | |||
290 | opt->dccpop_type = DCCPO_CONFIRM_R; /* NN can only confirm R */ | ||
291 | opt->dccpop_feat = feature; | ||
292 | opt->dccpop_val = copy; | ||
293 | opt->dccpop_len = len; | ||
294 | |||
295 | /* change feature */ | ||
296 | rc = dccp_feat_update(sk, type, feature, *val); | ||
297 | if (rc) { | ||
298 | kfree(opt->dccpop_val); | ||
299 | kfree(opt); | ||
300 | return rc; | ||
301 | } | ||
302 | |||
303 | dccp_pr_debug("Confirming NN feature %d (val=%d)\n", feature, *copy); | ||
304 | list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk, | ||
310 | u8 type, u8 feature) | ||
311 | { | ||
312 | /* XXX check if other confirms for that are queued and recycle slot */ | ||
313 | struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC); | ||
314 | |||
315 | if (opt == NULL) { | ||
316 | /* XXX what do we do? Ignoring should be fine. It's a change | ||
317 | * after all =P | ||
318 | */ | ||
319 | return; | ||
320 | } | ||
321 | |||
322 | opt->dccpop_type = type == DCCPO_CHANGE_L ? DCCPO_CONFIRM_R : | ||
323 | DCCPO_CONFIRM_L; | ||
324 | opt->dccpop_feat = feature; | ||
325 | opt->dccpop_val = 0; | ||
326 | opt->dccpop_len = 0; | ||
327 | |||
328 | /* change feature */ | ||
329 | dccp_pr_debug("Empty confirm feature %d type %d\n", feature, type); | ||
330 | list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); | ||
331 | } | ||
332 | |||
333 | static void dccp_feat_flush_confirm(struct sock *sk) | ||
334 | { | ||
335 | struct dccp_minisock *dmsk = dccp_msk(sk); | ||
336 | /* Check if there is anything to confirm in the first place */ | ||
337 | int yes = !list_empty(&dmsk->dccpms_conf); | ||
338 | |||
339 | if (!yes) { | ||
340 | struct dccp_opt_pend *opt; | ||
341 | |||
342 | list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { | ||
343 | if (opt->dccpop_conf) { | ||
344 | yes = 1; | ||
345 | break; | ||
346 | } | ||
347 | } | ||
348 | } | ||
349 | |||
350 | if (!yes) | ||
351 | return; | ||
352 | |||
353 | /* OK there is something to confirm... */ | ||
354 | /* XXX check if packet is in flight? Send delayed ack?? */ | ||
355 | if (sk->sk_state == DCCP_OPEN) | ||
356 | dccp_send_ack(sk); | ||
357 | } | ||
358 | |||
359 | int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) | ||
360 | { | ||
361 | int rc; | ||
362 | |||
363 | dccp_pr_debug("got feat change type=%d feat=%d\n", type, feature); | ||
364 | |||
365 | /* figure out if it's SP or NN feature */ | ||
366 | switch (feature) { | ||
367 | /* deal with SP features */ | ||
368 | case DCCPF_CCID: | ||
369 | rc = dccp_feat_sp(sk, type, feature, val, len); | ||
370 | break; | ||
371 | |||
372 | /* deal with NN features */ | ||
373 | case DCCPF_ACK_RATIO: | ||
374 | rc = dccp_feat_nn(sk, type, feature, val, len); | ||
375 | break; | ||
376 | |||
377 | /* XXX implement other features */ | ||
378 | default: | ||
379 | rc = -EFAULT; | ||
380 | break; | ||
381 | } | ||
382 | |||
383 | /* check if there were problems changing features */ | ||
384 | if (rc) { | ||
385 | /* If we don't agree on SP, we sent a confirm for old value. | ||
386 | * However we propagate rc to caller in case option was | ||
387 | * mandatory | ||
388 | */ | ||
389 | if (rc != DCCP_FEAT_SP_NOAGREE) | ||
390 | dccp_feat_empty_confirm(dccp_msk(sk), type, feature); | ||
391 | } | ||
392 | |||
393 | /* generate the confirm [if required] */ | ||
394 | dccp_feat_flush_confirm(sk); | ||
395 | |||
396 | return rc; | ||
397 | } | ||
398 | |||
399 | EXPORT_SYMBOL_GPL(dccp_feat_change_recv); | ||
400 | |||
401 | int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, | ||
402 | u8 *val, u8 len) | ||
403 | { | ||
404 | u8 t; | ||
405 | struct dccp_opt_pend *opt; | ||
406 | struct dccp_minisock *dmsk = dccp_msk(sk); | ||
407 | int rc = 1; | ||
408 | int all_confirmed = 1; | ||
409 | |||
410 | dccp_pr_debug("got feat confirm type=%d feat=%d\n", type, feature); | ||
411 | |||
412 | /* XXX sanity check type & feat */ | ||
413 | |||
414 | /* locate our change request */ | ||
415 | t = type == DCCPO_CONFIRM_L ? DCCPO_CHANGE_R : DCCPO_CHANGE_L; | ||
416 | |||
417 | list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { | ||
418 | if (!opt->dccpop_conf && opt->dccpop_type == t && | ||
419 | opt->dccpop_feat == feature) { | ||
420 | /* we found it */ | ||
421 | /* XXX do sanity check */ | ||
422 | |||
423 | opt->dccpop_conf = 1; | ||
424 | |||
425 | /* We got a confirmation---change the option */ | ||
426 | dccp_feat_update(sk, opt->dccpop_type, | ||
427 | opt->dccpop_feat, *val); | ||
428 | |||
429 | dccp_pr_debug("feat %d type %d confirmed %d\n", | ||
430 | feature, type, *val); | ||
431 | rc = 0; | ||
432 | break; | ||
433 | } | ||
434 | |||
435 | if (!opt->dccpop_conf) | ||
436 | all_confirmed = 0; | ||
437 | } | ||
438 | |||
439 | /* fix re-transmit timer */ | ||
440 | /* XXX gotta make sure that no option negotiation occurs during | ||
441 | * connection shutdown. Consider that the CLOSEREQ is sent and timer is | ||
442 | * on. if all options are confirmed it might kill timer which should | ||
443 | * remain alive until close is received. | ||
444 | */ | ||
445 | if (all_confirmed) { | ||
446 | dccp_pr_debug("clear feat negotiation timer %p\n", sk); | ||
447 | inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS); | ||
448 | } | ||
449 | |||
450 | if (rc) | ||
451 | dccp_pr_debug("feat %d type %d never requested\n", | ||
452 | feature, type); | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv); | ||
457 | |||
458 | void dccp_feat_clean(struct dccp_minisock *dmsk) | ||
459 | { | ||
460 | struct dccp_opt_pend *opt, *next; | ||
461 | |||
462 | list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending, | ||
463 | dccpop_node) { | ||
464 | BUG_ON(opt->dccpop_val == NULL); | ||
465 | kfree(opt->dccpop_val); | ||
466 | |||
467 | if (opt->dccpop_sc != NULL) { | ||
468 | BUG_ON(opt->dccpop_sc->dccpoc_val == NULL); | ||
469 | kfree(opt->dccpop_sc->dccpoc_val); | ||
470 | kfree(opt->dccpop_sc); | ||
471 | } | ||
472 | |||
473 | kfree(opt); | ||
474 | } | ||
475 | INIT_LIST_HEAD(&dmsk->dccpms_pending); | ||
476 | |||
477 | list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) { | ||
478 | BUG_ON(opt == NULL); | ||
479 | if (opt->dccpop_val != NULL) | ||
480 | kfree(opt->dccpop_val); | ||
481 | kfree(opt); | ||
482 | } | ||
483 | INIT_LIST_HEAD(&dmsk->dccpms_conf); | ||
484 | } | ||
485 | |||
486 | EXPORT_SYMBOL_GPL(dccp_feat_clean); | ||
487 | |||
488 | /* this is to be called only when a listening sock creates its child. It is | ||
489 | * assumed by the function---the confirm is not duplicated, but rather it is | ||
490 | * "passed on". | ||
491 | */ | ||
492 | int dccp_feat_clone(struct sock *oldsk, struct sock *newsk) | ||
493 | { | ||
494 | struct dccp_minisock *olddmsk = dccp_msk(oldsk); | ||
495 | struct dccp_minisock *newdmsk = dccp_msk(newsk); | ||
496 | struct dccp_opt_pend *opt; | ||
497 | int rc = 0; | ||
498 | |||
499 | INIT_LIST_HEAD(&newdmsk->dccpms_pending); | ||
500 | INIT_LIST_HEAD(&newdmsk->dccpms_conf); | ||
501 | |||
502 | list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) { | ||
503 | struct dccp_opt_pend *newopt; | ||
504 | /* copy the value of the option */ | ||
505 | u8 *val = kmalloc(opt->dccpop_len, GFP_ATOMIC); | ||
506 | |||
507 | if (val == NULL) | ||
508 | goto out_clean; | ||
509 | memcpy(val, opt->dccpop_val, opt->dccpop_len); | ||
510 | |||
511 | newopt = kmalloc(sizeof(*newopt), GFP_ATOMIC); | ||
512 | if (newopt == NULL) { | ||
513 | kfree(val); | ||
514 | goto out_clean; | ||
515 | } | ||
516 | |||
517 | /* insert the option */ | ||
518 | memcpy(newopt, opt, sizeof(*newopt)); | ||
519 | newopt->dccpop_val = val; | ||
520 | list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending); | ||
521 | |||
522 | /* XXX what happens with backlogs and multiple connections at | ||
523 | * once... | ||
524 | */ | ||
525 | /* the master socket no longer needs to worry about confirms */ | ||
526 | opt->dccpop_sc = 0; /* it's not a memleak---new socket has it */ | ||
527 | |||
528 | /* reset state for a new socket */ | ||
529 | opt->dccpop_conf = 0; | ||
530 | } | ||
531 | |||
532 | /* XXX not doing anything about the conf queue */ | ||
533 | |||
534 | out: | ||
535 | return rc; | ||
536 | |||
537 | out_clean: | ||
538 | dccp_feat_clean(newdmsk); | ||
539 | rc = -ENOMEM; | ||
540 | goto out; | ||
541 | } | ||
542 | |||
543 | EXPORT_SYMBOL_GPL(dccp_feat_clone); | ||
544 | |||
545 | static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat, | ||
546 | u8 *val, u8 len) | ||
547 | { | ||
548 | int rc = -ENOMEM; | ||
549 | u8 *copy = kmalloc(len, GFP_KERNEL); | ||
550 | |||
551 | if (copy != NULL) { | ||
552 | memcpy(copy, val, len); | ||
553 | rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL); | ||
554 | if (rc) | ||
555 | kfree(copy); | ||
556 | } | ||
557 | return rc; | ||
558 | } | ||
559 | |||
560 | int dccp_feat_init(struct dccp_minisock *dmsk) | ||
561 | { | ||
562 | int rc; | ||
563 | |||
564 | INIT_LIST_HEAD(&dmsk->dccpms_pending); | ||
565 | INIT_LIST_HEAD(&dmsk->dccpms_conf); | ||
566 | |||
567 | /* CCID L */ | ||
568 | rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID, | ||
569 | &dmsk->dccpms_tx_ccid, 1); | ||
570 | if (rc) | ||
571 | goto out; | ||
572 | |||
573 | /* CCID R */ | ||
574 | rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID, | ||
575 | &dmsk->dccpms_rx_ccid, 1); | ||
576 | if (rc) | ||
577 | goto out; | ||
578 | |||
579 | /* Ack ratio */ | ||
580 | rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO, | ||
581 | &dmsk->dccpms_ack_ratio, 1); | ||
582 | out: | ||
583 | return rc; | ||
584 | } | ||
585 | |||
586 | EXPORT_SYMBOL_GPL(dccp_feat_init); | ||
diff --git a/net/dccp/feat.h b/net/dccp/feat.h new file mode 100644 index 000000000000..6048373c7186 --- /dev/null +++ b/net/dccp/feat.h | |||
@@ -0,0 +1,29 @@ | |||
1 | #ifndef _DCCP_FEAT_H | ||
2 | #define _DCCP_FEAT_H | ||
3 | /* | ||
4 | * net/dccp/feat.h | ||
5 | * | ||
6 | * An implementation of the DCCP protocol | ||
7 | * Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/types.h> | ||
15 | |||
16 | struct sock; | ||
17 | struct dccp_minisock; | ||
18 | |||
19 | extern int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, | ||
20 | u8 *val, u8 len, gfp_t gfp); | ||
21 | extern int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, | ||
22 | u8 *val, u8 len); | ||
23 | extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, | ||
24 | u8 *val, u8 len); | ||
25 | extern void dccp_feat_clean(struct dccp_minisock *dmsk); | ||
26 | extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk); | ||
27 | extern int dccp_feat_init(struct dccp_minisock *dmsk); | ||
28 | |||
29 | #endif /* _DCCP_FEAT_H */ | ||
diff --git a/net/dccp/input.c b/net/dccp/input.c index b6cba72b44e8..bfc53665516b 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c | |||
@@ -32,7 +32,7 @@ static void dccp_fin(struct sock *sk, struct sk_buff *skb) | |||
32 | 32 | ||
33 | static void dccp_rcv_close(struct sock *sk, struct sk_buff *skb) | 33 | static void dccp_rcv_close(struct sock *sk, struct sk_buff *skb) |
34 | { | 34 | { |
35 | dccp_v4_send_reset(sk, DCCP_RESET_CODE_CLOSED); | 35 | dccp_send_reset(sk, DCCP_RESET_CODE_CLOSED); |
36 | dccp_fin(sk, skb); | 36 | dccp_fin(sk, skb); |
37 | dccp_set_state(sk, DCCP_CLOSED); | 37 | dccp_set_state(sk, DCCP_CLOSED); |
38 | sk_wake_async(sk, 1, POLL_HUP); | 38 | sk_wake_async(sk, 1, POLL_HUP); |
@@ -56,11 +56,11 @@ static void dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb) | |||
56 | dccp_send_close(sk, 0); | 56 | dccp_send_close(sk, 0); |
57 | } | 57 | } |
58 | 58 | ||
59 | static inline void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb) | 59 | static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb) |
60 | { | 60 | { |
61 | struct dccp_sock *dp = dccp_sk(sk); | 61 | struct dccp_sock *dp = dccp_sk(sk); |
62 | 62 | ||
63 | if (dp->dccps_options.dccpo_send_ack_vector) | 63 | if (dccp_msk(sk)->dccpms_send_ack_vector) |
64 | dccp_ackvec_check_rcv_ackno(dp->dccps_hc_rx_ackvec, sk, | 64 | dccp_ackvec_check_rcv_ackno(dp->dccps_hc_rx_ackvec, sk, |
65 | DCCP_SKB_CB(skb)->dccpd_ack_seq); | 65 | DCCP_SKB_CB(skb)->dccpd_ack_seq); |
66 | } | 66 | } |
@@ -151,9 +151,8 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb) | |||
151 | return 0; | 151 | return 0; |
152 | } | 152 | } |
153 | 153 | ||
154 | static inline int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb, | 154 | static int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb, |
155 | const struct dccp_hdr *dh, | 155 | const struct dccp_hdr *dh, const unsigned len) |
156 | const unsigned len) | ||
157 | { | 156 | { |
158 | struct dccp_sock *dp = dccp_sk(sk); | 157 | struct dccp_sock *dp = dccp_sk(sk); |
159 | 158 | ||
@@ -247,7 +246,7 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb, | |||
247 | if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) | 246 | if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) |
248 | dccp_event_ack_recv(sk, skb); | 247 | dccp_event_ack_recv(sk, skb); |
249 | 248 | ||
250 | if (dp->dccps_options.dccpo_send_ack_vector && | 249 | if (dccp_msk(sk)->dccpms_send_ack_vector && |
251 | dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, | 250 | dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, |
252 | DCCP_SKB_CB(skb)->dccpd_seq, | 251 | DCCP_SKB_CB(skb)->dccpd_seq, |
253 | DCCP_ACKVEC_STATE_RECEIVED)) | 252 | DCCP_ACKVEC_STATE_RECEIVED)) |
@@ -300,7 +299,10 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk, | |||
300 | goto out_invalid_packet; | 299 | goto out_invalid_packet; |
301 | } | 300 | } |
302 | 301 | ||
303 | if (dp->dccps_options.dccpo_send_ack_vector && | 302 | if (dccp_parse_options(sk, skb)) |
303 | goto out_invalid_packet; | ||
304 | |||
305 | if (dccp_msk(sk)->dccpms_send_ack_vector && | ||
304 | dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, | 306 | dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, |
305 | DCCP_SKB_CB(skb)->dccpd_seq, | 307 | DCCP_SKB_CB(skb)->dccpd_seq, |
306 | DCCP_ACKVEC_STATE_RECEIVED)) | 308 | DCCP_ACKVEC_STATE_RECEIVED)) |
@@ -321,14 +323,6 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk, | |||
321 | dccp_set_seqno(&dp->dccps_swl, | 323 | dccp_set_seqno(&dp->dccps_swl, |
322 | max48(dp->dccps_swl, dp->dccps_isr)); | 324 | max48(dp->dccps_swl, dp->dccps_isr)); |
323 | 325 | ||
324 | if (ccid_hc_rx_init(dp->dccps_hc_rx_ccid, sk) != 0 || | ||
325 | ccid_hc_tx_init(dp->dccps_hc_tx_ccid, sk) != 0) { | ||
326 | ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk); | ||
327 | ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk); | ||
328 | /* FIXME: send appropriate RESET code */ | ||
329 | goto out_invalid_packet; | ||
330 | } | ||
331 | |||
332 | dccp_sync_mss(sk, icsk->icsk_pmtu_cookie); | 326 | dccp_sync_mss(sk, icsk->icsk_pmtu_cookie); |
333 | 327 | ||
334 | /* | 328 | /* |
@@ -492,7 +486,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
492 | if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) | 486 | if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) |
493 | dccp_event_ack_recv(sk, skb); | 487 | dccp_event_ack_recv(sk, skb); |
494 | 488 | ||
495 | if (dp->dccps_options.dccpo_send_ack_vector && | 489 | if (dccp_msk(sk)->dccpms_send_ack_vector && |
496 | dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, | 490 | dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, |
497 | DCCP_SKB_CB(skb)->dccpd_seq, | 491 | DCCP_SKB_CB(skb)->dccpd_seq, |
498 | DCCP_ACKVEC_STATE_RECEIVED)) | 492 | DCCP_ACKVEC_STATE_RECEIVED)) |
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index dc0487b5bace..29047995c695 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -18,8 +18,10 @@ | |||
18 | #include <linux/random.h> | 18 | #include <linux/random.h> |
19 | 19 | ||
20 | #include <net/icmp.h> | 20 | #include <net/icmp.h> |
21 | #include <net/inet_common.h> | ||
21 | #include <net/inet_hashtables.h> | 22 | #include <net/inet_hashtables.h> |
22 | #include <net/inet_sock.h> | 23 | #include <net/inet_sock.h> |
24 | #include <net/protocol.h> | ||
23 | #include <net/sock.h> | 25 | #include <net/sock.h> |
24 | #include <net/timewait_sock.h> | 26 | #include <net/timewait_sock.h> |
25 | #include <net/tcp_states.h> | 27 | #include <net/tcp_states.h> |
@@ -28,14 +30,14 @@ | |||
28 | #include "ackvec.h" | 30 | #include "ackvec.h" |
29 | #include "ccid.h" | 31 | #include "ccid.h" |
30 | #include "dccp.h" | 32 | #include "dccp.h" |
33 | #include "feat.h" | ||
31 | 34 | ||
32 | struct inet_hashinfo __cacheline_aligned dccp_hashinfo = { | 35 | /* |
33 | .lhash_lock = RW_LOCK_UNLOCKED, | 36 | * This is the global socket data structure used for responding to |
34 | .lhash_users = ATOMIC_INIT(0), | 37 | * the Out-of-the-blue (OOTB) packets. A control sock will be created |
35 | .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait), | 38 | * for this socket at the initialization time. |
36 | }; | 39 | */ |
37 | 40 | static struct socket *dccp_v4_ctl_socket; | |
38 | EXPORT_SYMBOL_GPL(dccp_hashinfo); | ||
39 | 41 | ||
40 | static int dccp_v4_get_port(struct sock *sk, const unsigned short snum) | 42 | static int dccp_v4_get_port(struct sock *sk, const unsigned short snum) |
41 | { | 43 | { |
@@ -43,18 +45,6 @@ static int dccp_v4_get_port(struct sock *sk, const unsigned short snum) | |||
43 | inet_csk_bind_conflict); | 45 | inet_csk_bind_conflict); |
44 | } | 46 | } |
45 | 47 | ||
46 | static void dccp_v4_hash(struct sock *sk) | ||
47 | { | ||
48 | inet_hash(&dccp_hashinfo, sk); | ||
49 | } | ||
50 | |||
51 | void dccp_unhash(struct sock *sk) | ||
52 | { | ||
53 | inet_unhash(&dccp_hashinfo, sk); | ||
54 | } | ||
55 | |||
56 | EXPORT_SYMBOL_GPL(dccp_unhash); | ||
57 | |||
58 | int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | 48 | int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) |
59 | { | 49 | { |
60 | struct inet_sock *inet = inet_sk(sk); | 50 | struct inet_sock *inet = inet_sk(sk); |
@@ -207,11 +197,12 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk, | |||
207 | } /* else let the usual retransmit timer handle it */ | 197 | } /* else let the usual retransmit timer handle it */ |
208 | } | 198 | } |
209 | 199 | ||
210 | static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb) | 200 | static void dccp_v4_reqsk_send_ack(struct sk_buff *rxskb, |
201 | struct request_sock *req) | ||
211 | { | 202 | { |
212 | int err; | 203 | int err; |
213 | struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; | 204 | struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; |
214 | const int dccp_hdr_ack_len = sizeof(struct dccp_hdr) + | 205 | const u32 dccp_hdr_ack_len = sizeof(struct dccp_hdr) + |
215 | sizeof(struct dccp_hdr_ext) + | 206 | sizeof(struct dccp_hdr_ext) + |
216 | sizeof(struct dccp_hdr_ack_bits); | 207 | sizeof(struct dccp_hdr_ack_bits); |
217 | struct sk_buff *skb; | 208 | struct sk_buff *skb; |
@@ -219,12 +210,12 @@ static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb) | |||
219 | if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL) | 210 | if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL) |
220 | return; | 211 | return; |
221 | 212 | ||
222 | skb = alloc_skb(MAX_DCCP_HEADER + 15, GFP_ATOMIC); | 213 | skb = alloc_skb(dccp_v4_ctl_socket->sk->sk_prot->max_header, GFP_ATOMIC); |
223 | if (skb == NULL) | 214 | if (skb == NULL) |
224 | return; | 215 | return; |
225 | 216 | ||
226 | /* Reserve space for headers. */ | 217 | /* Reserve space for headers. */ |
227 | skb_reserve(skb, MAX_DCCP_HEADER); | 218 | skb_reserve(skb, dccp_v4_ctl_socket->sk->sk_prot->max_header); |
228 | 219 | ||
229 | skb->dst = dst_clone(rxskb->dst); | 220 | skb->dst = dst_clone(rxskb->dst); |
230 | 221 | ||
@@ -243,11 +234,11 @@ static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb) | |||
243 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), | 234 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), |
244 | DCCP_SKB_CB(rxskb)->dccpd_seq); | 235 | DCCP_SKB_CB(rxskb)->dccpd_seq); |
245 | 236 | ||
246 | bh_lock_sock(dccp_ctl_socket->sk); | 237 | bh_lock_sock(dccp_v4_ctl_socket->sk); |
247 | err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk, | 238 | err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk, |
248 | rxskb->nh.iph->daddr, | 239 | rxskb->nh.iph->daddr, |
249 | rxskb->nh.iph->saddr, NULL); | 240 | rxskb->nh.iph->saddr, NULL); |
250 | bh_unlock_sock(dccp_ctl_socket->sk); | 241 | bh_unlock_sock(dccp_v4_ctl_socket->sk); |
251 | 242 | ||
252 | if (err == NET_XMIT_CN || err == 0) { | 243 | if (err == NET_XMIT_CN || err == 0) { |
253 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); | 244 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); |
@@ -255,12 +246,6 @@ static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb) | |||
255 | } | 246 | } |
256 | } | 247 | } |
257 | 248 | ||
258 | static void dccp_v4_reqsk_send_ack(struct sk_buff *skb, | ||
259 | struct request_sock *req) | ||
260 | { | ||
261 | dccp_v4_ctl_send_ack(skb); | ||
262 | } | ||
263 | |||
264 | static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, | 249 | static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, |
265 | struct dst_entry *dst) | 250 | struct dst_entry *dst) |
266 | { | 251 | { |
@@ -275,7 +260,10 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, | |||
275 | skb = dccp_make_response(sk, dst, req); | 260 | skb = dccp_make_response(sk, dst, req); |
276 | if (skb != NULL) { | 261 | if (skb != NULL) { |
277 | const struct inet_request_sock *ireq = inet_rsk(req); | 262 | const struct inet_request_sock *ireq = inet_rsk(req); |
263 | struct dccp_hdr *dh = dccp_hdr(skb); | ||
278 | 264 | ||
265 | dh->dccph_checksum = dccp_v4_checksum(skb, ireq->loc_addr, | ||
266 | ireq->rmt_addr); | ||
279 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); | 267 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); |
280 | err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, | 268 | err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, |
281 | ireq->rmt_addr, | 269 | ireq->rmt_addr, |
@@ -301,7 +289,7 @@ out: | |||
301 | * check at all. A more general error queue to queue errors for later handling | 289 | * check at all. A more general error queue to queue errors for later handling |
302 | * is probably better. | 290 | * is probably better. |
303 | */ | 291 | */ |
304 | void dccp_v4_err(struct sk_buff *skb, u32 info) | 292 | static void dccp_v4_err(struct sk_buff *skb, u32 info) |
305 | { | 293 | { |
306 | const struct iphdr *iph = (struct iphdr *)skb->data; | 294 | const struct iphdr *iph = (struct iphdr *)skb->data; |
307 | const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + | 295 | const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + |
@@ -456,32 +444,6 @@ void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
456 | 444 | ||
457 | EXPORT_SYMBOL_GPL(dccp_v4_send_check); | 445 | EXPORT_SYMBOL_GPL(dccp_v4_send_check); |
458 | 446 | ||
459 | int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code) | ||
460 | { | ||
461 | struct sk_buff *skb; | ||
462 | /* | ||
463 | * FIXME: what if rebuild_header fails? | ||
464 | * Should we be doing a rebuild_header here? | ||
465 | */ | ||
466 | int err = inet_sk_rebuild_header(sk); | ||
467 | |||
468 | if (err != 0) | ||
469 | return err; | ||
470 | |||
471 | skb = dccp_make_reset(sk, sk->sk_dst_cache, code); | ||
472 | if (skb != NULL) { | ||
473 | const struct inet_sock *inet = inet_sk(sk); | ||
474 | |||
475 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); | ||
476 | err = ip_build_and_send_pkt(skb, sk, | ||
477 | inet->saddr, inet->daddr, NULL); | ||
478 | if (err == NET_XMIT_CN) | ||
479 | err = 0; | ||
480 | } | ||
481 | |||
482 | return err; | ||
483 | } | ||
484 | |||
485 | static inline u64 dccp_v4_init_sequence(const struct sock *sk, | 447 | static inline u64 dccp_v4_init_sequence(const struct sock *sk, |
486 | const struct sk_buff *skb) | 448 | const struct sk_buff *skb) |
487 | { | 449 | { |
@@ -497,9 +459,9 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
497 | struct dccp_sock dp; | 459 | struct dccp_sock dp; |
498 | struct request_sock *req; | 460 | struct request_sock *req; |
499 | struct dccp_request_sock *dreq; | 461 | struct dccp_request_sock *dreq; |
500 | const __u32 saddr = skb->nh.iph->saddr; | 462 | const __be32 saddr = skb->nh.iph->saddr; |
501 | const __u32 daddr = skb->nh.iph->daddr; | 463 | const __be32 daddr = skb->nh.iph->daddr; |
502 | const __u32 service = dccp_hdr_request(skb)->dccph_req_service; | 464 | const __be32 service = dccp_hdr_request(skb)->dccph_req_service; |
503 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | 465 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); |
504 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; | 466 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; |
505 | 467 | ||
@@ -535,7 +497,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
535 | if (req == NULL) | 497 | if (req == NULL) |
536 | goto drop; | 498 | goto drop; |
537 | 499 | ||
538 | /* FIXME: process options */ | 500 | if (dccp_parse_options(sk, skb)) |
501 | goto drop; | ||
539 | 502 | ||
540 | dccp_openreq_init(req, &dp, skb); | 503 | dccp_openreq_init(req, &dp, skb); |
541 | 504 | ||
@@ -660,8 +623,8 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | |||
660 | return sk; | 623 | return sk; |
661 | } | 624 | } |
662 | 625 | ||
663 | int dccp_v4_checksum(const struct sk_buff *skb, const u32 saddr, | 626 | int dccp_v4_checksum(const struct sk_buff *skb, const __be32 saddr, |
664 | const u32 daddr) | 627 | const __be32 daddr) |
665 | { | 628 | { |
666 | const struct dccp_hdr* dh = dccp_hdr(skb); | 629 | const struct dccp_hdr* dh = dccp_hdr(skb); |
667 | int checksum_len; | 630 | int checksum_len; |
@@ -680,8 +643,10 @@ int dccp_v4_checksum(const struct sk_buff *skb, const u32 saddr, | |||
680 | IPPROTO_DCCP, tmp); | 643 | IPPROTO_DCCP, tmp); |
681 | } | 644 | } |
682 | 645 | ||
646 | EXPORT_SYMBOL_GPL(dccp_v4_checksum); | ||
647 | |||
683 | static int dccp_v4_verify_checksum(struct sk_buff *skb, | 648 | static int dccp_v4_verify_checksum(struct sk_buff *skb, |
684 | const u32 saddr, const u32 daddr) | 649 | const __be32 saddr, const __be32 daddr) |
685 | { | 650 | { |
686 | struct dccp_hdr *dh = dccp_hdr(skb); | 651 | struct dccp_hdr *dh = dccp_hdr(skb); |
687 | int checksum_len; | 652 | int checksum_len; |
@@ -741,16 +706,17 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) | |||
741 | if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL) | 706 | if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL) |
742 | return; | 707 | return; |
743 | 708 | ||
744 | dst = dccp_v4_route_skb(dccp_ctl_socket->sk, rxskb); | 709 | dst = dccp_v4_route_skb(dccp_v4_ctl_socket->sk, rxskb); |
745 | if (dst == NULL) | 710 | if (dst == NULL) |
746 | return; | 711 | return; |
747 | 712 | ||
748 | skb = alloc_skb(MAX_DCCP_HEADER + 15, GFP_ATOMIC); | 713 | skb = alloc_skb(dccp_v4_ctl_socket->sk->sk_prot->max_header, |
714 | GFP_ATOMIC); | ||
749 | if (skb == NULL) | 715 | if (skb == NULL) |
750 | goto out; | 716 | goto out; |
751 | 717 | ||
752 | /* Reserve space for headers. */ | 718 | /* Reserve space for headers. */ |
753 | skb_reserve(skb, MAX_DCCP_HEADER); | 719 | skb_reserve(skb, dccp_v4_ctl_socket->sk->sk_prot->max_header); |
754 | skb->dst = dst_clone(dst); | 720 | skb->dst = dst_clone(dst); |
755 | 721 | ||
756 | skb->h.raw = skb_push(skb, dccp_hdr_reset_len); | 722 | skb->h.raw = skb_push(skb, dccp_hdr_reset_len); |
@@ -778,11 +744,11 @@ static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb) | |||
778 | dh->dccph_checksum = dccp_v4_checksum(skb, rxskb->nh.iph->saddr, | 744 | dh->dccph_checksum = dccp_v4_checksum(skb, rxskb->nh.iph->saddr, |
779 | rxskb->nh.iph->daddr); | 745 | rxskb->nh.iph->daddr); |
780 | 746 | ||
781 | bh_lock_sock(dccp_ctl_socket->sk); | 747 | bh_lock_sock(dccp_v4_ctl_socket->sk); |
782 | err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk, | 748 | err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk, |
783 | rxskb->nh.iph->daddr, | 749 | rxskb->nh.iph->daddr, |
784 | rxskb->nh.iph->saddr, NULL); | 750 | rxskb->nh.iph->saddr, NULL); |
785 | bh_unlock_sock(dccp_ctl_socket->sk); | 751 | bh_unlock_sock(dccp_v4_ctl_socket->sk); |
786 | 752 | ||
787 | if (err == NET_XMIT_CN || err == 0) { | 753 | if (err == NET_XMIT_CN || err == 0) { |
788 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); | 754 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); |
@@ -912,7 +878,7 @@ int dccp_invalid_packet(struct sk_buff *skb) | |||
912 | EXPORT_SYMBOL_GPL(dccp_invalid_packet); | 878 | EXPORT_SYMBOL_GPL(dccp_invalid_packet); |
913 | 879 | ||
914 | /* this is called when real data arrives */ | 880 | /* this is called when real data arrives */ |
915 | int dccp_v4_rcv(struct sk_buff *skb) | 881 | static int dccp_v4_rcv(struct sk_buff *skb) |
916 | { | 882 | { |
917 | const struct dccp_hdr *dh; | 883 | const struct dccp_hdr *dh; |
918 | struct sock *sk; | 884 | struct sock *sk; |
@@ -1019,111 +985,37 @@ do_time_wait: | |||
1019 | goto no_dccp_socket; | 985 | goto no_dccp_socket; |
1020 | } | 986 | } |
1021 | 987 | ||
1022 | struct inet_connection_sock_af_ops dccp_ipv4_af_ops = { | 988 | static struct inet_connection_sock_af_ops dccp_ipv4_af_ops = { |
1023 | .queue_xmit = ip_queue_xmit, | 989 | .queue_xmit = ip_queue_xmit, |
1024 | .send_check = dccp_v4_send_check, | 990 | .send_check = dccp_v4_send_check, |
1025 | .rebuild_header = inet_sk_rebuild_header, | 991 | .rebuild_header = inet_sk_rebuild_header, |
1026 | .conn_request = dccp_v4_conn_request, | 992 | .conn_request = dccp_v4_conn_request, |
1027 | .syn_recv_sock = dccp_v4_request_recv_sock, | 993 | .syn_recv_sock = dccp_v4_request_recv_sock, |
1028 | .net_header_len = sizeof(struct iphdr), | 994 | .net_header_len = sizeof(struct iphdr), |
1029 | .setsockopt = ip_setsockopt, | 995 | .setsockopt = ip_setsockopt, |
1030 | .getsockopt = ip_getsockopt, | 996 | .getsockopt = ip_getsockopt, |
1031 | .addr2sockaddr = inet_csk_addr2sockaddr, | 997 | .addr2sockaddr = inet_csk_addr2sockaddr, |
1032 | .sockaddr_len = sizeof(struct sockaddr_in), | 998 | .sockaddr_len = sizeof(struct sockaddr_in), |
999 | #ifdef CONFIG_COMPAT | ||
1000 | .compat_setsockopt = compat_ip_setsockopt, | ||
1001 | .compat_getsockopt = compat_ip_getsockopt, | ||
1002 | #endif | ||
1033 | }; | 1003 | }; |
1034 | 1004 | ||
1035 | int dccp_v4_init_sock(struct sock *sk) | 1005 | static int dccp_v4_init_sock(struct sock *sk) |
1036 | { | ||
1037 | struct dccp_sock *dp = dccp_sk(sk); | ||
1038 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
1039 | static int dccp_ctl_socket_init = 1; | ||
1040 | |||
1041 | dccp_options_init(&dp->dccps_options); | ||
1042 | do_gettimeofday(&dp->dccps_epoch); | ||
1043 | |||
1044 | if (dp->dccps_options.dccpo_send_ack_vector) { | ||
1045 | dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(DCCP_MAX_ACKVEC_LEN, | ||
1046 | GFP_KERNEL); | ||
1047 | if (dp->dccps_hc_rx_ackvec == NULL) | ||
1048 | return -ENOMEM; | ||
1049 | } | ||
1050 | |||
1051 | /* | ||
1052 | * FIXME: We're hardcoding the CCID, and doing this at this point makes | ||
1053 | * the listening (master) sock get CCID control blocks, which is not | ||
1054 | * necessary, but for now, to not mess with the test userspace apps, | ||
1055 | * lets leave it here, later the real solution is to do this in a | ||
1056 | * setsockopt(CCIDs-I-want/accept). -acme | ||
1057 | */ | ||
1058 | if (likely(!dccp_ctl_socket_init)) { | ||
1059 | dp->dccps_hc_rx_ccid = ccid_init(dp->dccps_options.dccpo_rx_ccid, | ||
1060 | sk); | ||
1061 | dp->dccps_hc_tx_ccid = ccid_init(dp->dccps_options.dccpo_tx_ccid, | ||
1062 | sk); | ||
1063 | if (dp->dccps_hc_rx_ccid == NULL || | ||
1064 | dp->dccps_hc_tx_ccid == NULL) { | ||
1065 | ccid_exit(dp->dccps_hc_rx_ccid, sk); | ||
1066 | ccid_exit(dp->dccps_hc_tx_ccid, sk); | ||
1067 | if (dp->dccps_options.dccpo_send_ack_vector) { | ||
1068 | dccp_ackvec_free(dp->dccps_hc_rx_ackvec); | ||
1069 | dp->dccps_hc_rx_ackvec = NULL; | ||
1070 | } | ||
1071 | dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; | ||
1072 | return -ENOMEM; | ||
1073 | } | ||
1074 | } else | ||
1075 | dccp_ctl_socket_init = 0; | ||
1076 | |||
1077 | dccp_init_xmit_timers(sk); | ||
1078 | icsk->icsk_rto = DCCP_TIMEOUT_INIT; | ||
1079 | sk->sk_state = DCCP_CLOSED; | ||
1080 | sk->sk_write_space = dccp_write_space; | ||
1081 | icsk->icsk_af_ops = &dccp_ipv4_af_ops; | ||
1082 | icsk->icsk_sync_mss = dccp_sync_mss; | ||
1083 | dp->dccps_mss_cache = 536; | ||
1084 | dp->dccps_role = DCCP_ROLE_UNDEFINED; | ||
1085 | dp->dccps_service = DCCP_SERVICE_INVALID_VALUE; | ||
1086 | |||
1087 | return 0; | ||
1088 | } | ||
1089 | |||
1090 | EXPORT_SYMBOL_GPL(dccp_v4_init_sock); | ||
1091 | |||
1092 | int dccp_v4_destroy_sock(struct sock *sk) | ||
1093 | { | 1006 | { |
1094 | struct dccp_sock *dp = dccp_sk(sk); | 1007 | static __u8 dccp_v4_ctl_sock_initialized; |
1008 | int err = dccp_init_sock(sk, dccp_v4_ctl_sock_initialized); | ||
1095 | 1009 | ||
1096 | /* | 1010 | if (err == 0) { |
1097 | * DCCP doesn't use sk_write_queue, just sk_send_head | 1011 | if (unlikely(!dccp_v4_ctl_sock_initialized)) |
1098 | * for retransmissions | 1012 | dccp_v4_ctl_sock_initialized = 1; |
1099 | */ | 1013 | inet_csk(sk)->icsk_af_ops = &dccp_ipv4_af_ops; |
1100 | if (sk->sk_send_head != NULL) { | ||
1101 | kfree_skb(sk->sk_send_head); | ||
1102 | sk->sk_send_head = NULL; | ||
1103 | } | 1014 | } |
1104 | 1015 | ||
1105 | /* Clean up a referenced DCCP bind bucket. */ | 1016 | return err; |
1106 | if (inet_csk(sk)->icsk_bind_hash != NULL) | ||
1107 | inet_put_port(&dccp_hashinfo, sk); | ||
1108 | |||
1109 | kfree(dp->dccps_service_list); | ||
1110 | dp->dccps_service_list = NULL; | ||
1111 | |||
1112 | ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk); | ||
1113 | ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk); | ||
1114 | if (dp->dccps_options.dccpo_send_ack_vector) { | ||
1115 | dccp_ackvec_free(dp->dccps_hc_rx_ackvec); | ||
1116 | dp->dccps_hc_rx_ackvec = NULL; | ||
1117 | } | ||
1118 | ccid_exit(dp->dccps_hc_rx_ccid, sk); | ||
1119 | ccid_exit(dp->dccps_hc_tx_ccid, sk); | ||
1120 | dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; | ||
1121 | |||
1122 | return 0; | ||
1123 | } | 1017 | } |
1124 | 1018 | ||
1125 | EXPORT_SYMBOL_GPL(dccp_v4_destroy_sock); | ||
1126 | |||
1127 | static void dccp_v4_reqsk_destructor(struct request_sock *req) | 1019 | static void dccp_v4_reqsk_destructor(struct request_sock *req) |
1128 | { | 1020 | { |
1129 | kfree(inet_rsk(req)->opt); | 1021 | kfree(inet_rsk(req)->opt); |
@@ -1142,7 +1034,7 @@ static struct timewait_sock_ops dccp_timewait_sock_ops = { | |||
1142 | .twsk_obj_size = sizeof(struct inet_timewait_sock), | 1034 | .twsk_obj_size = sizeof(struct inet_timewait_sock), |
1143 | }; | 1035 | }; |
1144 | 1036 | ||
1145 | struct proto dccp_prot = { | 1037 | static struct proto dccp_v4_prot = { |
1146 | .name = "DCCP", | 1038 | .name = "DCCP", |
1147 | .owner = THIS_MODULE, | 1039 | .owner = THIS_MODULE, |
1148 | .close = dccp_close, | 1040 | .close = dccp_close, |
@@ -1155,17 +1047,110 @@ struct proto dccp_prot = { | |||
1155 | .sendmsg = dccp_sendmsg, | 1047 | .sendmsg = dccp_sendmsg, |
1156 | .recvmsg = dccp_recvmsg, | 1048 | .recvmsg = dccp_recvmsg, |
1157 | .backlog_rcv = dccp_v4_do_rcv, | 1049 | .backlog_rcv = dccp_v4_do_rcv, |
1158 | .hash = dccp_v4_hash, | 1050 | .hash = dccp_hash, |
1159 | .unhash = dccp_unhash, | 1051 | .unhash = dccp_unhash, |
1160 | .accept = inet_csk_accept, | 1052 | .accept = inet_csk_accept, |
1161 | .get_port = dccp_v4_get_port, | 1053 | .get_port = dccp_v4_get_port, |
1162 | .shutdown = dccp_shutdown, | 1054 | .shutdown = dccp_shutdown, |
1163 | .destroy = dccp_v4_destroy_sock, | 1055 | .destroy = dccp_destroy_sock, |
1164 | .orphan_count = &dccp_orphan_count, | 1056 | .orphan_count = &dccp_orphan_count, |
1165 | .max_header = MAX_DCCP_HEADER, | 1057 | .max_header = MAX_DCCP_HEADER, |
1166 | .obj_size = sizeof(struct dccp_sock), | 1058 | .obj_size = sizeof(struct dccp_sock), |
1167 | .rsk_prot = &dccp_request_sock_ops, | 1059 | .rsk_prot = &dccp_request_sock_ops, |
1168 | .twsk_prot = &dccp_timewait_sock_ops, | 1060 | .twsk_prot = &dccp_timewait_sock_ops, |
1061 | #ifdef CONFIG_COMPAT | ||
1062 | .compat_setsockopt = compat_dccp_setsockopt, | ||
1063 | .compat_getsockopt = compat_dccp_getsockopt, | ||
1064 | #endif | ||
1065 | }; | ||
1066 | |||
1067 | static struct net_protocol dccp_v4_protocol = { | ||
1068 | .handler = dccp_v4_rcv, | ||
1069 | .err_handler = dccp_v4_err, | ||
1070 | .no_policy = 1, | ||
1071 | }; | ||
1072 | |||
1073 | static const struct proto_ops inet_dccp_ops = { | ||
1074 | .family = PF_INET, | ||
1075 | .owner = THIS_MODULE, | ||
1076 | .release = inet_release, | ||
1077 | .bind = inet_bind, | ||
1078 | .connect = inet_stream_connect, | ||
1079 | .socketpair = sock_no_socketpair, | ||
1080 | .accept = inet_accept, | ||
1081 | .getname = inet_getname, | ||
1082 | /* FIXME: work on tcp_poll to rename it to inet_csk_poll */ | ||
1083 | .poll = dccp_poll, | ||
1084 | .ioctl = inet_ioctl, | ||
1085 | /* FIXME: work on inet_listen to rename it to sock_common_listen */ | ||
1086 | .listen = inet_dccp_listen, | ||
1087 | .shutdown = inet_shutdown, | ||
1088 | .setsockopt = sock_common_setsockopt, | ||
1089 | .getsockopt = sock_common_getsockopt, | ||
1090 | .sendmsg = inet_sendmsg, | ||
1091 | .recvmsg = sock_common_recvmsg, | ||
1092 | .mmap = sock_no_mmap, | ||
1093 | .sendpage = sock_no_sendpage, | ||
1094 | #ifdef CONFIG_COMPAT | ||
1095 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
1096 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
1097 | #endif | ||
1169 | }; | 1098 | }; |
1170 | 1099 | ||
1171 | EXPORT_SYMBOL_GPL(dccp_prot); | 1100 | static struct inet_protosw dccp_v4_protosw = { |
1101 | .type = SOCK_DCCP, | ||
1102 | .protocol = IPPROTO_DCCP, | ||
1103 | .prot = &dccp_v4_prot, | ||
1104 | .ops = &inet_dccp_ops, | ||
1105 | .capability = -1, | ||
1106 | .no_check = 0, | ||
1107 | .flags = INET_PROTOSW_ICSK, | ||
1108 | }; | ||
1109 | |||
1110 | static int __init dccp_v4_init(void) | ||
1111 | { | ||
1112 | int err = proto_register(&dccp_v4_prot, 1); | ||
1113 | |||
1114 | if (err != 0) | ||
1115 | goto out; | ||
1116 | |||
1117 | err = inet_add_protocol(&dccp_v4_protocol, IPPROTO_DCCP); | ||
1118 | if (err != 0) | ||
1119 | goto out_proto_unregister; | ||
1120 | |||
1121 | inet_register_protosw(&dccp_v4_protosw); | ||
1122 | |||
1123 | err = inet_csk_ctl_sock_create(&dccp_v4_ctl_socket, PF_INET, | ||
1124 | SOCK_DCCP, IPPROTO_DCCP); | ||
1125 | if (err) | ||
1126 | goto out_unregister_protosw; | ||
1127 | out: | ||
1128 | return err; | ||
1129 | out_unregister_protosw: | ||
1130 | inet_unregister_protosw(&dccp_v4_protosw); | ||
1131 | inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); | ||
1132 | out_proto_unregister: | ||
1133 | proto_unregister(&dccp_v4_prot); | ||
1134 | goto out; | ||
1135 | } | ||
1136 | |||
1137 | static void __exit dccp_v4_exit(void) | ||
1138 | { | ||
1139 | inet_unregister_protosw(&dccp_v4_protosw); | ||
1140 | inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); | ||
1141 | proto_unregister(&dccp_v4_prot); | ||
1142 | } | ||
1143 | |||
1144 | module_init(dccp_v4_init); | ||
1145 | module_exit(dccp_v4_exit); | ||
1146 | |||
1147 | /* | ||
1148 | * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33) | ||
1149 | * values directly, Also cover the case where the protocol is not specified, | ||
1150 | * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP | ||
1151 | */ | ||
1152 | MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6"); | ||
1153 | MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6"); | ||
1154 | MODULE_LICENSE("GPL"); | ||
1155 | MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>"); | ||
1156 | MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol"); | ||
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 80c4d048869e..65e2ab0886e6 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * DCCP over IPv6 | 2 | * DCCP over IPv6 |
3 | * Linux INET6 implementation | 3 | * Linux INET6 implementation |
4 | * | 4 | * |
5 | * Based on net/dccp6/ipv6.c | 5 | * Based on net/dccp6/ipv6.c |
6 | * | 6 | * |
@@ -33,6 +33,9 @@ | |||
33 | #include "dccp.h" | 33 | #include "dccp.h" |
34 | #include "ipv6.h" | 34 | #include "ipv6.h" |
35 | 35 | ||
36 | /* Socket used for sending RSTs and ACKs */ | ||
37 | static struct socket *dccp_v6_ctl_socket; | ||
38 | |||
36 | static void dccp_v6_ctl_send_reset(struct sk_buff *skb); | 39 | static void dccp_v6_ctl_send_reset(struct sk_buff *skb); |
37 | static void dccp_v6_reqsk_send_ack(struct sk_buff *skb, | 40 | static void dccp_v6_reqsk_send_ack(struct sk_buff *skb, |
38 | struct request_sock *req); | 41 | struct request_sock *req); |
@@ -53,7 +56,7 @@ static void dccp_v6_hash(struct sock *sk) | |||
53 | { | 56 | { |
54 | if (sk->sk_state != DCCP_CLOSED) { | 57 | if (sk->sk_state != DCCP_CLOSED) { |
55 | if (inet_csk(sk)->icsk_af_ops == &dccp_ipv6_mapped) { | 58 | if (inet_csk(sk)->icsk_af_ops == &dccp_ipv6_mapped) { |
56 | dccp_prot.hash(sk); | 59 | dccp_hash(sk); |
57 | return; | 60 | return; |
58 | } | 61 | } |
59 | local_bh_disable(); | 62 | local_bh_disable(); |
@@ -63,8 +66,8 @@ static void dccp_v6_hash(struct sock *sk) | |||
63 | } | 66 | } |
64 | 67 | ||
65 | static inline u16 dccp_v6_check(struct dccp_hdr *dh, int len, | 68 | static inline u16 dccp_v6_check(struct dccp_hdr *dh, int len, |
66 | struct in6_addr *saddr, | 69 | struct in6_addr *saddr, |
67 | struct in6_addr *daddr, | 70 | struct in6_addr *daddr, |
68 | unsigned long base) | 71 | unsigned long base) |
69 | { | 72 | { |
70 | return csum_ipv6_magic(saddr, daddr, len, IPPROTO_DCCP, base); | 73 | return csum_ipv6_magic(saddr, daddr, len, IPPROTO_DCCP, base); |
@@ -79,17 +82,17 @@ static __u32 dccp_v6_init_sequence(struct sock *sk, struct sk_buff *skb) | |||
79 | skb->nh.ipv6h->saddr.s6_addr32, | 82 | skb->nh.ipv6h->saddr.s6_addr32, |
80 | dh->dccph_dport, | 83 | dh->dccph_dport, |
81 | dh->dccph_sport); | 84 | dh->dccph_sport); |
82 | else | 85 | |
83 | return secure_dccp_sequence_number(skb->nh.iph->daddr, | 86 | return secure_dccp_sequence_number(skb->nh.iph->daddr, |
84 | skb->nh.iph->saddr, | 87 | skb->nh.iph->saddr, |
85 | dh->dccph_dport, | 88 | dh->dccph_dport, |
86 | dh->dccph_sport); | 89 | dh->dccph_sport); |
87 | } | 90 | } |
88 | 91 | ||
89 | static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | 92 | static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, |
90 | int addr_len) | 93 | int addr_len) |
91 | { | 94 | { |
92 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; | 95 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr; |
93 | struct inet_connection_sock *icsk = inet_csk(sk); | 96 | struct inet_connection_sock *icsk = inet_csk(sk); |
94 | struct inet_sock *inet = inet_sk(sk); | 97 | struct inet_sock *inet = inet_sk(sk); |
95 | struct ipv6_pinfo *np = inet6_sk(sk); | 98 | struct ipv6_pinfo *np = inet6_sk(sk); |
@@ -102,10 +105,10 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
102 | 105 | ||
103 | dp->dccps_role = DCCP_ROLE_CLIENT; | 106 | dp->dccps_role = DCCP_ROLE_CLIENT; |
104 | 107 | ||
105 | if (addr_len < SIN6_LEN_RFC2133) | 108 | if (addr_len < SIN6_LEN_RFC2133) |
106 | return -EINVAL; | 109 | return -EINVAL; |
107 | 110 | ||
108 | if (usin->sin6_family != AF_INET6) | 111 | if (usin->sin6_family != AF_INET6) |
109 | return -EAFNOSUPPORT; | 112 | return -EAFNOSUPPORT; |
110 | 113 | ||
111 | memset(&fl, 0, sizeof(fl)); | 114 | memset(&fl, 0, sizeof(fl)); |
@@ -122,17 +125,15 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
122 | fl6_sock_release(flowlabel); | 125 | fl6_sock_release(flowlabel); |
123 | } | 126 | } |
124 | } | 127 | } |
125 | |||
126 | /* | 128 | /* |
127 | * connect() to INADDR_ANY means loopback (BSD'ism). | 129 | * connect() to INADDR_ANY means loopback (BSD'ism). |
128 | */ | 130 | */ |
129 | 131 | if (ipv6_addr_any(&usin->sin6_addr)) | |
130 | if (ipv6_addr_any(&usin->sin6_addr)) | 132 | usin->sin6_addr.s6_addr[15] = 1; |
131 | usin->sin6_addr.s6_addr[15] = 0x1; | ||
132 | 133 | ||
133 | addr_type = ipv6_addr_type(&usin->sin6_addr); | 134 | addr_type = ipv6_addr_type(&usin->sin6_addr); |
134 | 135 | ||
135 | if(addr_type & IPV6_ADDR_MULTICAST) | 136 | if (addr_type & IPV6_ADDR_MULTICAST) |
136 | return -ENETUNREACH; | 137 | return -ENETUNREACH; |
137 | 138 | ||
138 | if (addr_type & IPV6_ADDR_LINKLOCAL) { | 139 | if (addr_type & IPV6_ADDR_LINKLOCAL) { |
@@ -157,9 +158,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
157 | np->flow_label = fl.fl6_flowlabel; | 158 | np->flow_label = fl.fl6_flowlabel; |
158 | 159 | ||
159 | /* | 160 | /* |
160 | * DCCP over IPv4 | 161 | * DCCP over IPv4 |
161 | */ | 162 | */ |
162 | |||
163 | if (addr_type == IPV6_ADDR_MAPPED) { | 163 | if (addr_type == IPV6_ADDR_MAPPED) { |
164 | u32 exthdrlen = icsk->icsk_ext_hdr_len; | 164 | u32 exthdrlen = icsk->icsk_ext_hdr_len; |
165 | struct sockaddr_in sin; | 165 | struct sockaddr_in sin; |
@@ -177,7 +177,6 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
177 | sk->sk_backlog_rcv = dccp_v4_do_rcv; | 177 | sk->sk_backlog_rcv = dccp_v4_do_rcv; |
178 | 178 | ||
179 | err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin)); | 179 | err = dccp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin)); |
180 | |||
181 | if (err) { | 180 | if (err) { |
182 | icsk->icsk_ext_hdr_len = exthdrlen; | 181 | icsk->icsk_ext_hdr_len = exthdrlen; |
183 | icsk->icsk_af_ops = &dccp_ipv6_af_ops; | 182 | icsk->icsk_af_ops = &dccp_ipv6_af_ops; |
@@ -203,8 +202,9 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
203 | fl.fl_ip_dport = usin->sin6_port; | 202 | fl.fl_ip_dport = usin->sin6_port; |
204 | fl.fl_ip_sport = inet->sport; | 203 | fl.fl_ip_sport = inet->sport; |
205 | 204 | ||
206 | if (np->opt && np->opt->srcrt) { | 205 | if (np->opt != NULL && np->opt->srcrt != NULL) { |
207 | struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; | 206 | const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; |
207 | |||
208 | ipv6_addr_copy(&final, &fl.fl6_dst); | 208 | ipv6_addr_copy(&final, &fl.fl6_dst); |
209 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | 209 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); |
210 | final_p = &final; | 210 | final_p = &final; |
@@ -213,10 +213,12 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
213 | err = ip6_dst_lookup(sk, &dst, &fl); | 213 | err = ip6_dst_lookup(sk, &dst, &fl); |
214 | if (err) | 214 | if (err) |
215 | goto failure; | 215 | goto failure; |
216 | |||
216 | if (final_p) | 217 | if (final_p) |
217 | ipv6_addr_copy(&fl.fl6_dst, final_p); | 218 | ipv6_addr_copy(&fl.fl6_dst, final_p); |
218 | 219 | ||
219 | if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) | 220 | err = xfrm_lookup(&dst, &fl, sk, 0); |
221 | if (err < 0) | ||
220 | goto failure; | 222 | goto failure; |
221 | 223 | ||
222 | if (saddr == NULL) { | 224 | if (saddr == NULL) { |
@@ -231,7 +233,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
231 | ip6_dst_store(sk, dst, NULL); | 233 | ip6_dst_store(sk, dst, NULL); |
232 | 234 | ||
233 | icsk->icsk_ext_hdr_len = 0; | 235 | icsk->icsk_ext_hdr_len = 0; |
234 | if (np->opt) | 236 | if (np->opt != NULL) |
235 | icsk->icsk_ext_hdr_len = (np->opt->opt_flen + | 237 | icsk->icsk_ext_hdr_len = (np->opt->opt_flen + |
236 | np->opt->opt_nflen); | 238 | np->opt->opt_nflen); |
237 | 239 | ||
@@ -264,7 +266,7 @@ failure: | |||
264 | } | 266 | } |
265 | 267 | ||
266 | static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 268 | static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
267 | int type, int code, int offset, __u32 info) | 269 | int type, int code, int offset, __be32 info) |
268 | { | 270 | { |
269 | struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data; | 271 | struct ipv6hdr *hdr = (struct ipv6hdr *)skb->data; |
270 | const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset); | 272 | const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + offset); |
@@ -305,7 +307,6 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
305 | 307 | ||
306 | /* icmp should have updated the destination cache entry */ | 308 | /* icmp should have updated the destination cache entry */ |
307 | dst = __sk_dst_check(sk, np->dst_cookie); | 309 | dst = __sk_dst_check(sk, np->dst_cookie); |
308 | |||
309 | if (dst == NULL) { | 310 | if (dst == NULL) { |
310 | struct inet_sock *inet = inet_sk(sk); | 311 | struct inet_sock *inet = inet_sk(sk); |
311 | struct flowi fl; | 312 | struct flowi fl; |
@@ -322,16 +323,17 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
322 | fl.fl_ip_dport = inet->dport; | 323 | fl.fl_ip_dport = inet->dport; |
323 | fl.fl_ip_sport = inet->sport; | 324 | fl.fl_ip_sport = inet->sport; |
324 | 325 | ||
325 | if ((err = ip6_dst_lookup(sk, &dst, &fl))) { | 326 | err = ip6_dst_lookup(sk, &dst, &fl); |
327 | if (err) { | ||
326 | sk->sk_err_soft = -err; | 328 | sk->sk_err_soft = -err; |
327 | goto out; | 329 | goto out; |
328 | } | 330 | } |
329 | 331 | ||
330 | if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) { | 332 | err = xfrm_lookup(&dst, &fl, sk, 0); |
333 | if (err < 0) { | ||
331 | sk->sk_err_soft = -err; | 334 | sk->sk_err_soft = -err; |
332 | goto out; | 335 | goto out; |
333 | } | 336 | } |
334 | |||
335 | } else | 337 | } else |
336 | dst_hold(dst); | 338 | dst_hold(dst); |
337 | 339 | ||
@@ -355,11 +357,12 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
355 | req = inet6_csk_search_req(sk, &prev, dh->dccph_dport, | 357 | req = inet6_csk_search_req(sk, &prev, dh->dccph_dport, |
356 | &hdr->daddr, &hdr->saddr, | 358 | &hdr->daddr, &hdr->saddr, |
357 | inet6_iif(skb)); | 359 | inet6_iif(skb)); |
358 | if (!req) | 360 | if (req == NULL) |
359 | goto out; | 361 | goto out; |
360 | 362 | ||
361 | /* ICMPs are not backlogged, hence we cannot get | 363 | /* |
362 | * an established socket here. | 364 | * ICMPs are not backlogged, hence we cannot get an established |
365 | * socket here. | ||
363 | */ | 366 | */ |
364 | BUG_TRAP(req->sk == NULL); | 367 | BUG_TRAP(req->sk == NULL); |
365 | 368 | ||
@@ -373,7 +376,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
373 | 376 | ||
374 | case DCCP_REQUESTING: | 377 | case DCCP_REQUESTING: |
375 | case DCCP_RESPOND: /* Cannot happen. | 378 | case DCCP_RESPOND: /* Cannot happen. |
376 | It can, it SYNs are crossed. --ANK */ | 379 | It can, it SYNs are crossed. --ANK */ |
377 | if (!sock_owned_by_user(sk)) { | 380 | if (!sock_owned_by_user(sk)) { |
378 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); | 381 | DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); |
379 | sk->sk_err = err; | 382 | sk->sk_err = err; |
@@ -382,7 +385,6 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
382 | * (see connect in sock.c) | 385 | * (see connect in sock.c) |
383 | */ | 386 | */ |
384 | sk->sk_error_report(sk); | 387 | sk->sk_error_report(sk); |
385 | |||
386 | dccp_done(sk); | 388 | dccp_done(sk); |
387 | } else | 389 | } else |
388 | sk->sk_err_soft = err; | 390 | sk->sk_err_soft = err; |
@@ -428,14 +430,16 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, | |||
428 | ireq6->pktopts) { | 430 | ireq6->pktopts) { |
429 | struct sk_buff *pktopts = ireq6->pktopts; | 431 | struct sk_buff *pktopts = ireq6->pktopts; |
430 | struct inet6_skb_parm *rxopt = IP6CB(pktopts); | 432 | struct inet6_skb_parm *rxopt = IP6CB(pktopts); |
433 | |||
431 | if (rxopt->srcrt) | 434 | if (rxopt->srcrt) |
432 | opt = ipv6_invert_rthdr(sk, | 435 | opt = ipv6_invert_rthdr(sk, |
433 | (struct ipv6_rt_hdr *)(pktopts->nh.raw + | 436 | (struct ipv6_rt_hdr *)(pktopts->nh.raw + |
434 | rxopt->srcrt)); | 437 | rxopt->srcrt)); |
435 | } | 438 | } |
436 | 439 | ||
437 | if (opt && opt->srcrt) { | 440 | if (opt != NULL && opt->srcrt != NULL) { |
438 | struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt; | 441 | const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt; |
442 | |||
439 | ipv6_addr_copy(&final, &fl.fl6_dst); | 443 | ipv6_addr_copy(&final, &fl.fl6_dst); |
440 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | 444 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); |
441 | final_p = &final; | 445 | final_p = &final; |
@@ -444,15 +448,19 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, | |||
444 | err = ip6_dst_lookup(sk, &dst, &fl); | 448 | err = ip6_dst_lookup(sk, &dst, &fl); |
445 | if (err) | 449 | if (err) |
446 | goto done; | 450 | goto done; |
451 | |||
447 | if (final_p) | 452 | if (final_p) |
448 | ipv6_addr_copy(&fl.fl6_dst, final_p); | 453 | ipv6_addr_copy(&fl.fl6_dst, final_p); |
449 | if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) | 454 | |
455 | err = xfrm_lookup(&dst, &fl, sk, 0); | ||
456 | if (err < 0) | ||
450 | goto done; | 457 | goto done; |
451 | } | 458 | } |
452 | 459 | ||
453 | skb = dccp_make_response(sk, dst, req); | 460 | skb = dccp_make_response(sk, dst, req); |
454 | if (skb != NULL) { | 461 | if (skb != NULL) { |
455 | struct dccp_hdr *dh = dccp_hdr(skb); | 462 | struct dccp_hdr *dh = dccp_hdr(skb); |
463 | |||
456 | dh->dccph_checksum = dccp_v6_check(dh, skb->len, | 464 | dh->dccph_checksum = dccp_v6_check(dh, skb->len, |
457 | &ireq6->loc_addr, | 465 | &ireq6->loc_addr, |
458 | &ireq6->rmt_addr, | 466 | &ireq6->rmt_addr, |
@@ -466,7 +474,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, | |||
466 | } | 474 | } |
467 | 475 | ||
468 | done: | 476 | done: |
469 | if (opt && opt != np->opt) | 477 | if (opt != NULL && opt != np->opt) |
470 | sock_kfree_s(sk, opt, opt->tot_len); | 478 | sock_kfree_s(sk, opt, opt->tot_len); |
471 | dst_release(dst); | 479 | dst_release(dst); |
472 | return err; | 480 | return err; |
@@ -497,7 +505,7 @@ static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
497 | struct dccp_hdr *dh = dccp_hdr(skb); | 505 | struct dccp_hdr *dh = dccp_hdr(skb); |
498 | 506 | ||
499 | dh->dccph_checksum = csum_ipv6_magic(&np->saddr, &np->daddr, | 507 | dh->dccph_checksum = csum_ipv6_magic(&np->saddr, &np->daddr, |
500 | len, IPPROTO_DCCP, | 508 | len, IPPROTO_DCCP, |
501 | csum_partial((char *)dh, | 509 | csum_partial((char *)dh, |
502 | dh->dccph_doff << 2, | 510 | dh->dccph_doff << 2, |
503 | skb->csum)); | 511 | skb->csum)); |
@@ -505,8 +513,8 @@ static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
505 | 513 | ||
506 | static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) | 514 | static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) |
507 | { | 515 | { |
508 | struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; | 516 | struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; |
509 | const int dccp_hdr_reset_len = sizeof(struct dccp_hdr) + | 517 | const u32 dccp_hdr_reset_len = sizeof(struct dccp_hdr) + |
510 | sizeof(struct dccp_hdr_ext) + | 518 | sizeof(struct dccp_hdr_ext) + |
511 | sizeof(struct dccp_hdr_reset); | 519 | sizeof(struct dccp_hdr_reset); |
512 | struct sk_buff *skb; | 520 | struct sk_buff *skb; |
@@ -517,20 +525,14 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) | |||
517 | return; | 525 | return; |
518 | 526 | ||
519 | if (!ipv6_unicast_destination(rxskb)) | 527 | if (!ipv6_unicast_destination(rxskb)) |
520 | return; | 528 | return; |
521 | |||
522 | /* | ||
523 | * We need to grab some memory, and put together an RST, | ||
524 | * and then put it into the queue to be sent. | ||
525 | */ | ||
526 | 529 | ||
527 | skb = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + | 530 | skb = alloc_skb(dccp_v6_ctl_socket->sk->sk_prot->max_header, |
528 | dccp_hdr_reset_len, GFP_ATOMIC); | 531 | GFP_ATOMIC); |
529 | if (skb == NULL) | 532 | if (skb == NULL) |
530 | return; | 533 | return; |
531 | 534 | ||
532 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr) + | 535 | skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header); |
533 | dccp_hdr_reset_len); | ||
534 | 536 | ||
535 | skb->h.raw = skb_push(skb, dccp_hdr_reset_len); | 537 | skb->h.raw = skb_push(skb, dccp_hdr_reset_len); |
536 | dh = dccp_hdr(skb); | 538 | dh = dccp_hdr(skb); |
@@ -568,7 +570,7 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) | |||
568 | /* sk = NULL, but it is safe for now. RST socket required. */ | 570 | /* sk = NULL, but it is safe for now. RST socket required. */ |
569 | if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { | 571 | if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { |
570 | if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { | 572 | if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { |
571 | ip6_xmit(NULL, skb, &fl, NULL, 0); | 573 | ip6_xmit(dccp_v6_ctl_socket->sk, skb, &fl, NULL, 0); |
572 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); | 574 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); |
573 | DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS); | 575 | DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS); |
574 | return; | 576 | return; |
@@ -578,22 +580,22 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb) | |||
578 | kfree_skb(skb); | 580 | kfree_skb(skb); |
579 | } | 581 | } |
580 | 582 | ||
581 | static void dccp_v6_ctl_send_ack(struct sk_buff *rxskb) | 583 | static void dccp_v6_reqsk_send_ack(struct sk_buff *rxskb, |
584 | struct request_sock *req) | ||
582 | { | 585 | { |
583 | struct flowi fl; | 586 | struct flowi fl; |
584 | struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; | 587 | struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh; |
585 | const int dccp_hdr_ack_len = sizeof(struct dccp_hdr) + | 588 | const u32 dccp_hdr_ack_len = sizeof(struct dccp_hdr) + |
586 | sizeof(struct dccp_hdr_ext) + | 589 | sizeof(struct dccp_hdr_ext) + |
587 | sizeof(struct dccp_hdr_ack_bits); | 590 | sizeof(struct dccp_hdr_ack_bits); |
588 | struct sk_buff *skb; | 591 | struct sk_buff *skb; |
589 | 592 | ||
590 | skb = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + | 593 | skb = alloc_skb(dccp_v6_ctl_socket->sk->sk_prot->max_header, |
591 | dccp_hdr_ack_len, GFP_ATOMIC); | 594 | GFP_ATOMIC); |
592 | if (skb == NULL) | 595 | if (skb == NULL) |
593 | return; | 596 | return; |
594 | 597 | ||
595 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr) + | 598 | skb_reserve(skb, dccp_v6_ctl_socket->sk->sk_prot->max_header); |
596 | dccp_hdr_ack_len); | ||
597 | 599 | ||
598 | skb->h.raw = skb_push(skb, dccp_hdr_ack_len); | 600 | skb->h.raw = skb_push(skb, dccp_hdr_ack_len); |
599 | dh = dccp_hdr(skb); | 601 | dh = dccp_hdr(skb); |
@@ -605,7 +607,7 @@ static void dccp_v6_ctl_send_ack(struct sk_buff *rxskb) | |||
605 | dh->dccph_dport = rxdh->dccph_sport; | 607 | dh->dccph_dport = rxdh->dccph_sport; |
606 | dh->dccph_doff = dccp_hdr_ack_len / 4; | 608 | dh->dccph_doff = dccp_hdr_ack_len / 4; |
607 | dh->dccph_x = 1; | 609 | dh->dccph_x = 1; |
608 | 610 | ||
609 | dccp_hdr_set_seq(dh, DCCP_SKB_CB(rxskb)->dccpd_ack_seq); | 611 | dccp_hdr_set_seq(dh, DCCP_SKB_CB(rxskb)->dccpd_ack_seq); |
610 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), | 612 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), |
611 | DCCP_SKB_CB(rxskb)->dccpd_seq); | 613 | DCCP_SKB_CB(rxskb)->dccpd_seq); |
@@ -623,7 +625,7 @@ static void dccp_v6_ctl_send_ack(struct sk_buff *rxskb) | |||
623 | 625 | ||
624 | if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { | 626 | if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { |
625 | if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { | 627 | if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { |
626 | ip6_xmit(NULL, skb, &fl, NULL, 0); | 628 | ip6_xmit(dccp_v6_ctl_socket->sk, skb, &fl, NULL, 0); |
627 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); | 629 | DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); |
628 | return; | 630 | return; |
629 | } | 631 | } |
@@ -632,12 +634,6 @@ static void dccp_v6_ctl_send_ack(struct sk_buff *rxskb) | |||
632 | kfree_skb(skb); | 634 | kfree_skb(skb); |
633 | } | 635 | } |
634 | 636 | ||
635 | static void dccp_v6_reqsk_send_ack(struct sk_buff *skb, | ||
636 | struct request_sock *req) | ||
637 | { | ||
638 | dccp_v6_ctl_send_ack(skb); | ||
639 | } | ||
640 | |||
641 | static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) | 637 | static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) |
642 | { | 638 | { |
643 | const struct dccp_hdr *dh = dccp_hdr(skb); | 639 | const struct dccp_hdr *dh = dccp_hdr(skb); |
@@ -657,7 +653,6 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) | |||
657 | &iph->saddr, dh->dccph_sport, | 653 | &iph->saddr, dh->dccph_sport, |
658 | &iph->daddr, ntohs(dh->dccph_dport), | 654 | &iph->daddr, ntohs(dh->dccph_dport), |
659 | inet6_iif(skb)); | 655 | inet6_iif(skb)); |
660 | |||
661 | if (nsk != NULL) { | 656 | if (nsk != NULL) { |
662 | if (nsk->sk_state != DCCP_TIME_WAIT) { | 657 | if (nsk->sk_state != DCCP_TIME_WAIT) { |
663 | bh_lock_sock(nsk); | 658 | bh_lock_sock(nsk); |
@@ -678,7 +673,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
678 | struct dccp_request_sock *dreq; | 673 | struct dccp_request_sock *dreq; |
679 | struct inet6_request_sock *ireq6; | 674 | struct inet6_request_sock *ireq6; |
680 | struct ipv6_pinfo *np = inet6_sk(sk); | 675 | struct ipv6_pinfo *np = inet6_sk(sk); |
681 | const __u32 service = dccp_hdr_request(skb)->dccph_req_service; | 676 | const __be32 service = dccp_hdr_request(skb)->dccph_req_service; |
682 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | 677 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); |
683 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; | 678 | __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; |
684 | 679 | ||
@@ -686,17 +681,17 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
686 | return dccp_v4_conn_request(sk, skb); | 681 | return dccp_v4_conn_request(sk, skb); |
687 | 682 | ||
688 | if (!ipv6_unicast_destination(skb)) | 683 | if (!ipv6_unicast_destination(skb)) |
689 | goto drop; | 684 | goto drop; |
690 | 685 | ||
691 | if (dccp_bad_service_code(sk, service)) { | 686 | if (dccp_bad_service_code(sk, service)) { |
692 | reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; | 687 | reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; |
693 | goto drop; | 688 | goto drop; |
694 | } | 689 | } |
695 | /* | 690 | /* |
696 | * There are no SYN attacks on IPv6, yet... | 691 | * There are no SYN attacks on IPv6, yet... |
697 | */ | 692 | */ |
698 | if (inet_csk_reqsk_queue_is_full(sk)) | 693 | if (inet_csk_reqsk_queue_is_full(sk)) |
699 | goto drop; | 694 | goto drop; |
700 | 695 | ||
701 | if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) | 696 | if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) |
702 | goto drop; | 697 | goto drop; |
@@ -730,7 +725,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
730 | ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL) | 725 | ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL) |
731 | ireq6->iif = inet6_iif(skb); | 726 | ireq6->iif = inet6_iif(skb); |
732 | 727 | ||
733 | /* | 728 | /* |
734 | * Step 3: Process LISTEN state | 729 | * Step 3: Process LISTEN state |
735 | * | 730 | * |
736 | * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie | 731 | * Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookie |
@@ -774,9 +769,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
774 | /* | 769 | /* |
775 | * v6 mapped | 770 | * v6 mapped |
776 | */ | 771 | */ |
777 | |||
778 | newsk = dccp_v4_request_recv_sock(sk, skb, req, dst); | 772 | newsk = dccp_v4_request_recv_sock(sk, skb, req, dst); |
779 | if (newsk == NULL) | 773 | if (newsk == NULL) |
780 | return NULL; | 774 | return NULL; |
781 | 775 | ||
782 | newdp6 = (struct dccp6_sock *)newsk; | 776 | newdp6 = (struct dccp6_sock *)newsk; |
@@ -822,9 +816,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
822 | if (sk_acceptq_is_full(sk)) | 816 | if (sk_acceptq_is_full(sk)) |
823 | goto out_overflow; | 817 | goto out_overflow; |
824 | 818 | ||
825 | if (np->rxopt.bits.osrcrt == 2 && | 819 | if (np->rxopt.bits.osrcrt == 2 && opt == NULL && ireq6->pktopts) { |
826 | opt == NULL && ireq6->pktopts) { | 820 | const struct inet6_skb_parm *rxopt = IP6CB(ireq6->pktopts); |
827 | struct inet6_skb_parm *rxopt = IP6CB(ireq6->pktopts); | 821 | |
828 | if (rxopt->srcrt) | 822 | if (rxopt->srcrt) |
829 | opt = ipv6_invert_rthdr(sk, | 823 | opt = ipv6_invert_rthdr(sk, |
830 | (struct ipv6_rt_hdr *)(ireq6->pktopts->nh.raw + | 824 | (struct ipv6_rt_hdr *)(ireq6->pktopts->nh.raw + |
@@ -838,8 +832,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
838 | memset(&fl, 0, sizeof(fl)); | 832 | memset(&fl, 0, sizeof(fl)); |
839 | fl.proto = IPPROTO_DCCP; | 833 | fl.proto = IPPROTO_DCCP; |
840 | ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); | 834 | ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); |
841 | if (opt && opt->srcrt) { | 835 | if (opt != NULL && opt->srcrt != NULL) { |
842 | struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; | 836 | const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt; |
837 | |||
843 | ipv6_addr_copy(&final, &fl.fl6_dst); | 838 | ipv6_addr_copy(&final, &fl.fl6_dst); |
844 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); | 839 | ipv6_addr_copy(&fl.fl6_dst, rt0->addr); |
845 | final_p = &final; | 840 | final_p = &final; |
@@ -857,7 +852,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
857 | 852 | ||
858 | if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0) | 853 | if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0) |
859 | goto out; | 854 | goto out; |
860 | } | 855 | } |
861 | 856 | ||
862 | newsk = dccp_create_openreq_child(sk, req, skb); | 857 | newsk = dccp_create_openreq_child(sk, req, skb); |
863 | if (newsk == NULL) | 858 | if (newsk == NULL) |
@@ -870,9 +865,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
870 | */ | 865 | */ |
871 | 866 | ||
872 | ip6_dst_store(newsk, dst, NULL); | 867 | ip6_dst_store(newsk, dst, NULL); |
873 | newsk->sk_route_caps = dst->dev->features & | 868 | newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM | |
874 | ~(NETIF_F_IP_CSUM | NETIF_F_TSO); | 869 | NETIF_F_TSO); |
875 | |||
876 | newdp6 = (struct dccp6_sock *)newsk; | 870 | newdp6 = (struct dccp6_sock *)newsk; |
877 | newinet = inet_sk(newsk); | 871 | newinet = inet_sk(newsk); |
878 | newinet->pinet6 = &newdp6->inet6; | 872 | newinet->pinet6 = &newdp6->inet6; |
@@ -886,7 +880,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
886 | ipv6_addr_copy(&newnp->rcv_saddr, &ireq6->loc_addr); | 880 | ipv6_addr_copy(&newnp->rcv_saddr, &ireq6->loc_addr); |
887 | newsk->sk_bound_dev_if = ireq6->iif; | 881 | newsk->sk_bound_dev_if = ireq6->iif; |
888 | 882 | ||
889 | /* Now IPv6 options... | 883 | /* Now IPv6 options... |
890 | 884 | ||
891 | First: no IPv4 options. | 885 | First: no IPv4 options. |
892 | */ | 886 | */ |
@@ -908,20 +902,20 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, | |||
908 | newnp->mcast_oif = inet6_iif(skb); | 902 | newnp->mcast_oif = inet6_iif(skb); |
909 | newnp->mcast_hops = skb->nh.ipv6h->hop_limit; | 903 | newnp->mcast_hops = skb->nh.ipv6h->hop_limit; |
910 | 904 | ||
911 | /* Clone native IPv6 options from listening socket (if any) | 905 | /* |
912 | 906 | * Clone native IPv6 options from listening socket (if any) | |
913 | Yes, keeping reference count would be much more clever, | 907 | * |
914 | but we make one more one thing there: reattach optmem | 908 | * Yes, keeping reference count would be much more clever, but we make |
915 | to newsk. | 909 | * one more one thing there: reattach optmem to newsk. |
916 | */ | 910 | */ |
917 | if (opt) { | 911 | if (opt != NULL) { |
918 | newnp->opt = ipv6_dup_options(newsk, opt); | 912 | newnp->opt = ipv6_dup_options(newsk, opt); |
919 | if (opt != np->opt) | 913 | if (opt != np->opt) |
920 | sock_kfree_s(sk, opt, opt->tot_len); | 914 | sock_kfree_s(sk, opt, opt->tot_len); |
921 | } | 915 | } |
922 | 916 | ||
923 | inet_csk(newsk)->icsk_ext_hdr_len = 0; | 917 | inet_csk(newsk)->icsk_ext_hdr_len = 0; |
924 | if (newnp->opt) | 918 | if (newnp->opt != NULL) |
925 | inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + | 919 | inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + |
926 | newnp->opt->opt_flen); | 920 | newnp->opt->opt_flen); |
927 | 921 | ||
@@ -938,7 +932,7 @@ out_overflow: | |||
938 | NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS); | 932 | NET_INC_STATS_BH(LINUX_MIB_LISTENOVERFLOWS); |
939 | out: | 933 | out: |
940 | NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS); | 934 | NET_INC_STATS_BH(LINUX_MIB_LISTENDROPS); |
941 | if (opt && opt != np->opt) | 935 | if (opt != NULL && opt != np->opt) |
942 | sock_kfree_s(sk, opt, opt->tot_len); | 936 | sock_kfree_s(sk, opt, opt->tot_len); |
943 | dst_release(dst); | 937 | dst_release(dst); |
944 | return NULL; | 938 | return NULL; |
@@ -972,8 +966,8 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
972 | goto discard; | 966 | goto discard; |
973 | 967 | ||
974 | /* | 968 | /* |
975 | * socket locking is here for SMP purposes as backlog rcv | 969 | * socket locking is here for SMP purposes as backlog rcv is currently |
976 | * is currently called with bh processing disabled. | 970 | * called with bh processing disabled. |
977 | */ | 971 | */ |
978 | 972 | ||
979 | /* Do Stevens' IPV6_PKTOPTIONS. | 973 | /* Do Stevens' IPV6_PKTOPTIONS. |
@@ -998,20 +992,20 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
998 | return 0; | 992 | return 0; |
999 | } | 993 | } |
1000 | 994 | ||
1001 | if (sk->sk_state == DCCP_LISTEN) { | 995 | if (sk->sk_state == DCCP_LISTEN) { |
1002 | struct sock *nsk = dccp_v6_hnd_req(sk, skb); | 996 | struct sock *nsk = dccp_v6_hnd_req(sk, skb); |
1003 | if (!nsk) | ||
1004 | goto discard; | ||
1005 | 997 | ||
998 | if (nsk == NULL) | ||
999 | goto discard; | ||
1006 | /* | 1000 | /* |
1007 | * Queue it on the new socket if the new socket is active, | 1001 | * Queue it on the new socket if the new socket is active, |
1008 | * otherwise we just shortcircuit this and continue with | 1002 | * otherwise we just shortcircuit this and continue with |
1009 | * the new socket.. | 1003 | * the new socket.. |
1010 | */ | 1004 | */ |
1011 | if(nsk != sk) { | 1005 | if (nsk != sk) { |
1012 | if (dccp_child_process(sk, nsk, skb)) | 1006 | if (dccp_child_process(sk, nsk, skb)) |
1013 | goto reset; | 1007 | goto reset; |
1014 | if (opt_skb) | 1008 | if (opt_skb != NULL) |
1015 | __kfree_skb(opt_skb); | 1009 | __kfree_skb(opt_skb); |
1016 | return 0; | 1010 | return 0; |
1017 | } | 1011 | } |
@@ -1024,7 +1018,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
1024 | reset: | 1018 | reset: |
1025 | dccp_v6_ctl_send_reset(skb); | 1019 | dccp_v6_ctl_send_reset(skb); |
1026 | discard: | 1020 | discard: |
1027 | if (opt_skb) | 1021 | if (opt_skb != NULL) |
1028 | __kfree_skb(opt_skb); | 1022 | __kfree_skb(opt_skb); |
1029 | kfree_skb(skb); | 1023 | kfree_skb(skb); |
1030 | return 0; | 1024 | return 0; |
@@ -1057,7 +1051,7 @@ static int dccp_v6_rcv(struct sk_buff **pskb) | |||
1057 | dh->dccph_sport, | 1051 | dh->dccph_sport, |
1058 | &skb->nh.ipv6h->daddr, ntohs(dh->dccph_dport), | 1052 | &skb->nh.ipv6h->daddr, ntohs(dh->dccph_dport), |
1059 | inet6_iif(skb)); | 1053 | inet6_iif(skb)); |
1060 | /* | 1054 | /* |
1061 | * Step 2: | 1055 | * Step 2: |
1062 | * If no socket ... | 1056 | * If no socket ... |
1063 | * Generate Reset(No Connection) unless P.type == Reset | 1057 | * Generate Reset(No Connection) unless P.type == Reset |
@@ -1066,15 +1060,14 @@ static int dccp_v6_rcv(struct sk_buff **pskb) | |||
1066 | if (sk == NULL) | 1060 | if (sk == NULL) |
1067 | goto no_dccp_socket; | 1061 | goto no_dccp_socket; |
1068 | 1062 | ||
1069 | /* | 1063 | /* |
1070 | * Step 2: | 1064 | * Step 2: |
1071 | * ... or S.state == TIMEWAIT, | 1065 | * ... or S.state == TIMEWAIT, |
1072 | * Generate Reset(No Connection) unless P.type == Reset | 1066 | * Generate Reset(No Connection) unless P.type == Reset |
1073 | * Drop packet and return | 1067 | * Drop packet and return |
1074 | */ | 1068 | */ |
1075 | |||
1076 | if (sk->sk_state == DCCP_TIME_WAIT) | 1069 | if (sk->sk_state == DCCP_TIME_WAIT) |
1077 | goto do_time_wait; | 1070 | goto do_time_wait; |
1078 | 1071 | ||
1079 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) | 1072 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
1080 | goto discard_and_relse; | 1073 | goto discard_and_relse; |
@@ -1113,32 +1106,40 @@ do_time_wait: | |||
1113 | } | 1106 | } |
1114 | 1107 | ||
1115 | static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = { | 1108 | static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = { |
1116 | .queue_xmit = inet6_csk_xmit, | 1109 | .queue_xmit = inet6_csk_xmit, |
1117 | .send_check = dccp_v6_send_check, | 1110 | .send_check = dccp_v6_send_check, |
1118 | .rebuild_header = inet6_sk_rebuild_header, | 1111 | .rebuild_header = inet6_sk_rebuild_header, |
1119 | .conn_request = dccp_v6_conn_request, | 1112 | .conn_request = dccp_v6_conn_request, |
1120 | .syn_recv_sock = dccp_v6_request_recv_sock, | 1113 | .syn_recv_sock = dccp_v6_request_recv_sock, |
1121 | .net_header_len = sizeof(struct ipv6hdr), | 1114 | .net_header_len = sizeof(struct ipv6hdr), |
1122 | .setsockopt = ipv6_setsockopt, | 1115 | .setsockopt = ipv6_setsockopt, |
1123 | .getsockopt = ipv6_getsockopt, | 1116 | .getsockopt = ipv6_getsockopt, |
1124 | .addr2sockaddr = inet6_csk_addr2sockaddr, | 1117 | .addr2sockaddr = inet6_csk_addr2sockaddr, |
1125 | .sockaddr_len = sizeof(struct sockaddr_in6) | 1118 | .sockaddr_len = sizeof(struct sockaddr_in6), |
1119 | #ifdef CONFIG_COMPAT | ||
1120 | .compat_setsockopt = compat_ipv6_setsockopt, | ||
1121 | .compat_getsockopt = compat_ipv6_getsockopt, | ||
1122 | #endif | ||
1126 | }; | 1123 | }; |
1127 | 1124 | ||
1128 | /* | 1125 | /* |
1129 | * DCCP over IPv4 via INET6 API | 1126 | * DCCP over IPv4 via INET6 API |
1130 | */ | 1127 | */ |
1131 | static struct inet_connection_sock_af_ops dccp_ipv6_mapped = { | 1128 | static struct inet_connection_sock_af_ops dccp_ipv6_mapped = { |
1132 | .queue_xmit = ip_queue_xmit, | 1129 | .queue_xmit = ip_queue_xmit, |
1133 | .send_check = dccp_v4_send_check, | 1130 | .send_check = dccp_v4_send_check, |
1134 | .rebuild_header = inet_sk_rebuild_header, | 1131 | .rebuild_header = inet_sk_rebuild_header, |
1135 | .conn_request = dccp_v6_conn_request, | 1132 | .conn_request = dccp_v6_conn_request, |
1136 | .syn_recv_sock = dccp_v6_request_recv_sock, | 1133 | .syn_recv_sock = dccp_v6_request_recv_sock, |
1137 | .net_header_len = sizeof(struct iphdr), | 1134 | .net_header_len = sizeof(struct iphdr), |
1138 | .setsockopt = ipv6_setsockopt, | 1135 | .setsockopt = ipv6_setsockopt, |
1139 | .getsockopt = ipv6_getsockopt, | 1136 | .getsockopt = ipv6_getsockopt, |
1140 | .addr2sockaddr = inet6_csk_addr2sockaddr, | 1137 | .addr2sockaddr = inet6_csk_addr2sockaddr, |
1141 | .sockaddr_len = sizeof(struct sockaddr_in6) | 1138 | .sockaddr_len = sizeof(struct sockaddr_in6), |
1139 | #ifdef CONFIG_COMPAT | ||
1140 | .compat_setsockopt = compat_ipv6_setsockopt, | ||
1141 | .compat_getsockopt = compat_ipv6_getsockopt, | ||
1142 | #endif | ||
1142 | }; | 1143 | }; |
1143 | 1144 | ||
1144 | /* NOTE: A lot of things set to zero explicitly by call to | 1145 | /* NOTE: A lot of things set to zero explicitly by call to |
@@ -1146,71 +1147,83 @@ static struct inet_connection_sock_af_ops dccp_ipv6_mapped = { | |||
1146 | */ | 1147 | */ |
1147 | static int dccp_v6_init_sock(struct sock *sk) | 1148 | static int dccp_v6_init_sock(struct sock *sk) |
1148 | { | 1149 | { |
1149 | int err = dccp_v4_init_sock(sk); | 1150 | static __u8 dccp_v6_ctl_sock_initialized; |
1151 | int err = dccp_init_sock(sk, dccp_v6_ctl_sock_initialized); | ||
1150 | 1152 | ||
1151 | if (err == 0) | 1153 | if (err == 0) { |
1154 | if (unlikely(!dccp_v6_ctl_sock_initialized)) | ||
1155 | dccp_v6_ctl_sock_initialized = 1; | ||
1152 | inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops; | 1156 | inet_csk(sk)->icsk_af_ops = &dccp_ipv6_af_ops; |
1157 | } | ||
1153 | 1158 | ||
1154 | return err; | 1159 | return err; |
1155 | } | 1160 | } |
1156 | 1161 | ||
1157 | static int dccp_v6_destroy_sock(struct sock *sk) | 1162 | static int dccp_v6_destroy_sock(struct sock *sk) |
1158 | { | 1163 | { |
1159 | dccp_v4_destroy_sock(sk); | 1164 | dccp_destroy_sock(sk); |
1160 | return inet6_destroy_sock(sk); | 1165 | return inet6_destroy_sock(sk); |
1161 | } | 1166 | } |
1162 | 1167 | ||
1163 | static struct proto dccp_v6_prot = { | 1168 | static struct proto dccp_v6_prot = { |
1164 | .name = "DCCPv6", | 1169 | .name = "DCCPv6", |
1165 | .owner = THIS_MODULE, | 1170 | .owner = THIS_MODULE, |
1166 | .close = dccp_close, | 1171 | .close = dccp_close, |
1167 | .connect = dccp_v6_connect, | 1172 | .connect = dccp_v6_connect, |
1168 | .disconnect = dccp_disconnect, | 1173 | .disconnect = dccp_disconnect, |
1169 | .ioctl = dccp_ioctl, | 1174 | .ioctl = dccp_ioctl, |
1170 | .init = dccp_v6_init_sock, | 1175 | .init = dccp_v6_init_sock, |
1171 | .setsockopt = dccp_setsockopt, | 1176 | .setsockopt = dccp_setsockopt, |
1172 | .getsockopt = dccp_getsockopt, | 1177 | .getsockopt = dccp_getsockopt, |
1173 | .sendmsg = dccp_sendmsg, | 1178 | .sendmsg = dccp_sendmsg, |
1174 | .recvmsg = dccp_recvmsg, | 1179 | .recvmsg = dccp_recvmsg, |
1175 | .backlog_rcv = dccp_v6_do_rcv, | 1180 | .backlog_rcv = dccp_v6_do_rcv, |
1176 | .hash = dccp_v6_hash, | 1181 | .hash = dccp_v6_hash, |
1177 | .unhash = dccp_unhash, | 1182 | .unhash = dccp_unhash, |
1178 | .accept = inet_csk_accept, | 1183 | .accept = inet_csk_accept, |
1179 | .get_port = dccp_v6_get_port, | 1184 | .get_port = dccp_v6_get_port, |
1180 | .shutdown = dccp_shutdown, | 1185 | .shutdown = dccp_shutdown, |
1181 | .destroy = dccp_v6_destroy_sock, | 1186 | .destroy = dccp_v6_destroy_sock, |
1182 | .orphan_count = &dccp_orphan_count, | 1187 | .orphan_count = &dccp_orphan_count, |
1183 | .max_header = MAX_DCCP_HEADER, | 1188 | .max_header = MAX_DCCP_HEADER, |
1184 | .obj_size = sizeof(struct dccp6_sock), | 1189 | .obj_size = sizeof(struct dccp6_sock), |
1185 | .rsk_prot = &dccp6_request_sock_ops, | 1190 | .rsk_prot = &dccp6_request_sock_ops, |
1186 | .twsk_prot = &dccp6_timewait_sock_ops, | 1191 | .twsk_prot = &dccp6_timewait_sock_ops, |
1192 | #ifdef CONFIG_COMPAT | ||
1193 | .compat_setsockopt = compat_dccp_setsockopt, | ||
1194 | .compat_getsockopt = compat_dccp_getsockopt, | ||
1195 | #endif | ||
1187 | }; | 1196 | }; |
1188 | 1197 | ||
1189 | static struct inet6_protocol dccp_v6_protocol = { | 1198 | static struct inet6_protocol dccp_v6_protocol = { |
1190 | .handler = dccp_v6_rcv, | 1199 | .handler = dccp_v6_rcv, |
1191 | .err_handler = dccp_v6_err, | 1200 | .err_handler = dccp_v6_err, |
1192 | .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL, | 1201 | .flags = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL, |
1193 | }; | 1202 | }; |
1194 | 1203 | ||
1195 | static struct proto_ops inet6_dccp_ops = { | 1204 | static struct proto_ops inet6_dccp_ops = { |
1196 | .family = PF_INET6, | 1205 | .family = PF_INET6, |
1197 | .owner = THIS_MODULE, | 1206 | .owner = THIS_MODULE, |
1198 | .release = inet6_release, | 1207 | .release = inet6_release, |
1199 | .bind = inet6_bind, | 1208 | .bind = inet6_bind, |
1200 | .connect = inet_stream_connect, | 1209 | .connect = inet_stream_connect, |
1201 | .socketpair = sock_no_socketpair, | 1210 | .socketpair = sock_no_socketpair, |
1202 | .accept = inet_accept, | 1211 | .accept = inet_accept, |
1203 | .getname = inet6_getname, | 1212 | .getname = inet6_getname, |
1204 | .poll = dccp_poll, | 1213 | .poll = dccp_poll, |
1205 | .ioctl = inet6_ioctl, | 1214 | .ioctl = inet6_ioctl, |
1206 | .listen = inet_dccp_listen, | 1215 | .listen = inet_dccp_listen, |
1207 | .shutdown = inet_shutdown, | 1216 | .shutdown = inet_shutdown, |
1208 | .setsockopt = sock_common_setsockopt, | 1217 | .setsockopt = sock_common_setsockopt, |
1209 | .getsockopt = sock_common_getsockopt, | 1218 | .getsockopt = sock_common_getsockopt, |
1210 | .sendmsg = inet_sendmsg, | 1219 | .sendmsg = inet_sendmsg, |
1211 | .recvmsg = sock_common_recvmsg, | 1220 | .recvmsg = sock_common_recvmsg, |
1212 | .mmap = sock_no_mmap, | 1221 | .mmap = sock_no_mmap, |
1213 | .sendpage = sock_no_sendpage, | 1222 | .sendpage = sock_no_sendpage, |
1223 | #ifdef CONFIG_COMPAT | ||
1224 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
1225 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
1226 | #endif | ||
1214 | }; | 1227 | }; |
1215 | 1228 | ||
1216 | static struct inet_protosw dccp_v6_protosw = { | 1229 | static struct inet_protosw dccp_v6_protosw = { |
@@ -1234,8 +1247,16 @@ static int __init dccp_v6_init(void) | |||
1234 | goto out_unregister_proto; | 1247 | goto out_unregister_proto; |
1235 | 1248 | ||
1236 | inet6_register_protosw(&dccp_v6_protosw); | 1249 | inet6_register_protosw(&dccp_v6_protosw); |
1250 | |||
1251 | err = inet_csk_ctl_sock_create(&dccp_v6_ctl_socket, PF_INET6, | ||
1252 | SOCK_DCCP, IPPROTO_DCCP); | ||
1253 | if (err != 0) | ||
1254 | goto out_unregister_protosw; | ||
1237 | out: | 1255 | out: |
1238 | return err; | 1256 | return err; |
1257 | out_unregister_protosw: | ||
1258 | inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); | ||
1259 | inet6_unregister_protosw(&dccp_v6_protosw); | ||
1239 | out_unregister_proto: | 1260 | out_unregister_proto: |
1240 | proto_unregister(&dccp_v6_prot); | 1261 | proto_unregister(&dccp_v6_prot); |
1241 | goto out; | 1262 | goto out; |
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index 29261fc198e7..c0349e5b0551 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "ackvec.h" | 22 | #include "ackvec.h" |
23 | #include "ccid.h" | 23 | #include "ccid.h" |
24 | #include "dccp.h" | 24 | #include "dccp.h" |
25 | #include "feat.h" | ||
25 | 26 | ||
26 | struct inet_timewait_death_row dccp_death_row = { | 27 | struct inet_timewait_death_row dccp_death_row = { |
27 | .sysctl_max_tw_buckets = NR_FILE * 2, | 28 | .sysctl_max_tw_buckets = NR_FILE * 2, |
@@ -106,6 +107,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk, | |||
106 | const struct dccp_request_sock *dreq = dccp_rsk(req); | 107 | const struct dccp_request_sock *dreq = dccp_rsk(req); |
107 | struct inet_connection_sock *newicsk = inet_csk(sk); | 108 | struct inet_connection_sock *newicsk = inet_csk(sk); |
108 | struct dccp_sock *newdp = dccp_sk(newsk); | 109 | struct dccp_sock *newdp = dccp_sk(newsk); |
110 | struct dccp_minisock *newdmsk = dccp_msk(newsk); | ||
109 | 111 | ||
110 | newdp->dccps_role = DCCP_ROLE_SERVER; | 112 | newdp->dccps_role = DCCP_ROLE_SERVER; |
111 | newdp->dccps_hc_rx_ackvec = NULL; | 113 | newdp->dccps_hc_rx_ackvec = NULL; |
@@ -114,27 +116,27 @@ struct sock *dccp_create_openreq_child(struct sock *sk, | |||
114 | newicsk->icsk_rto = DCCP_TIMEOUT_INIT; | 116 | newicsk->icsk_rto = DCCP_TIMEOUT_INIT; |
115 | do_gettimeofday(&newdp->dccps_epoch); | 117 | do_gettimeofday(&newdp->dccps_epoch); |
116 | 118 | ||
117 | if (newdp->dccps_options.dccpo_send_ack_vector) { | 119 | if (dccp_feat_clone(sk, newsk)) |
120 | goto out_free; | ||
121 | |||
122 | if (newdmsk->dccpms_send_ack_vector) { | ||
118 | newdp->dccps_hc_rx_ackvec = | 123 | newdp->dccps_hc_rx_ackvec = |
119 | dccp_ackvec_alloc(DCCP_MAX_ACKVEC_LEN, | 124 | dccp_ackvec_alloc(GFP_ATOMIC); |
120 | GFP_ATOMIC); | ||
121 | /* | ||
122 | * XXX: We're using the same CCIDs set on the parent, | ||
123 | * i.e. sk_clone copied the master sock and left the | ||
124 | * CCID pointers for this child, that is why we do the | ||
125 | * __ccid_get calls. | ||
126 | */ | ||
127 | if (unlikely(newdp->dccps_hc_rx_ackvec == NULL)) | 125 | if (unlikely(newdp->dccps_hc_rx_ackvec == NULL)) |
128 | goto out_free; | 126 | goto out_free; |
129 | } | 127 | } |
130 | 128 | ||
131 | if (unlikely(ccid_hc_rx_init(newdp->dccps_hc_rx_ccid, | 129 | newdp->dccps_hc_rx_ccid = |
132 | newsk) != 0 || | 130 | ccid_hc_rx_new(newdmsk->dccpms_rx_ccid, |
133 | ccid_hc_tx_init(newdp->dccps_hc_tx_ccid, | 131 | newsk, GFP_ATOMIC); |
134 | newsk) != 0)) { | 132 | newdp->dccps_hc_tx_ccid = |
133 | ccid_hc_tx_new(newdmsk->dccpms_tx_ccid, | ||
134 | newsk, GFP_ATOMIC); | ||
135 | if (unlikely(newdp->dccps_hc_rx_ccid == NULL || | ||
136 | newdp->dccps_hc_tx_ccid == NULL)) { | ||
135 | dccp_ackvec_free(newdp->dccps_hc_rx_ackvec); | 137 | dccp_ackvec_free(newdp->dccps_hc_rx_ackvec); |
136 | ccid_hc_rx_exit(newdp->dccps_hc_rx_ccid, newsk); | 138 | ccid_hc_rx_delete(newdp->dccps_hc_rx_ccid, newsk); |
137 | ccid_hc_tx_exit(newdp->dccps_hc_tx_ccid, newsk); | 139 | ccid_hc_tx_delete(newdp->dccps_hc_tx_ccid, newsk); |
138 | out_free: | 140 | out_free: |
139 | /* It is still raw copy of parent, so invalidate | 141 | /* It is still raw copy of parent, so invalidate |
140 | * destructor and make plain sk_free() */ | 142 | * destructor and make plain sk_free() */ |
@@ -143,9 +145,6 @@ out_free: | |||
143 | return NULL; | 145 | return NULL; |
144 | } | 146 | } |
145 | 147 | ||
146 | __ccid_get(newdp->dccps_hc_rx_ccid); | ||
147 | __ccid_get(newdp->dccps_hc_tx_ccid); | ||
148 | |||
149 | /* | 148 | /* |
150 | * Step 3: Process LISTEN state | 149 | * Step 3: Process LISTEN state |
151 | * | 150 | * |
@@ -155,7 +154,7 @@ out_free: | |||
155 | */ | 154 | */ |
156 | 155 | ||
157 | /* See dccp_v4_conn_request */ | 156 | /* See dccp_v4_conn_request */ |
158 | newdp->dccps_options.dccpo_sequence_window = req->rcv_wnd; | 157 | newdmsk->dccpms_sequence_window = req->rcv_wnd; |
159 | 158 | ||
160 | newdp->dccps_gar = newdp->dccps_isr = dreq->dreq_isr; | 159 | newdp->dccps_gar = newdp->dccps_isr = dreq->dreq_isr; |
161 | dccp_update_gsr(newsk, dreq->dreq_isr); | 160 | dccp_update_gsr(newsk, dreq->dreq_isr); |
diff --git a/net/dccp/options.c b/net/dccp/options.c index 0a76426c9aea..e9feb2a0c770 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c | |||
@@ -21,19 +21,23 @@ | |||
21 | #include "ackvec.h" | 21 | #include "ackvec.h" |
22 | #include "ccid.h" | 22 | #include "ccid.h" |
23 | #include "dccp.h" | 23 | #include "dccp.h" |
24 | #include "feat.h" | ||
24 | 25 | ||
25 | /* stores the default values for new connection. may be changed with sysctl */ | 26 | int dccp_feat_default_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW; |
26 | static const struct dccp_options dccpo_default_values = { | 27 | int dccp_feat_default_rx_ccid = DCCPF_INITIAL_CCID; |
27 | .dccpo_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW, | 28 | int dccp_feat_default_tx_ccid = DCCPF_INITIAL_CCID; |
28 | .dccpo_rx_ccid = DCCPF_INITIAL_CCID, | 29 | int dccp_feat_default_ack_ratio = DCCPF_INITIAL_ACK_RATIO; |
29 | .dccpo_tx_ccid = DCCPF_INITIAL_CCID, | 30 | int dccp_feat_default_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR; |
30 | .dccpo_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR, | 31 | int dccp_feat_default_send_ndp_count = DCCPF_INITIAL_SEND_NDP_COUNT; |
31 | .dccpo_send_ndp_count = DCCPF_INITIAL_SEND_NDP_COUNT, | ||
32 | }; | ||
33 | 32 | ||
34 | void dccp_options_init(struct dccp_options *dccpo) | 33 | void dccp_minisock_init(struct dccp_minisock *dmsk) |
35 | { | 34 | { |
36 | memcpy(dccpo, &dccpo_default_values, sizeof(*dccpo)); | 35 | dmsk->dccpms_sequence_window = dccp_feat_default_sequence_window; |
36 | dmsk->dccpms_rx_ccid = dccp_feat_default_rx_ccid; | ||
37 | dmsk->dccpms_tx_ccid = dccp_feat_default_tx_ccid; | ||
38 | dmsk->dccpms_ack_ratio = dccp_feat_default_ack_ratio; | ||
39 | dmsk->dccpms_send_ack_vector = dccp_feat_default_send_ack_vector; | ||
40 | dmsk->dccpms_send_ndp_count = dccp_feat_default_send_ndp_count; | ||
37 | } | 41 | } |
38 | 42 | ||
39 | static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len) | 43 | static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len) |
@@ -69,9 +73,12 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
69 | unsigned char opt, len; | 73 | unsigned char opt, len; |
70 | unsigned char *value; | 74 | unsigned char *value; |
71 | u32 elapsed_time; | 75 | u32 elapsed_time; |
76 | int rc; | ||
77 | int mandatory = 0; | ||
72 | 78 | ||
73 | memset(opt_recv, 0, sizeof(*opt_recv)); | 79 | memset(opt_recv, 0, sizeof(*opt_recv)); |
74 | 80 | ||
81 | opt = len = 0; | ||
75 | while (opt_ptr != opt_end) { | 82 | while (opt_ptr != opt_end) { |
76 | opt = *opt_ptr++; | 83 | opt = *opt_ptr++; |
77 | len = 0; | 84 | len = 0; |
@@ -100,6 +107,12 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
100 | switch (opt) { | 107 | switch (opt) { |
101 | case DCCPO_PADDING: | 108 | case DCCPO_PADDING: |
102 | break; | 109 | break; |
110 | case DCCPO_MANDATORY: | ||
111 | if (mandatory) | ||
112 | goto out_invalid_option; | ||
113 | if (pkt_type != DCCP_PKT_DATA) | ||
114 | mandatory = 1; | ||
115 | break; | ||
103 | case DCCPO_NDP_COUNT: | 116 | case DCCPO_NDP_COUNT: |
104 | if (len > 3) | 117 | if (len > 3) |
105 | goto out_invalid_option; | 118 | goto out_invalid_option; |
@@ -108,12 +121,37 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
108 | dccp_pr_debug("%sNDP count=%d\n", debug_prefix, | 121 | dccp_pr_debug("%sNDP count=%d\n", debug_prefix, |
109 | opt_recv->dccpor_ndp); | 122 | opt_recv->dccpor_ndp); |
110 | break; | 123 | break; |
124 | case DCCPO_CHANGE_L: | ||
125 | /* fall through */ | ||
126 | case DCCPO_CHANGE_R: | ||
127 | if (len < 2) | ||
128 | goto out_invalid_option; | ||
129 | rc = dccp_feat_change_recv(sk, opt, *value, value + 1, | ||
130 | len - 1); | ||
131 | /* | ||
132 | * When there is a change error, change_recv is | ||
133 | * responsible for dealing with it. i.e. reply with an | ||
134 | * empty confirm. | ||
135 | * If the change was mandatory, then we need to die. | ||
136 | */ | ||
137 | if (rc && mandatory) | ||
138 | goto out_invalid_option; | ||
139 | break; | ||
140 | case DCCPO_CONFIRM_L: | ||
141 | /* fall through */ | ||
142 | case DCCPO_CONFIRM_R: | ||
143 | if (len < 2) | ||
144 | goto out_invalid_option; | ||
145 | if (dccp_feat_confirm_recv(sk, opt, *value, | ||
146 | value + 1, len - 1)) | ||
147 | goto out_invalid_option; | ||
148 | break; | ||
111 | case DCCPO_ACK_VECTOR_0: | 149 | case DCCPO_ACK_VECTOR_0: |
112 | case DCCPO_ACK_VECTOR_1: | 150 | case DCCPO_ACK_VECTOR_1: |
113 | if (pkt_type == DCCP_PKT_DATA) | 151 | if (pkt_type == DCCP_PKT_DATA) |
114 | continue; | 152 | break; |
115 | 153 | ||
116 | if (dp->dccps_options.dccpo_send_ack_vector && | 154 | if (dccp_msk(sk)->dccpms_send_ack_vector && |
117 | dccp_ackvec_parse(sk, skb, opt, value, len)) | 155 | dccp_ackvec_parse(sk, skb, opt, value, len)) |
118 | goto out_invalid_option; | 156 | goto out_invalid_option; |
119 | break; | 157 | break; |
@@ -121,7 +159,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
121 | if (len != 4) | 159 | if (len != 4) |
122 | goto out_invalid_option; | 160 | goto out_invalid_option; |
123 | 161 | ||
124 | opt_recv->dccpor_timestamp = ntohl(*(u32 *)value); | 162 | opt_recv->dccpor_timestamp = ntohl(*(__be32 *)value); |
125 | 163 | ||
126 | dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp; | 164 | dp->dccps_timestamp_echo = opt_recv->dccpor_timestamp; |
127 | dccp_timestamp(sk, &dp->dccps_timestamp_time); | 165 | dccp_timestamp(sk, &dp->dccps_timestamp_time); |
@@ -135,7 +173,7 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
135 | if (len != 4 && len != 6 && len != 8) | 173 | if (len != 4 && len != 6 && len != 8) |
136 | goto out_invalid_option; | 174 | goto out_invalid_option; |
137 | 175 | ||
138 | opt_recv->dccpor_timestamp_echo = ntohl(*(u32 *)value); | 176 | opt_recv->dccpor_timestamp_echo = ntohl(*(__be32 *)value); |
139 | 177 | ||
140 | dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, ackno=%llu, ", | 178 | dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, ackno=%llu, ", |
141 | debug_prefix, | 179 | debug_prefix, |
@@ -149,9 +187,9 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
149 | break; | 187 | break; |
150 | 188 | ||
151 | if (len == 6) | 189 | if (len == 6) |
152 | elapsed_time = ntohs(*(u16 *)(value + 4)); | 190 | elapsed_time = ntohs(*(__be16 *)(value + 4)); |
153 | else | 191 | else |
154 | elapsed_time = ntohl(*(u32 *)(value + 4)); | 192 | elapsed_time = ntohl(*(__be32 *)(value + 4)); |
155 | 193 | ||
156 | /* Give precedence to the biggest ELAPSED_TIME */ | 194 | /* Give precedence to the biggest ELAPSED_TIME */ |
157 | if (elapsed_time > opt_recv->dccpor_elapsed_time) | 195 | if (elapsed_time > opt_recv->dccpor_elapsed_time) |
@@ -165,9 +203,9 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
165 | continue; | 203 | continue; |
166 | 204 | ||
167 | if (len == 2) | 205 | if (len == 2) |
168 | elapsed_time = ntohs(*(u16 *)value); | 206 | elapsed_time = ntohs(*(__be16 *)value); |
169 | else | 207 | else |
170 | elapsed_time = ntohl(*(u32 *)value); | 208 | elapsed_time = ntohl(*(__be32 *)value); |
171 | 209 | ||
172 | if (elapsed_time > opt_recv->dccpor_elapsed_time) | 210 | if (elapsed_time > opt_recv->dccpor_elapsed_time) |
173 | opt_recv->dccpor_elapsed_time = elapsed_time; | 211 | opt_recv->dccpor_elapsed_time = elapsed_time; |
@@ -208,8 +246,15 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) | |||
208 | sk, opt, len); | 246 | sk, opt, len); |
209 | break; | 247 | break; |
210 | } | 248 | } |
249 | |||
250 | if (opt != DCCPO_MANDATORY) | ||
251 | mandatory = 0; | ||
211 | } | 252 | } |
212 | 253 | ||
254 | /* mandatory was the last byte in option list -> reset connection */ | ||
255 | if (mandatory) | ||
256 | goto out_invalid_option; | ||
257 | |||
213 | return 0; | 258 | return 0; |
214 | 259 | ||
215 | out_invalid_option: | 260 | out_invalid_option: |
@@ -219,6 +264,8 @@ out_invalid_option: | |||
219 | return -1; | 264 | return -1; |
220 | } | 265 | } |
221 | 266 | ||
267 | EXPORT_SYMBOL_GPL(dccp_parse_options); | ||
268 | |||
222 | static void dccp_encode_value_var(const u32 value, unsigned char *to, | 269 | static void dccp_encode_value_var(const u32 value, unsigned char *to, |
223 | const unsigned int len) | 270 | const unsigned int len) |
224 | { | 271 | { |
@@ -237,17 +284,14 @@ static inline int dccp_ndp_len(const int ndp) | |||
237 | return likely(ndp <= 0xFF) ? 1 : ndp <= 0xFFFF ? 2 : 3; | 284 | return likely(ndp <= 0xFF) ? 1 : ndp <= 0xFFFF ? 2 : 3; |
238 | } | 285 | } |
239 | 286 | ||
240 | void dccp_insert_option(struct sock *sk, struct sk_buff *skb, | 287 | int dccp_insert_option(struct sock *sk, struct sk_buff *skb, |
241 | const unsigned char option, | 288 | const unsigned char option, |
242 | const void *value, const unsigned char len) | 289 | const void *value, const unsigned char len) |
243 | { | 290 | { |
244 | unsigned char *to; | 291 | unsigned char *to; |
245 | 292 | ||
246 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN) { | 293 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN) |
247 | LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert " | 294 | return -1; |
248 | "%d option!\n", option); | ||
249 | return; | ||
250 | } | ||
251 | 295 | ||
252 | DCCP_SKB_CB(skb)->dccpd_opt_len += len + 2; | 296 | DCCP_SKB_CB(skb)->dccpd_opt_len += len + 2; |
253 | 297 | ||
@@ -256,11 +300,12 @@ void dccp_insert_option(struct sock *sk, struct sk_buff *skb, | |||
256 | *to++ = len + 2; | 300 | *to++ = len + 2; |
257 | 301 | ||
258 | memcpy(to, value, len); | 302 | memcpy(to, value, len); |
303 | return 0; | ||
259 | } | 304 | } |
260 | 305 | ||
261 | EXPORT_SYMBOL_GPL(dccp_insert_option); | 306 | EXPORT_SYMBOL_GPL(dccp_insert_option); |
262 | 307 | ||
263 | static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) | 308 | static int dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) |
264 | { | 309 | { |
265 | struct dccp_sock *dp = dccp_sk(sk); | 310 | struct dccp_sock *dp = dccp_sk(sk); |
266 | int ndp = dp->dccps_ndp_count; | 311 | int ndp = dp->dccps_ndp_count; |
@@ -276,7 +321,7 @@ static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) | |||
276 | const int len = ndp_len + 2; | 321 | const int len = ndp_len + 2; |
277 | 322 | ||
278 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) | 323 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) |
279 | return; | 324 | return -1; |
280 | 325 | ||
281 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | 326 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; |
282 | 327 | ||
@@ -285,6 +330,8 @@ static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb) | |||
285 | *ptr++ = len; | 330 | *ptr++ = len; |
286 | dccp_encode_value_var(ndp, ptr, ndp_len); | 331 | dccp_encode_value_var(ndp, ptr, ndp_len); |
287 | } | 332 | } |
333 | |||
334 | return 0; | ||
288 | } | 335 | } |
289 | 336 | ||
290 | static inline int dccp_elapsed_time_len(const u32 elapsed_time) | 337 | static inline int dccp_elapsed_time_len(const u32 elapsed_time) |
@@ -292,27 +339,18 @@ static inline int dccp_elapsed_time_len(const u32 elapsed_time) | |||
292 | return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; | 339 | return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4; |
293 | } | 340 | } |
294 | 341 | ||
295 | void dccp_insert_option_elapsed_time(struct sock *sk, | 342 | int dccp_insert_option_elapsed_time(struct sock *sk, struct sk_buff *skb, |
296 | struct sk_buff *skb, | 343 | u32 elapsed_time) |
297 | u32 elapsed_time) | ||
298 | { | 344 | { |
299 | #ifdef CONFIG_IP_DCCP_DEBUG | ||
300 | struct dccp_sock *dp = dccp_sk(sk); | ||
301 | const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? | ||
302 | "CLIENT TX opt: " : "server TX opt: "; | ||
303 | #endif | ||
304 | const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); | 345 | const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time); |
305 | const int len = 2 + elapsed_time_len; | 346 | const int len = 2 + elapsed_time_len; |
306 | unsigned char *to; | 347 | unsigned char *to; |
307 | 348 | ||
308 | if (elapsed_time_len == 0) | 349 | if (elapsed_time_len == 0) |
309 | return; | 350 | return 0; |
310 | 351 | ||
311 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { | 352 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) |
312 | LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to " | 353 | return -1; |
313 | "insert elapsed time!\n"); | ||
314 | return; | ||
315 | } | ||
316 | 354 | ||
317 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | 355 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; |
318 | 356 | ||
@@ -321,17 +359,14 @@ void dccp_insert_option_elapsed_time(struct sock *sk, | |||
321 | *to++ = len; | 359 | *to++ = len; |
322 | 360 | ||
323 | if (elapsed_time_len == 2) { | 361 | if (elapsed_time_len == 2) { |
324 | const u16 var16 = htons((u16)elapsed_time); | 362 | const __be16 var16 = htons((u16)elapsed_time); |
325 | memcpy(to, &var16, 2); | 363 | memcpy(to, &var16, 2); |
326 | } else { | 364 | } else { |
327 | const u32 var32 = htonl(elapsed_time); | 365 | const __be32 var32 = htonl(elapsed_time); |
328 | memcpy(to, &var32, 4); | 366 | memcpy(to, &var32, 4); |
329 | } | 367 | } |
330 | 368 | ||
331 | dccp_pr_debug("%sELAPSED_TIME=%u, len=%d, seqno=%llu\n", | 369 | return 0; |
332 | debug_prefix, elapsed_time, | ||
333 | len, | ||
334 | (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); | ||
335 | } | 370 | } |
336 | 371 | ||
337 | EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time); | 372 | EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time); |
@@ -352,32 +387,27 @@ void dccp_timestamp(const struct sock *sk, struct timeval *tv) | |||
352 | 387 | ||
353 | EXPORT_SYMBOL_GPL(dccp_timestamp); | 388 | EXPORT_SYMBOL_GPL(dccp_timestamp); |
354 | 389 | ||
355 | void dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb) | 390 | int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb) |
356 | { | 391 | { |
357 | struct timeval tv; | 392 | struct timeval tv; |
358 | u32 now; | 393 | __be32 now; |
359 | 394 | ||
360 | dccp_timestamp(sk, &tv); | 395 | dccp_timestamp(sk, &tv); |
361 | now = timeval_usecs(&tv) / 10; | 396 | now = htonl(timeval_usecs(&tv) / 10); |
362 | /* yes this will overflow but that is the point as we want a | 397 | /* yes this will overflow but that is the point as we want a |
363 | * 10 usec 32 bit timer which mean it wraps every 11.9 hours */ | 398 | * 10 usec 32 bit timer which mean it wraps every 11.9 hours */ |
364 | 399 | ||
365 | now = htonl(now); | 400 | return dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now)); |
366 | dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now)); | ||
367 | } | 401 | } |
368 | 402 | ||
369 | EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp); | 403 | EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp); |
370 | 404 | ||
371 | static void dccp_insert_option_timestamp_echo(struct sock *sk, | 405 | static int dccp_insert_option_timestamp_echo(struct sock *sk, |
372 | struct sk_buff *skb) | 406 | struct sk_buff *skb) |
373 | { | 407 | { |
374 | struct dccp_sock *dp = dccp_sk(sk); | 408 | struct dccp_sock *dp = dccp_sk(sk); |
375 | #ifdef CONFIG_IP_DCCP_DEBUG | ||
376 | const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? | ||
377 | "CLIENT TX opt: " : "server TX opt: "; | ||
378 | #endif | ||
379 | struct timeval now; | 409 | struct timeval now; |
380 | u32 tstamp_echo; | 410 | __be32 tstamp_echo; |
381 | u32 elapsed_time; | 411 | u32 elapsed_time; |
382 | int len, elapsed_time_len; | 412 | int len, elapsed_time_len; |
383 | unsigned char *to; | 413 | unsigned char *to; |
@@ -387,11 +417,8 @@ static void dccp_insert_option_timestamp_echo(struct sock *sk, | |||
387 | elapsed_time_len = dccp_elapsed_time_len(elapsed_time); | 417 | elapsed_time_len = dccp_elapsed_time_len(elapsed_time); |
388 | len = 6 + elapsed_time_len; | 418 | len = 6 + elapsed_time_len; |
389 | 419 | ||
390 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { | 420 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) |
391 | LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert " | 421 | return -1; |
392 | "timestamp echo!\n"); | ||
393 | return; | ||
394 | } | ||
395 | 422 | ||
396 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; | 423 | DCCP_SKB_CB(skb)->dccpd_opt_len += len; |
397 | 424 | ||
@@ -402,51 +429,149 @@ static void dccp_insert_option_timestamp_echo(struct sock *sk, | |||
402 | tstamp_echo = htonl(dp->dccps_timestamp_echo); | 429 | tstamp_echo = htonl(dp->dccps_timestamp_echo); |
403 | memcpy(to, &tstamp_echo, 4); | 430 | memcpy(to, &tstamp_echo, 4); |
404 | to += 4; | 431 | to += 4; |
405 | 432 | ||
406 | if (elapsed_time_len == 2) { | 433 | if (elapsed_time_len == 2) { |
407 | const u16 var16 = htons((u16)elapsed_time); | 434 | const __be16 var16 = htons((u16)elapsed_time); |
408 | memcpy(to, &var16, 2); | 435 | memcpy(to, &var16, 2); |
409 | } else if (elapsed_time_len == 4) { | 436 | } else if (elapsed_time_len == 4) { |
410 | const u32 var32 = htonl(elapsed_time); | 437 | const __be32 var32 = htonl(elapsed_time); |
411 | memcpy(to, &var32, 4); | 438 | memcpy(to, &var32, 4); |
412 | } | 439 | } |
413 | 440 | ||
414 | dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, seqno=%llu\n", | ||
415 | debug_prefix, dp->dccps_timestamp_echo, | ||
416 | len, | ||
417 | (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); | ||
418 | |||
419 | dp->dccps_timestamp_echo = 0; | 441 | dp->dccps_timestamp_echo = 0; |
420 | dp->dccps_timestamp_time.tv_sec = 0; | 442 | dp->dccps_timestamp_time.tv_sec = 0; |
421 | dp->dccps_timestamp_time.tv_usec = 0; | 443 | dp->dccps_timestamp_time.tv_usec = 0; |
444 | return 0; | ||
422 | } | 445 | } |
423 | 446 | ||
424 | void dccp_insert_options(struct sock *sk, struct sk_buff *skb) | 447 | static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat, |
448 | u8 *val, u8 len) | ||
449 | { | ||
450 | u8 *to; | ||
451 | |||
452 | if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) { | ||
453 | LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small" | ||
454 | " to insert feature %d option!\n", feat); | ||
455 | return -1; | ||
456 | } | ||
457 | |||
458 | DCCP_SKB_CB(skb)->dccpd_opt_len += len + 3; | ||
459 | |||
460 | to = skb_push(skb, len + 3); | ||
461 | *to++ = type; | ||
462 | *to++ = len + 3; | ||
463 | *to++ = feat; | ||
464 | |||
465 | if (len) | ||
466 | memcpy(to, val, len); | ||
467 | dccp_pr_debug("option %d feat %d len %d\n", type, feat, len); | ||
468 | |||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb) | ||
425 | { | 473 | { |
426 | struct dccp_sock *dp = dccp_sk(sk); | 474 | struct dccp_sock *dp = dccp_sk(sk); |
475 | struct dccp_minisock *dmsk = dccp_msk(sk); | ||
476 | struct dccp_opt_pend *opt, *next; | ||
477 | int change = 0; | ||
478 | |||
479 | /* confirm any options [NN opts] */ | ||
480 | list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) { | ||
481 | dccp_insert_feat_opt(skb, opt->dccpop_type, | ||
482 | opt->dccpop_feat, opt->dccpop_val, | ||
483 | opt->dccpop_len); | ||
484 | /* fear empty confirms */ | ||
485 | if (opt->dccpop_val) | ||
486 | kfree(opt->dccpop_val); | ||
487 | kfree(opt); | ||
488 | } | ||
489 | INIT_LIST_HEAD(&dmsk->dccpms_conf); | ||
490 | |||
491 | /* see which features we need to send */ | ||
492 | list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { | ||
493 | /* see if we need to send any confirm */ | ||
494 | if (opt->dccpop_sc) { | ||
495 | dccp_insert_feat_opt(skb, opt->dccpop_type + 1, | ||
496 | opt->dccpop_feat, | ||
497 | opt->dccpop_sc->dccpoc_val, | ||
498 | opt->dccpop_sc->dccpoc_len); | ||
499 | |||
500 | BUG_ON(!opt->dccpop_sc->dccpoc_val); | ||
501 | kfree(opt->dccpop_sc->dccpoc_val); | ||
502 | kfree(opt->dccpop_sc); | ||
503 | opt->dccpop_sc = NULL; | ||
504 | } | ||
505 | |||
506 | /* any option not confirmed, re-send it */ | ||
507 | if (!opt->dccpop_conf) { | ||
508 | dccp_insert_feat_opt(skb, opt->dccpop_type, | ||
509 | opt->dccpop_feat, opt->dccpop_val, | ||
510 | opt->dccpop_len); | ||
511 | change++; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | /* Retransmit timer. | ||
516 | * If this is the master listening sock, we don't set a timer on it. It | ||
517 | * should be fine because if the dude doesn't receive our RESPONSE | ||
518 | * [which will contain the CHANGE] he will send another REQUEST which | ||
519 | * will "retrnasmit" the change. | ||
520 | */ | ||
521 | if (change && dp->dccps_role != DCCP_ROLE_LISTEN) { | ||
522 | dccp_pr_debug("reset feat negotiation timer %p\n", sk); | ||
523 | |||
524 | /* XXX don't reset the timer on re-transmissions. I.e. reset it | ||
525 | * only when sending new stuff i guess. Currently the timer | ||
526 | * never backs off because on re-transmission it just resets it! | ||
527 | */ | ||
528 | inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, | ||
529 | inet_csk(sk)->icsk_rto, DCCP_RTO_MAX); | ||
530 | } | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | int dccp_insert_options(struct sock *sk, struct sk_buff *skb) | ||
536 | { | ||
537 | struct dccp_sock *dp = dccp_sk(sk); | ||
538 | struct dccp_minisock *dmsk = dccp_msk(sk); | ||
427 | 539 | ||
428 | DCCP_SKB_CB(skb)->dccpd_opt_len = 0; | 540 | DCCP_SKB_CB(skb)->dccpd_opt_len = 0; |
429 | 541 | ||
430 | if (dp->dccps_options.dccpo_send_ndp_count) | 542 | if (dmsk->dccpms_send_ndp_count && |
431 | dccp_insert_option_ndp(sk, skb); | 543 | dccp_insert_option_ndp(sk, skb)) |
544 | return -1; | ||
432 | 545 | ||
433 | if (!dccp_packet_without_ack(skb)) { | 546 | if (!dccp_packet_without_ack(skb)) { |
434 | if (dp->dccps_options.dccpo_send_ack_vector && | 547 | if (dmsk->dccpms_send_ack_vector && |
435 | dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) | 548 | dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) && |
436 | dccp_insert_option_ackvec(sk, skb); | 549 | dccp_insert_option_ackvec(sk, skb)) |
437 | if (dp->dccps_timestamp_echo != 0) | 550 | return -1; |
438 | dccp_insert_option_timestamp_echo(sk, skb); | 551 | |
552 | if (dp->dccps_timestamp_echo != 0 && | ||
553 | dccp_insert_option_timestamp_echo(sk, skb)) | ||
554 | return -1; | ||
439 | } | 555 | } |
440 | 556 | ||
441 | if (dp->dccps_hc_rx_insert_options) { | 557 | if (dp->dccps_hc_rx_insert_options) { |
442 | ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb); | 558 | if (ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb)) |
559 | return -1; | ||
443 | dp->dccps_hc_rx_insert_options = 0; | 560 | dp->dccps_hc_rx_insert_options = 0; |
444 | } | 561 | } |
445 | if (dp->dccps_hc_tx_insert_options) { | 562 | if (dp->dccps_hc_tx_insert_options) { |
446 | ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb); | 563 | if (ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb)) |
564 | return -1; | ||
447 | dp->dccps_hc_tx_insert_options = 0; | 565 | dp->dccps_hc_tx_insert_options = 0; |
448 | } | 566 | } |
449 | 567 | ||
568 | /* Feature negotiation */ | ||
569 | /* Data packets can't do feat negotiation */ | ||
570 | if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA && | ||
571 | DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATAACK && | ||
572 | dccp_insert_options_feat(sk, skb)) | ||
573 | return -1; | ||
574 | |||
450 | /* XXX: insert other options when appropriate */ | 575 | /* XXX: insert other options when appropriate */ |
451 | 576 | ||
452 | if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) { | 577 | if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) { |
@@ -459,4 +584,6 @@ void dccp_insert_options(struct sock *sk, struct sk_buff *skb) | |||
459 | DCCP_SKB_CB(skb)->dccpd_opt_len += padding; | 584 | DCCP_SKB_CB(skb)->dccpd_opt_len += padding; |
460 | } | 585 | } |
461 | } | 586 | } |
587 | |||
588 | return 0; | ||
462 | } | 589 | } |
diff --git a/net/dccp/output.c b/net/dccp/output.c index efd7ffb903a1..7409e4a3abdf 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c | |||
@@ -27,7 +27,7 @@ static inline void dccp_event_ack_sent(struct sock *sk) | |||
27 | inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK); | 27 | inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK); |
28 | } | 28 | } |
29 | 29 | ||
30 | static inline void dccp_skb_entail(struct sock *sk, struct sk_buff *skb) | 30 | static void dccp_skb_entail(struct sock *sk, struct sk_buff *skb) |
31 | { | 31 | { |
32 | skb_set_owner_w(skb, sk); | 32 | skb_set_owner_w(skb, sk); |
33 | WARN_ON(sk->sk_send_head); | 33 | WARN_ON(sk->sk_send_head); |
@@ -49,7 +49,7 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) | |||
49 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); | 49 | struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); |
50 | struct dccp_hdr *dh; | 50 | struct dccp_hdr *dh; |
51 | /* XXX For now we're using only 48 bits sequence numbers */ | 51 | /* XXX For now we're using only 48 bits sequence numbers */ |
52 | const int dccp_header_size = sizeof(*dh) + | 52 | const u32 dccp_header_size = sizeof(*dh) + |
53 | sizeof(struct dccp_hdr_ext) + | 53 | sizeof(struct dccp_hdr_ext) + |
54 | dccp_packet_hdr_len(dcb->dccpd_type); | 54 | dccp_packet_hdr_len(dcb->dccpd_type); |
55 | int err, set_ack = 1; | 55 | int err, set_ack = 1; |
@@ -64,6 +64,10 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) | |||
64 | case DCCP_PKT_DATAACK: | 64 | case DCCP_PKT_DATAACK: |
65 | break; | 65 | break; |
66 | 66 | ||
67 | case DCCP_PKT_REQUEST: | ||
68 | set_ack = 0; | ||
69 | /* fall through */ | ||
70 | |||
67 | case DCCP_PKT_SYNC: | 71 | case DCCP_PKT_SYNC: |
68 | case DCCP_PKT_SYNCACK: | 72 | case DCCP_PKT_SYNCACK: |
69 | ackno = dcb->dccpd_seq; | 73 | ackno = dcb->dccpd_seq; |
@@ -79,7 +83,11 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) | |||
79 | } | 83 | } |
80 | 84 | ||
81 | dcb->dccpd_seq = dp->dccps_gss; | 85 | dcb->dccpd_seq = dp->dccps_gss; |
82 | dccp_insert_options(sk, skb); | 86 | |
87 | if (dccp_insert_options(sk, skb)) { | ||
88 | kfree_skb(skb); | ||
89 | return -EPROTO; | ||
90 | } | ||
83 | 91 | ||
84 | skb->h.raw = skb_push(skb, dccp_header_size); | 92 | skb->h.raw = skb_push(skb, dccp_header_size); |
85 | dh = dccp_hdr(skb); | 93 | dh = dccp_hdr(skb); |
@@ -275,17 +283,16 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, | |||
275 | { | 283 | { |
276 | struct dccp_hdr *dh; | 284 | struct dccp_hdr *dh; |
277 | struct dccp_request_sock *dreq; | 285 | struct dccp_request_sock *dreq; |
278 | const int dccp_header_size = sizeof(struct dccp_hdr) + | 286 | const u32 dccp_header_size = sizeof(struct dccp_hdr) + |
279 | sizeof(struct dccp_hdr_ext) + | 287 | sizeof(struct dccp_hdr_ext) + |
280 | sizeof(struct dccp_hdr_response); | 288 | sizeof(struct dccp_hdr_response); |
281 | struct sk_buff *skb = sock_wmalloc(sk, MAX_HEADER + DCCP_MAX_OPT_LEN + | 289 | struct sk_buff *skb = sock_wmalloc(sk, sk->sk_prot->max_header, 1, |
282 | dccp_header_size, 1, | ||
283 | GFP_ATOMIC); | 290 | GFP_ATOMIC); |
284 | if (skb == NULL) | 291 | if (skb == NULL) |
285 | return NULL; | 292 | return NULL; |
286 | 293 | ||
287 | /* Reserve space for headers. */ | 294 | /* Reserve space for headers. */ |
288 | skb_reserve(skb, MAX_HEADER + DCCP_MAX_OPT_LEN + dccp_header_size); | 295 | skb_reserve(skb, sk->sk_prot->max_header); |
289 | 296 | ||
290 | skb->dst = dst_clone(dst); | 297 | skb->dst = dst_clone(dst); |
291 | skb->csum = 0; | 298 | skb->csum = 0; |
@@ -293,7 +300,11 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, | |||
293 | dreq = dccp_rsk(req); | 300 | dreq = dccp_rsk(req); |
294 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE; | 301 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE; |
295 | DCCP_SKB_CB(skb)->dccpd_seq = dreq->dreq_iss; | 302 | DCCP_SKB_CB(skb)->dccpd_seq = dreq->dreq_iss; |
296 | dccp_insert_options(sk, skb); | 303 | |
304 | if (dccp_insert_options(sk, skb)) { | ||
305 | kfree_skb(skb); | ||
306 | return NULL; | ||
307 | } | ||
297 | 308 | ||
298 | skb->h.raw = skb_push(skb, dccp_header_size); | 309 | skb->h.raw = skb_push(skb, dccp_header_size); |
299 | 310 | ||
@@ -310,32 +321,28 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, | |||
310 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_isr); | 321 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_isr); |
311 | dccp_hdr_response(skb)->dccph_resp_service = dreq->dreq_service; | 322 | dccp_hdr_response(skb)->dccph_resp_service = dreq->dreq_service; |
312 | 323 | ||
313 | dh->dccph_checksum = dccp_v4_checksum(skb, inet_rsk(req)->loc_addr, | ||
314 | inet_rsk(req)->rmt_addr); | ||
315 | |||
316 | DCCP_INC_STATS(DCCP_MIB_OUTSEGS); | 324 | DCCP_INC_STATS(DCCP_MIB_OUTSEGS); |
317 | return skb; | 325 | return skb; |
318 | } | 326 | } |
319 | 327 | ||
320 | EXPORT_SYMBOL_GPL(dccp_make_response); | 328 | EXPORT_SYMBOL_GPL(dccp_make_response); |
321 | 329 | ||
322 | struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst, | 330 | static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst, |
323 | const enum dccp_reset_codes code) | 331 | const enum dccp_reset_codes code) |
324 | 332 | ||
325 | { | 333 | { |
326 | struct dccp_hdr *dh; | 334 | struct dccp_hdr *dh; |
327 | struct dccp_sock *dp = dccp_sk(sk); | 335 | struct dccp_sock *dp = dccp_sk(sk); |
328 | const int dccp_header_size = sizeof(struct dccp_hdr) + | 336 | const u32 dccp_header_size = sizeof(struct dccp_hdr) + |
329 | sizeof(struct dccp_hdr_ext) + | 337 | sizeof(struct dccp_hdr_ext) + |
330 | sizeof(struct dccp_hdr_reset); | 338 | sizeof(struct dccp_hdr_reset); |
331 | struct sk_buff *skb = sock_wmalloc(sk, MAX_HEADER + DCCP_MAX_OPT_LEN + | 339 | struct sk_buff *skb = sock_wmalloc(sk, sk->sk_prot->max_header, 1, |
332 | dccp_header_size, 1, | ||
333 | GFP_ATOMIC); | 340 | GFP_ATOMIC); |
334 | if (skb == NULL) | 341 | if (skb == NULL) |
335 | return NULL; | 342 | return NULL; |
336 | 343 | ||
337 | /* Reserve space for headers. */ | 344 | /* Reserve space for headers. */ |
338 | skb_reserve(skb, MAX_HEADER + DCCP_MAX_OPT_LEN + dccp_header_size); | 345 | skb_reserve(skb, sk->sk_prot->max_header); |
339 | 346 | ||
340 | skb->dst = dst_clone(dst); | 347 | skb->dst = dst_clone(dst); |
341 | skb->csum = 0; | 348 | skb->csum = 0; |
@@ -345,7 +352,11 @@ struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst, | |||
345 | DCCP_SKB_CB(skb)->dccpd_reset_code = code; | 352 | DCCP_SKB_CB(skb)->dccpd_reset_code = code; |
346 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESET; | 353 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESET; |
347 | DCCP_SKB_CB(skb)->dccpd_seq = dp->dccps_gss; | 354 | DCCP_SKB_CB(skb)->dccpd_seq = dp->dccps_gss; |
348 | dccp_insert_options(sk, skb); | 355 | |
356 | if (dccp_insert_options(sk, skb)) { | ||
357 | kfree_skb(skb); | ||
358 | return NULL; | ||
359 | } | ||
349 | 360 | ||
350 | skb->h.raw = skb_push(skb, dccp_header_size); | 361 | skb->h.raw = skb_push(skb, dccp_header_size); |
351 | 362 | ||
@@ -362,14 +373,34 @@ struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst, | |||
362 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dp->dccps_gsr); | 373 | dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dp->dccps_gsr); |
363 | 374 | ||
364 | dccp_hdr_reset(skb)->dccph_reset_code = code; | 375 | dccp_hdr_reset(skb)->dccph_reset_code = code; |
365 | 376 | inet_csk(sk)->icsk_af_ops->send_check(sk, skb->len, skb); | |
366 | dh->dccph_checksum = dccp_v4_checksum(skb, inet_sk(sk)->saddr, | ||
367 | inet_sk(sk)->daddr); | ||
368 | 377 | ||
369 | DCCP_INC_STATS(DCCP_MIB_OUTSEGS); | 378 | DCCP_INC_STATS(DCCP_MIB_OUTSEGS); |
370 | return skb; | 379 | return skb; |
371 | } | 380 | } |
372 | 381 | ||
382 | int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code) | ||
383 | { | ||
384 | /* | ||
385 | * FIXME: what if rebuild_header fails? | ||
386 | * Should we be doing a rebuild_header here? | ||
387 | */ | ||
388 | int err = inet_sk_rebuild_header(sk); | ||
389 | |||
390 | if (err == 0) { | ||
391 | struct sk_buff *skb = dccp_make_reset(sk, sk->sk_dst_cache, | ||
392 | code); | ||
393 | if (skb != NULL) { | ||
394 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); | ||
395 | err = inet_csk(sk)->icsk_af_ops->queue_xmit(skb, 0); | ||
396 | if (err == NET_XMIT_CN) | ||
397 | err = 0; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | return err; | ||
402 | } | ||
403 | |||
373 | /* | 404 | /* |
374 | * Do all connect socket setups that can be done AF independent. | 405 | * Do all connect socket setups that can be done AF independent. |
375 | */ | 406 | */ |
@@ -405,12 +436,12 @@ int dccp_connect(struct sock *sk) | |||
405 | 436 | ||
406 | dccp_connect_init(sk); | 437 | dccp_connect_init(sk); |
407 | 438 | ||
408 | skb = alloc_skb(MAX_DCCP_HEADER + 15, sk->sk_allocation); | 439 | skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation); |
409 | if (unlikely(skb == NULL)) | 440 | if (unlikely(skb == NULL)) |
410 | return -ENOBUFS; | 441 | return -ENOBUFS; |
411 | 442 | ||
412 | /* Reserve space for headers. */ | 443 | /* Reserve space for headers. */ |
413 | skb_reserve(skb, MAX_DCCP_HEADER); | 444 | skb_reserve(skb, sk->sk_prot->max_header); |
414 | 445 | ||
415 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST; | 446 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST; |
416 | skb->csum = 0; | 447 | skb->csum = 0; |
@@ -431,7 +462,8 @@ void dccp_send_ack(struct sock *sk) | |||
431 | { | 462 | { |
432 | /* If we have been reset, we may not send again. */ | 463 | /* If we have been reset, we may not send again. */ |
433 | if (sk->sk_state != DCCP_CLOSED) { | 464 | if (sk->sk_state != DCCP_CLOSED) { |
434 | struct sk_buff *skb = alloc_skb(MAX_DCCP_HEADER, GFP_ATOMIC); | 465 | struct sk_buff *skb = alloc_skb(sk->sk_prot->max_header, |
466 | GFP_ATOMIC); | ||
435 | 467 | ||
436 | if (skb == NULL) { | 468 | if (skb == NULL) { |
437 | inet_csk_schedule_ack(sk); | 469 | inet_csk_schedule_ack(sk); |
@@ -443,7 +475,7 @@ void dccp_send_ack(struct sock *sk) | |||
443 | } | 475 | } |
444 | 476 | ||
445 | /* Reserve space for headers */ | 477 | /* Reserve space for headers */ |
446 | skb_reserve(skb, MAX_DCCP_HEADER); | 478 | skb_reserve(skb, sk->sk_prot->max_header); |
447 | skb->csum = 0; | 479 | skb->csum = 0; |
448 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_ACK; | 480 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_ACK; |
449 | dccp_transmit_skb(sk, skb); | 481 | dccp_transmit_skb(sk, skb); |
@@ -490,14 +522,14 @@ void dccp_send_sync(struct sock *sk, const u64 seq, | |||
490 | * dccp_transmit_skb() will set the ownership to this | 522 | * dccp_transmit_skb() will set the ownership to this |
491 | * sock. | 523 | * sock. |
492 | */ | 524 | */ |
493 | struct sk_buff *skb = alloc_skb(MAX_DCCP_HEADER, GFP_ATOMIC); | 525 | struct sk_buff *skb = alloc_skb(sk->sk_prot->max_header, GFP_ATOMIC); |
494 | 526 | ||
495 | if (skb == NULL) | 527 | if (skb == NULL) |
496 | /* FIXME: how to make sure the sync is sent? */ | 528 | /* FIXME: how to make sure the sync is sent? */ |
497 | return; | 529 | return; |
498 | 530 | ||
499 | /* Reserve space for headers and prepare control bits. */ | 531 | /* Reserve space for headers and prepare control bits. */ |
500 | skb_reserve(skb, MAX_DCCP_HEADER); | 532 | skb_reserve(skb, sk->sk_prot->max_header); |
501 | skb->csum = 0; | 533 | skb->csum = 0; |
502 | DCCP_SKB_CB(skb)->dccpd_type = pkt_type; | 534 | DCCP_SKB_CB(skb)->dccpd_type = pkt_type; |
503 | DCCP_SKB_CB(skb)->dccpd_seq = seq; | 535 | DCCP_SKB_CB(skb)->dccpd_seq = seq; |
@@ -505,6 +537,8 @@ void dccp_send_sync(struct sock *sk, const u64 seq, | |||
505 | dccp_transmit_skb(sk, skb); | 537 | dccp_transmit_skb(sk, skb); |
506 | } | 538 | } |
507 | 539 | ||
540 | EXPORT_SYMBOL_GPL(dccp_send_sync); | ||
541 | |||
508 | /* | 542 | /* |
509 | * Send a DCCP_PKT_CLOSE/CLOSEREQ. The caller locks the socket for us. This | 543 | * Send a DCCP_PKT_CLOSE/CLOSEREQ. The caller locks the socket for us. This |
510 | * cannot be allowed to fail queueing a DCCP_PKT_CLOSE/CLOSEREQ frame under | 544 | * cannot be allowed to fail queueing a DCCP_PKT_CLOSE/CLOSEREQ frame under |
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 65b11ea90d85..d4b293e16283 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
@@ -23,9 +23,7 @@ | |||
23 | #include <linux/random.h> | 23 | #include <linux/random.h> |
24 | #include <net/checksum.h> | 24 | #include <net/checksum.h> |
25 | 25 | ||
26 | #include <net/inet_common.h> | ||
27 | #include <net/inet_sock.h> | 26 | #include <net/inet_sock.h> |
28 | #include <net/protocol.h> | ||
29 | #include <net/sock.h> | 27 | #include <net/sock.h> |
30 | #include <net/xfrm.h> | 28 | #include <net/xfrm.h> |
31 | 29 | ||
@@ -37,6 +35,7 @@ | |||
37 | 35 | ||
38 | #include "ccid.h" | 36 | #include "ccid.h" |
39 | #include "dccp.h" | 37 | #include "dccp.h" |
38 | #include "feat.h" | ||
40 | 39 | ||
41 | DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly; | 40 | DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly; |
42 | 41 | ||
@@ -46,12 +45,66 @@ atomic_t dccp_orphan_count = ATOMIC_INIT(0); | |||
46 | 45 | ||
47 | EXPORT_SYMBOL_GPL(dccp_orphan_count); | 46 | EXPORT_SYMBOL_GPL(dccp_orphan_count); |
48 | 47 | ||
49 | static struct net_protocol dccp_protocol = { | 48 | struct inet_hashinfo __cacheline_aligned dccp_hashinfo = { |
50 | .handler = dccp_v4_rcv, | 49 | .lhash_lock = RW_LOCK_UNLOCKED, |
51 | .err_handler = dccp_v4_err, | 50 | .lhash_users = ATOMIC_INIT(0), |
52 | .no_policy = 1, | 51 | .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait), |
53 | }; | 52 | }; |
54 | 53 | ||
54 | EXPORT_SYMBOL_GPL(dccp_hashinfo); | ||
55 | |||
56 | void dccp_set_state(struct sock *sk, const int state) | ||
57 | { | ||
58 | const int oldstate = sk->sk_state; | ||
59 | |||
60 | dccp_pr_debug("%s(%p) %-10.10s -> %s\n", | ||
61 | dccp_role(sk), sk, | ||
62 | dccp_state_name(oldstate), dccp_state_name(state)); | ||
63 | WARN_ON(state == oldstate); | ||
64 | |||
65 | switch (state) { | ||
66 | case DCCP_OPEN: | ||
67 | if (oldstate != DCCP_OPEN) | ||
68 | DCCP_INC_STATS(DCCP_MIB_CURRESTAB); | ||
69 | break; | ||
70 | |||
71 | case DCCP_CLOSED: | ||
72 | if (oldstate == DCCP_CLOSING || oldstate == DCCP_OPEN) | ||
73 | DCCP_INC_STATS(DCCP_MIB_ESTABRESETS); | ||
74 | |||
75 | sk->sk_prot->unhash(sk); | ||
76 | if (inet_csk(sk)->icsk_bind_hash != NULL && | ||
77 | !(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) | ||
78 | inet_put_port(&dccp_hashinfo, sk); | ||
79 | /* fall through */ | ||
80 | default: | ||
81 | if (oldstate == DCCP_OPEN) | ||
82 | DCCP_DEC_STATS(DCCP_MIB_CURRESTAB); | ||
83 | } | ||
84 | |||
85 | /* Change state AFTER socket is unhashed to avoid closed | ||
86 | * socket sitting in hash tables. | ||
87 | */ | ||
88 | sk->sk_state = state; | ||
89 | } | ||
90 | |||
91 | EXPORT_SYMBOL_GPL(dccp_set_state); | ||
92 | |||
93 | void dccp_done(struct sock *sk) | ||
94 | { | ||
95 | dccp_set_state(sk, DCCP_CLOSED); | ||
96 | dccp_clear_xmit_timers(sk); | ||
97 | |||
98 | sk->sk_shutdown = SHUTDOWN_MASK; | ||
99 | |||
100 | if (!sock_flag(sk, SOCK_DEAD)) | ||
101 | sk->sk_state_change(sk); | ||
102 | else | ||
103 | inet_csk_destroy_sock(sk); | ||
104 | } | ||
105 | |||
106 | EXPORT_SYMBOL_GPL(dccp_done); | ||
107 | |||
55 | const char *dccp_packet_name(const int type) | 108 | const char *dccp_packet_name(const int type) |
56 | { | 109 | { |
57 | static const char *dccp_packet_names[] = { | 110 | static const char *dccp_packet_names[] = { |
@@ -96,6 +149,120 @@ const char *dccp_state_name(const int state) | |||
96 | 149 | ||
97 | EXPORT_SYMBOL_GPL(dccp_state_name); | 150 | EXPORT_SYMBOL_GPL(dccp_state_name); |
98 | 151 | ||
152 | void dccp_hash(struct sock *sk) | ||
153 | { | ||
154 | inet_hash(&dccp_hashinfo, sk); | ||
155 | } | ||
156 | |||
157 | EXPORT_SYMBOL_GPL(dccp_hash); | ||
158 | |||
159 | void dccp_unhash(struct sock *sk) | ||
160 | { | ||
161 | inet_unhash(&dccp_hashinfo, sk); | ||
162 | } | ||
163 | |||
164 | EXPORT_SYMBOL_GPL(dccp_unhash); | ||
165 | |||
166 | int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) | ||
167 | { | ||
168 | struct dccp_sock *dp = dccp_sk(sk); | ||
169 | struct dccp_minisock *dmsk = dccp_msk(sk); | ||
170 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
171 | |||
172 | dccp_minisock_init(&dp->dccps_minisock); | ||
173 | do_gettimeofday(&dp->dccps_epoch); | ||
174 | |||
175 | /* | ||
176 | * FIXME: We're hardcoding the CCID, and doing this at this point makes | ||
177 | * the listening (master) sock get CCID control blocks, which is not | ||
178 | * necessary, but for now, to not mess with the test userspace apps, | ||
179 | * lets leave it here, later the real solution is to do this in a | ||
180 | * setsockopt(CCIDs-I-want/accept). -acme | ||
181 | */ | ||
182 | if (likely(ctl_sock_initialized)) { | ||
183 | int rc = dccp_feat_init(dmsk); | ||
184 | |||
185 | if (rc) | ||
186 | return rc; | ||
187 | |||
188 | if (dmsk->dccpms_send_ack_vector) { | ||
189 | dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL); | ||
190 | if (dp->dccps_hc_rx_ackvec == NULL) | ||
191 | return -ENOMEM; | ||
192 | } | ||
193 | dp->dccps_hc_rx_ccid = ccid_hc_rx_new(dmsk->dccpms_rx_ccid, | ||
194 | sk, GFP_KERNEL); | ||
195 | dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid, | ||
196 | sk, GFP_KERNEL); | ||
197 | if (unlikely(dp->dccps_hc_rx_ccid == NULL || | ||
198 | dp->dccps_hc_tx_ccid == NULL)) { | ||
199 | ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); | ||
200 | ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); | ||
201 | if (dmsk->dccpms_send_ack_vector) { | ||
202 | dccp_ackvec_free(dp->dccps_hc_rx_ackvec); | ||
203 | dp->dccps_hc_rx_ackvec = NULL; | ||
204 | } | ||
205 | dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; | ||
206 | return -ENOMEM; | ||
207 | } | ||
208 | } else { | ||
209 | /* control socket doesn't need feat nego */ | ||
210 | INIT_LIST_HEAD(&dmsk->dccpms_pending); | ||
211 | INIT_LIST_HEAD(&dmsk->dccpms_conf); | ||
212 | } | ||
213 | |||
214 | dccp_init_xmit_timers(sk); | ||
215 | icsk->icsk_rto = DCCP_TIMEOUT_INIT; | ||
216 | sk->sk_state = DCCP_CLOSED; | ||
217 | sk->sk_write_space = dccp_write_space; | ||
218 | icsk->icsk_sync_mss = dccp_sync_mss; | ||
219 | dp->dccps_mss_cache = 536; | ||
220 | dp->dccps_role = DCCP_ROLE_UNDEFINED; | ||
221 | dp->dccps_service = DCCP_SERVICE_INVALID_VALUE; | ||
222 | dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1; | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | EXPORT_SYMBOL_GPL(dccp_init_sock); | ||
228 | |||
229 | int dccp_destroy_sock(struct sock *sk) | ||
230 | { | ||
231 | struct dccp_sock *dp = dccp_sk(sk); | ||
232 | struct dccp_minisock *dmsk = dccp_msk(sk); | ||
233 | |||
234 | /* | ||
235 | * DCCP doesn't use sk_write_queue, just sk_send_head | ||
236 | * for retransmissions | ||
237 | */ | ||
238 | if (sk->sk_send_head != NULL) { | ||
239 | kfree_skb(sk->sk_send_head); | ||
240 | sk->sk_send_head = NULL; | ||
241 | } | ||
242 | |||
243 | /* Clean up a referenced DCCP bind bucket. */ | ||
244 | if (inet_csk(sk)->icsk_bind_hash != NULL) | ||
245 | inet_put_port(&dccp_hashinfo, sk); | ||
246 | |||
247 | kfree(dp->dccps_service_list); | ||
248 | dp->dccps_service_list = NULL; | ||
249 | |||
250 | if (dmsk->dccpms_send_ack_vector) { | ||
251 | dccp_ackvec_free(dp->dccps_hc_rx_ackvec); | ||
252 | dp->dccps_hc_rx_ackvec = NULL; | ||
253 | } | ||
254 | ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); | ||
255 | ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); | ||
256 | dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; | ||
257 | |||
258 | /* clean up feature negotiation state */ | ||
259 | dccp_feat_clean(dmsk); | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | EXPORT_SYMBOL_GPL(dccp_destroy_sock); | ||
265 | |||
99 | static inline int dccp_listen_start(struct sock *sk) | 266 | static inline int dccp_listen_start(struct sock *sk) |
100 | { | 267 | { |
101 | struct dccp_sock *dp = dccp_sk(sk); | 268 | struct dccp_sock *dp = dccp_sk(sk); |
@@ -220,7 +387,7 @@ int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
220 | 387 | ||
221 | EXPORT_SYMBOL_GPL(dccp_ioctl); | 388 | EXPORT_SYMBOL_GPL(dccp_ioctl); |
222 | 389 | ||
223 | static int dccp_setsockopt_service(struct sock *sk, const u32 service, | 390 | static int dccp_setsockopt_service(struct sock *sk, const __be32 service, |
224 | char __user *optval, int optlen) | 391 | char __user *optval, int optlen) |
225 | { | 392 | { |
226 | struct dccp_sock *dp = dccp_sk(sk); | 393 | struct dccp_sock *dp = dccp_sk(sk); |
@@ -255,18 +422,46 @@ static int dccp_setsockopt_service(struct sock *sk, const u32 service, | |||
255 | return 0; | 422 | return 0; |
256 | } | 423 | } |
257 | 424 | ||
258 | int dccp_setsockopt(struct sock *sk, int level, int optname, | 425 | /* byte 1 is feature. the rest is the preference list */ |
259 | char __user *optval, int optlen) | 426 | static int dccp_setsockopt_change(struct sock *sk, int type, |
427 | struct dccp_so_feat __user *optval) | ||
428 | { | ||
429 | struct dccp_so_feat opt; | ||
430 | u8 *val; | ||
431 | int rc; | ||
432 | |||
433 | if (copy_from_user(&opt, optval, sizeof(opt))) | ||
434 | return -EFAULT; | ||
435 | |||
436 | val = kmalloc(opt.dccpsf_len, GFP_KERNEL); | ||
437 | if (!val) | ||
438 | return -ENOMEM; | ||
439 | |||
440 | if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) { | ||
441 | rc = -EFAULT; | ||
442 | goto out_free_val; | ||
443 | } | ||
444 | |||
445 | rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat, | ||
446 | val, opt.dccpsf_len, GFP_KERNEL); | ||
447 | if (rc) | ||
448 | goto out_free_val; | ||
449 | |||
450 | out: | ||
451 | return rc; | ||
452 | |||
453 | out_free_val: | ||
454 | kfree(val); | ||
455 | goto out; | ||
456 | } | ||
457 | |||
458 | static int do_dccp_setsockopt(struct sock *sk, int level, int optname, | ||
459 | char __user *optval, int optlen) | ||
260 | { | 460 | { |
261 | struct dccp_sock *dp; | 461 | struct dccp_sock *dp; |
262 | int err; | 462 | int err; |
263 | int val; | 463 | int val; |
264 | 464 | ||
265 | if (level != SOL_DCCP) | ||
266 | return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level, | ||
267 | optname, optval, | ||
268 | optlen); | ||
269 | |||
270 | if (optlen < sizeof(int)) | 465 | if (optlen < sizeof(int)) |
271 | return -EINVAL; | 466 | return -EINVAL; |
272 | 467 | ||
@@ -284,6 +479,25 @@ int dccp_setsockopt(struct sock *sk, int level, int optname, | |||
284 | case DCCP_SOCKOPT_PACKET_SIZE: | 479 | case DCCP_SOCKOPT_PACKET_SIZE: |
285 | dp->dccps_packet_size = val; | 480 | dp->dccps_packet_size = val; |
286 | break; | 481 | break; |
482 | |||
483 | case DCCP_SOCKOPT_CHANGE_L: | ||
484 | if (optlen != sizeof(struct dccp_so_feat)) | ||
485 | err = -EINVAL; | ||
486 | else | ||
487 | err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L, | ||
488 | (struct dccp_so_feat *) | ||
489 | optval); | ||
490 | break; | ||
491 | |||
492 | case DCCP_SOCKOPT_CHANGE_R: | ||
493 | if (optlen != sizeof(struct dccp_so_feat)) | ||
494 | err = -EINVAL; | ||
495 | else | ||
496 | err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R, | ||
497 | (struct dccp_so_feat *) | ||
498 | optval); | ||
499 | break; | ||
500 | |||
287 | default: | 501 | default: |
288 | err = -ENOPROTOOPT; | 502 | err = -ENOPROTOOPT; |
289 | break; | 503 | break; |
@@ -293,10 +507,33 @@ int dccp_setsockopt(struct sock *sk, int level, int optname, | |||
293 | return err; | 507 | return err; |
294 | } | 508 | } |
295 | 509 | ||
510 | int dccp_setsockopt(struct sock *sk, int level, int optname, | ||
511 | char __user *optval, int optlen) | ||
512 | { | ||
513 | if (level != SOL_DCCP) | ||
514 | return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level, | ||
515 | optname, optval, | ||
516 | optlen); | ||
517 | return do_dccp_setsockopt(sk, level, optname, optval, optlen); | ||
518 | } | ||
519 | |||
296 | EXPORT_SYMBOL_GPL(dccp_setsockopt); | 520 | EXPORT_SYMBOL_GPL(dccp_setsockopt); |
297 | 521 | ||
522 | #ifdef CONFIG_COMPAT | ||
523 | int compat_dccp_setsockopt(struct sock *sk, int level, int optname, | ||
524 | char __user *optval, int optlen) | ||
525 | { | ||
526 | if (level != SOL_DCCP) | ||
527 | return inet_csk_compat_setsockopt(sk, level, optname, | ||
528 | optval, optlen); | ||
529 | return do_dccp_setsockopt(sk, level, optname, optval, optlen); | ||
530 | } | ||
531 | |||
532 | EXPORT_SYMBOL_GPL(compat_dccp_setsockopt); | ||
533 | #endif | ||
534 | |||
298 | static int dccp_getsockopt_service(struct sock *sk, int len, | 535 | static int dccp_getsockopt_service(struct sock *sk, int len, |
299 | u32 __user *optval, | 536 | __be32 __user *optval, |
300 | int __user *optlen) | 537 | int __user *optlen) |
301 | { | 538 | { |
302 | const struct dccp_sock *dp = dccp_sk(sk); | 539 | const struct dccp_sock *dp = dccp_sk(sk); |
@@ -326,16 +563,12 @@ out: | |||
326 | return err; | 563 | return err; |
327 | } | 564 | } |
328 | 565 | ||
329 | int dccp_getsockopt(struct sock *sk, int level, int optname, | 566 | static int do_dccp_getsockopt(struct sock *sk, int level, int optname, |
330 | char __user *optval, int __user *optlen) | 567 | char __user *optval, int __user *optlen) |
331 | { | 568 | { |
332 | struct dccp_sock *dp; | 569 | struct dccp_sock *dp; |
333 | int val, len; | 570 | int val, len; |
334 | 571 | ||
335 | if (level != SOL_DCCP) | ||
336 | return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level, | ||
337 | optname, optval, | ||
338 | optlen); | ||
339 | if (get_user(len, optlen)) | 572 | if (get_user(len, optlen)) |
340 | return -EFAULT; | 573 | return -EFAULT; |
341 | 574 | ||
@@ -351,7 +584,7 @@ int dccp_getsockopt(struct sock *sk, int level, int optname, | |||
351 | break; | 584 | break; |
352 | case DCCP_SOCKOPT_SERVICE: | 585 | case DCCP_SOCKOPT_SERVICE: |
353 | return dccp_getsockopt_service(sk, len, | 586 | return dccp_getsockopt_service(sk, len, |
354 | (u32 __user *)optval, optlen); | 587 | (__be32 __user *)optval, optlen); |
355 | case 128 ... 191: | 588 | case 128 ... 191: |
356 | return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, | 589 | return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, |
357 | len, (u32 __user *)optval, optlen); | 590 | len, (u32 __user *)optval, optlen); |
@@ -368,8 +601,31 @@ int dccp_getsockopt(struct sock *sk, int level, int optname, | |||
368 | return 0; | 601 | return 0; |
369 | } | 602 | } |
370 | 603 | ||
604 | int dccp_getsockopt(struct sock *sk, int level, int optname, | ||
605 | char __user *optval, int __user *optlen) | ||
606 | { | ||
607 | if (level != SOL_DCCP) | ||
608 | return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level, | ||
609 | optname, optval, | ||
610 | optlen); | ||
611 | return do_dccp_getsockopt(sk, level, optname, optval, optlen); | ||
612 | } | ||
613 | |||
371 | EXPORT_SYMBOL_GPL(dccp_getsockopt); | 614 | EXPORT_SYMBOL_GPL(dccp_getsockopt); |
372 | 615 | ||
616 | #ifdef CONFIG_COMPAT | ||
617 | int compat_dccp_getsockopt(struct sock *sk, int level, int optname, | ||
618 | char __user *optval, int __user *optlen) | ||
619 | { | ||
620 | if (level != SOL_DCCP) | ||
621 | return inet_csk_compat_getsockopt(sk, level, optname, | ||
622 | optval, optlen); | ||
623 | return do_dccp_getsockopt(sk, level, optname, optval, optlen); | ||
624 | } | ||
625 | |||
626 | EXPORT_SYMBOL_GPL(compat_dccp_getsockopt); | ||
627 | #endif | ||
628 | |||
373 | int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 629 | int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
374 | size_t len) | 630 | size_t len) |
375 | { | 631 | { |
@@ -679,84 +935,7 @@ void dccp_shutdown(struct sock *sk, int how) | |||
679 | 935 | ||
680 | EXPORT_SYMBOL_GPL(dccp_shutdown); | 936 | EXPORT_SYMBOL_GPL(dccp_shutdown); |
681 | 937 | ||
682 | static const struct proto_ops inet_dccp_ops = { | 938 | static int __init dccp_mib_init(void) |
683 | .family = PF_INET, | ||
684 | .owner = THIS_MODULE, | ||
685 | .release = inet_release, | ||
686 | .bind = inet_bind, | ||
687 | .connect = inet_stream_connect, | ||
688 | .socketpair = sock_no_socketpair, | ||
689 | .accept = inet_accept, | ||
690 | .getname = inet_getname, | ||
691 | /* FIXME: work on tcp_poll to rename it to inet_csk_poll */ | ||
692 | .poll = dccp_poll, | ||
693 | .ioctl = inet_ioctl, | ||
694 | /* FIXME: work on inet_listen to rename it to sock_common_listen */ | ||
695 | .listen = inet_dccp_listen, | ||
696 | .shutdown = inet_shutdown, | ||
697 | .setsockopt = sock_common_setsockopt, | ||
698 | .getsockopt = sock_common_getsockopt, | ||
699 | .sendmsg = inet_sendmsg, | ||
700 | .recvmsg = sock_common_recvmsg, | ||
701 | .mmap = sock_no_mmap, | ||
702 | .sendpage = sock_no_sendpage, | ||
703 | }; | ||
704 | |||
705 | extern struct net_proto_family inet_family_ops; | ||
706 | |||
707 | static struct inet_protosw dccp_v4_protosw = { | ||
708 | .type = SOCK_DCCP, | ||
709 | .protocol = IPPROTO_DCCP, | ||
710 | .prot = &dccp_prot, | ||
711 | .ops = &inet_dccp_ops, | ||
712 | .capability = -1, | ||
713 | .no_check = 0, | ||
714 | .flags = INET_PROTOSW_ICSK, | ||
715 | }; | ||
716 | |||
717 | /* | ||
718 | * This is the global socket data structure used for responding to | ||
719 | * the Out-of-the-blue (OOTB) packets. A control sock will be created | ||
720 | * for this socket at the initialization time. | ||
721 | */ | ||
722 | struct socket *dccp_ctl_socket; | ||
723 | |||
724 | static char dccp_ctl_socket_err_msg[] __initdata = | ||
725 | KERN_ERR "DCCP: Failed to create the control socket.\n"; | ||
726 | |||
727 | static int __init dccp_ctl_sock_init(void) | ||
728 | { | ||
729 | int rc = sock_create_kern(PF_INET, SOCK_DCCP, IPPROTO_DCCP, | ||
730 | &dccp_ctl_socket); | ||
731 | if (rc < 0) | ||
732 | printk(dccp_ctl_socket_err_msg); | ||
733 | else { | ||
734 | dccp_ctl_socket->sk->sk_allocation = GFP_ATOMIC; | ||
735 | inet_sk(dccp_ctl_socket->sk)->uc_ttl = -1; | ||
736 | |||
737 | /* Unhash it so that IP input processing does not even | ||
738 | * see it, we do not wish this socket to see incoming | ||
739 | * packets. | ||
740 | */ | ||
741 | dccp_ctl_socket->sk->sk_prot->unhash(dccp_ctl_socket->sk); | ||
742 | } | ||
743 | |||
744 | return rc; | ||
745 | } | ||
746 | |||
747 | #ifdef CONFIG_IP_DCCP_UNLOAD_HACK | ||
748 | void dccp_ctl_sock_exit(void) | ||
749 | { | ||
750 | if (dccp_ctl_socket != NULL) { | ||
751 | sock_release(dccp_ctl_socket); | ||
752 | dccp_ctl_socket = NULL; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | EXPORT_SYMBOL_GPL(dccp_ctl_sock_exit); | ||
757 | #endif | ||
758 | |||
759 | static int __init init_dccp_v4_mibs(void) | ||
760 | { | 939 | { |
761 | int rc = -ENOMEM; | 940 | int rc = -ENOMEM; |
762 | 941 | ||
@@ -778,6 +957,13 @@ out_free_one: | |||
778 | 957 | ||
779 | } | 958 | } |
780 | 959 | ||
960 | static void dccp_mib_exit(void) | ||
961 | { | ||
962 | free_percpu(dccp_statistics[0]); | ||
963 | free_percpu(dccp_statistics[1]); | ||
964 | dccp_statistics[0] = dccp_statistics[1] = NULL; | ||
965 | } | ||
966 | |||
781 | static int thash_entries; | 967 | static int thash_entries; |
782 | module_param(thash_entries, int, 0444); | 968 | module_param(thash_entries, int, 0444); |
783 | MODULE_PARM_DESC(thash_entries, "Number of ehash buckets"); | 969 | MODULE_PARM_DESC(thash_entries, "Number of ehash buckets"); |
@@ -794,17 +980,14 @@ static int __init dccp_init(void) | |||
794 | { | 980 | { |
795 | unsigned long goal; | 981 | unsigned long goal; |
796 | int ehash_order, bhash_order, i; | 982 | int ehash_order, bhash_order, i; |
797 | int rc = proto_register(&dccp_prot, 1); | 983 | int rc = -ENOBUFS; |
798 | |||
799 | if (rc) | ||
800 | goto out; | ||
801 | 984 | ||
802 | dccp_hashinfo.bind_bucket_cachep = | 985 | dccp_hashinfo.bind_bucket_cachep = |
803 | kmem_cache_create("dccp_bind_bucket", | 986 | kmem_cache_create("dccp_bind_bucket", |
804 | sizeof(struct inet_bind_bucket), 0, | 987 | sizeof(struct inet_bind_bucket), 0, |
805 | SLAB_HWCACHE_ALIGN, NULL, NULL); | 988 | SLAB_HWCACHE_ALIGN, NULL, NULL); |
806 | if (!dccp_hashinfo.bind_bucket_cachep) | 989 | if (!dccp_hashinfo.bind_bucket_cachep) |
807 | goto out_proto_unregister; | 990 | goto out; |
808 | 991 | ||
809 | /* | 992 | /* |
810 | * Size and allocate the main established and bind bucket | 993 | * Size and allocate the main established and bind bucket |
@@ -866,27 +1049,23 @@ static int __init dccp_init(void) | |||
866 | INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain); | 1049 | INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain); |
867 | } | 1050 | } |
868 | 1051 | ||
869 | if (init_dccp_v4_mibs()) | 1052 | rc = dccp_mib_init(); |
1053 | if (rc) | ||
870 | goto out_free_dccp_bhash; | 1054 | goto out_free_dccp_bhash; |
871 | 1055 | ||
872 | rc = -EAGAIN; | 1056 | rc = dccp_ackvec_init(); |
873 | if (inet_add_protocol(&dccp_protocol, IPPROTO_DCCP)) | 1057 | if (rc) |
874 | goto out_free_dccp_v4_mibs; | 1058 | goto out_free_dccp_mib; |
875 | |||
876 | inet_register_protosw(&dccp_v4_protosw); | ||
877 | 1059 | ||
878 | rc = dccp_ctl_sock_init(); | 1060 | rc = dccp_sysctl_init(); |
879 | if (rc) | 1061 | if (rc) |
880 | goto out_unregister_protosw; | 1062 | goto out_ackvec_exit; |
881 | out: | 1063 | out: |
882 | return rc; | 1064 | return rc; |
883 | out_unregister_protosw: | 1065 | out_ackvec_exit: |
884 | inet_unregister_protosw(&dccp_v4_protosw); | 1066 | dccp_ackvec_exit(); |
885 | inet_del_protocol(&dccp_protocol, IPPROTO_DCCP); | 1067 | out_free_dccp_mib: |
886 | out_free_dccp_v4_mibs: | 1068 | dccp_mib_exit(); |
887 | free_percpu(dccp_statistics[0]); | ||
888 | free_percpu(dccp_statistics[1]); | ||
889 | dccp_statistics[0] = dccp_statistics[1] = NULL; | ||
890 | out_free_dccp_bhash: | 1069 | out_free_dccp_bhash: |
891 | free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order); | 1070 | free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order); |
892 | dccp_hashinfo.bhash = NULL; | 1071 | dccp_hashinfo.bhash = NULL; |
@@ -896,23 +1075,12 @@ out_free_dccp_ehash: | |||
896 | out_free_bind_bucket_cachep: | 1075 | out_free_bind_bucket_cachep: |
897 | kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); | 1076 | kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); |
898 | dccp_hashinfo.bind_bucket_cachep = NULL; | 1077 | dccp_hashinfo.bind_bucket_cachep = NULL; |
899 | out_proto_unregister: | ||
900 | proto_unregister(&dccp_prot); | ||
901 | goto out; | 1078 | goto out; |
902 | } | 1079 | } |
903 | 1080 | ||
904 | static const char dccp_del_proto_err_msg[] __exitdata = | ||
905 | KERN_ERR "can't remove dccp net_protocol\n"; | ||
906 | |||
907 | static void __exit dccp_fini(void) | 1081 | static void __exit dccp_fini(void) |
908 | { | 1082 | { |
909 | inet_unregister_protosw(&dccp_v4_protosw); | 1083 | dccp_mib_exit(); |
910 | |||
911 | if (inet_del_protocol(&dccp_protocol, IPPROTO_DCCP) < 0) | ||
912 | printk(dccp_del_proto_err_msg); | ||
913 | |||
914 | free_percpu(dccp_statistics[0]); | ||
915 | free_percpu(dccp_statistics[1]); | ||
916 | free_pages((unsigned long)dccp_hashinfo.bhash, | 1084 | free_pages((unsigned long)dccp_hashinfo.bhash, |
917 | get_order(dccp_hashinfo.bhash_size * | 1085 | get_order(dccp_hashinfo.bhash_size * |
918 | sizeof(struct inet_bind_hashbucket))); | 1086 | sizeof(struct inet_bind_hashbucket))); |
@@ -920,19 +1088,13 @@ static void __exit dccp_fini(void) | |||
920 | get_order(dccp_hashinfo.ehash_size * | 1088 | get_order(dccp_hashinfo.ehash_size * |
921 | sizeof(struct inet_ehash_bucket))); | 1089 | sizeof(struct inet_ehash_bucket))); |
922 | kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); | 1090 | kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); |
923 | proto_unregister(&dccp_prot); | 1091 | dccp_ackvec_exit(); |
1092 | dccp_sysctl_exit(); | ||
924 | } | 1093 | } |
925 | 1094 | ||
926 | module_init(dccp_init); | 1095 | module_init(dccp_init); |
927 | module_exit(dccp_fini); | 1096 | module_exit(dccp_fini); |
928 | 1097 | ||
929 | /* | ||
930 | * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33) | ||
931 | * values directly, Also cover the case where the protocol is not specified, | ||
932 | * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP | ||
933 | */ | ||
934 | MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6"); | ||
935 | MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6"); | ||
936 | MODULE_LICENSE("GPL"); | 1098 | MODULE_LICENSE("GPL"); |
937 | MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@conectiva.com.br>"); | 1099 | MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@conectiva.com.br>"); |
938 | MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol"); | 1100 | MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol"); |
diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c new file mode 100644 index 000000000000..64c89e9c229e --- /dev/null +++ b/net/dccp/sysctl.c | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * net/dccp/sysctl.c | ||
3 | * | ||
4 | * An implementation of the DCCP protocol | ||
5 | * Arnaldo Carvalho de Melo <acme@mandriva.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License v2 | ||
9 | * as published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/mm.h> | ||
14 | #include <linux/sysctl.h> | ||
15 | |||
16 | #ifndef CONFIG_SYSCTL | ||
17 | #error This file should not be compiled without CONFIG_SYSCTL defined | ||
18 | #endif | ||
19 | |||
20 | extern int dccp_feat_default_sequence_window; | ||
21 | extern int dccp_feat_default_rx_ccid; | ||
22 | extern int dccp_feat_default_tx_ccid; | ||
23 | extern int dccp_feat_default_ack_ratio; | ||
24 | extern int dccp_feat_default_send_ack_vector; | ||
25 | extern int dccp_feat_default_send_ndp_count; | ||
26 | |||
27 | static struct ctl_table dccp_default_table[] = { | ||
28 | { | ||
29 | .ctl_name = NET_DCCP_DEFAULT_SEQ_WINDOW, | ||
30 | .procname = "seq_window", | ||
31 | .data = &dccp_feat_default_sequence_window, | ||
32 | .maxlen = sizeof(dccp_feat_default_sequence_window), | ||
33 | .mode = 0644, | ||
34 | .proc_handler = proc_dointvec, | ||
35 | }, | ||
36 | { | ||
37 | .ctl_name = NET_DCCP_DEFAULT_RX_CCID, | ||
38 | .procname = "rx_ccid", | ||
39 | .data = &dccp_feat_default_rx_ccid, | ||
40 | .maxlen = sizeof(dccp_feat_default_rx_ccid), | ||
41 | .mode = 0644, | ||
42 | .proc_handler = proc_dointvec, | ||
43 | }, | ||
44 | { | ||
45 | .ctl_name = NET_DCCP_DEFAULT_TX_CCID, | ||
46 | .procname = "tx_ccid", | ||
47 | .data = &dccp_feat_default_tx_ccid, | ||
48 | .maxlen = sizeof(dccp_feat_default_tx_ccid), | ||
49 | .mode = 0644, | ||
50 | .proc_handler = proc_dointvec, | ||
51 | }, | ||
52 | { | ||
53 | .ctl_name = NET_DCCP_DEFAULT_ACK_RATIO, | ||
54 | .procname = "ack_ratio", | ||
55 | .data = &dccp_feat_default_ack_ratio, | ||
56 | .maxlen = sizeof(dccp_feat_default_ack_ratio), | ||
57 | .mode = 0644, | ||
58 | .proc_handler = proc_dointvec, | ||
59 | }, | ||
60 | { | ||
61 | .ctl_name = NET_DCCP_DEFAULT_SEND_ACKVEC, | ||
62 | .procname = "send_ackvec", | ||
63 | .data = &dccp_feat_default_send_ack_vector, | ||
64 | .maxlen = sizeof(dccp_feat_default_send_ack_vector), | ||
65 | .mode = 0644, | ||
66 | .proc_handler = proc_dointvec, | ||
67 | }, | ||
68 | { | ||
69 | .ctl_name = NET_DCCP_DEFAULT_SEND_NDP, | ||
70 | .procname = "send_ndp", | ||
71 | .data = &dccp_feat_default_send_ndp_count, | ||
72 | .maxlen = sizeof(dccp_feat_default_send_ndp_count), | ||
73 | .mode = 0644, | ||
74 | .proc_handler = proc_dointvec, | ||
75 | }, | ||
76 | { .ctl_name = 0, } | ||
77 | }; | ||
78 | |||
79 | static struct ctl_table dccp_table[] = { | ||
80 | { | ||
81 | .ctl_name = NET_DCCP_DEFAULT, | ||
82 | .procname = "default", | ||
83 | .mode = 0555, | ||
84 | .child = dccp_default_table, | ||
85 | }, | ||
86 | { .ctl_name = 0, }, | ||
87 | }; | ||
88 | |||
89 | static struct ctl_table dccp_dir_table[] = { | ||
90 | { | ||
91 | .ctl_name = NET_DCCP, | ||
92 | .procname = "dccp", | ||
93 | .mode = 0555, | ||
94 | .child = dccp_table, | ||
95 | }, | ||
96 | { .ctl_name = 0, }, | ||
97 | }; | ||
98 | |||
99 | static struct ctl_table dccp_root_table[] = { | ||
100 | { | ||
101 | .ctl_name = CTL_NET, | ||
102 | .procname = "net", | ||
103 | .mode = 0555, | ||
104 | .child = dccp_dir_table, | ||
105 | }, | ||
106 | { .ctl_name = 0, }, | ||
107 | }; | ||
108 | |||
109 | static struct ctl_table_header *dccp_table_header; | ||
110 | |||
111 | int __init dccp_sysctl_init(void) | ||
112 | { | ||
113 | dccp_table_header = register_sysctl_table(dccp_root_table, 1); | ||
114 | |||
115 | return dccp_table_header != NULL ? 0 : -ENOMEM; | ||
116 | } | ||
117 | |||
118 | void dccp_sysctl_exit(void) | ||
119 | { | ||
120 | if (dccp_table_header != NULL) { | ||
121 | unregister_sysctl_table(dccp_table_header); | ||
122 | dccp_table_header = NULL; | ||
123 | } | ||
124 | } | ||
diff --git a/net/dccp/timer.c b/net/dccp/timer.c index aa34b576e228..5244415e5f18 100644 --- a/net/dccp/timer.c +++ b/net/dccp/timer.c | |||
@@ -31,7 +31,7 @@ static void dccp_write_err(struct sock *sk) | |||
31 | sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT; | 31 | sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT; |
32 | sk->sk_error_report(sk); | 32 | sk->sk_error_report(sk); |
33 | 33 | ||
34 | dccp_v4_send_reset(sk, DCCP_RESET_CODE_ABORTED); | 34 | dccp_send_reset(sk, DCCP_RESET_CODE_ABORTED); |
35 | dccp_done(sk); | 35 | dccp_done(sk); |
36 | DCCP_INC_STATS_BH(DCCP_MIB_ABORTONTIMEOUT); | 36 | DCCP_INC_STATS_BH(DCCP_MIB_ABORTONTIMEOUT); |
37 | } | 37 | } |
@@ -141,6 +141,17 @@ static void dccp_retransmit_timer(struct sock *sk) | |||
141 | { | 141 | { |
142 | struct inet_connection_sock *icsk = inet_csk(sk); | 142 | struct inet_connection_sock *icsk = inet_csk(sk); |
143 | 143 | ||
144 | /* retransmit timer is used for feature negotiation throughout | ||
145 | * connection. In this case, no packet is re-transmitted, but rather an | ||
146 | * ack is generated and pending changes are splaced into its options. | ||
147 | */ | ||
148 | if (sk->sk_send_head == NULL) { | ||
149 | dccp_pr_debug("feat negotiation retransmit timeout %p\n", sk); | ||
150 | if (sk->sk_state == DCCP_OPEN) | ||
151 | dccp_send_ack(sk); | ||
152 | goto backoff; | ||
153 | } | ||
154 | |||
144 | /* | 155 | /* |
145 | * sk->sk_send_head has to have one skb with | 156 | * sk->sk_send_head has to have one skb with |
146 | * DCCP_SKB_CB(skb)->dccpd_type set to one of the retransmittable DCCP | 157 | * DCCP_SKB_CB(skb)->dccpd_type set to one of the retransmittable DCCP |
@@ -177,6 +188,7 @@ static void dccp_retransmit_timer(struct sock *sk) | |||
177 | goto out; | 188 | goto out; |
178 | } | 189 | } |
179 | 190 | ||
191 | backoff: | ||
180 | icsk->icsk_backoff++; | 192 | icsk->icsk_backoff++; |
181 | icsk->icsk_retransmits++; | 193 | icsk->icsk_retransmits++; |
182 | 194 | ||
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index ce4aaf94860d..2b289ef20ab3 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c | |||
@@ -172,7 +172,7 @@ static struct hlist_head *dn_find_list(struct sock *sk) | |||
172 | /* | 172 | /* |
173 | * Valid ports are those greater than zero and not already in use. | 173 | * Valid ports are those greater than zero and not already in use. |
174 | */ | 174 | */ |
175 | static int check_port(unsigned short port) | 175 | static int check_port(__le16 port) |
176 | { | 176 | { |
177 | struct sock *sk; | 177 | struct sock *sk; |
178 | struct hlist_node *node; | 178 | struct hlist_node *node; |
@@ -661,7 +661,7 @@ disc_reject: | |||
661 | } | 661 | } |
662 | } | 662 | } |
663 | 663 | ||
664 | char *dn_addr2asc(dn_address addr, char *buf) | 664 | char *dn_addr2asc(__u16 addr, char *buf) |
665 | { | 665 | { |
666 | unsigned short node, area; | 666 | unsigned short node, area; |
667 | 667 | ||
@@ -801,7 +801,7 @@ static int dn_auto_bind(struct socket *sock) | |||
801 | /* End of compatibility stuff */ | 801 | /* End of compatibility stuff */ |
802 | 802 | ||
803 | scp->addr.sdn_add.a_len = dn_htons(2); | 803 | scp->addr.sdn_add.a_len = dn_htons(2); |
804 | rv = dn_dev_bind_default((dn_address *)scp->addr.sdn_add.a_addr); | 804 | rv = dn_dev_bind_default((__le16 *)scp->addr.sdn_add.a_addr); |
805 | if (rv == 0) { | 805 | if (rv == 0) { |
806 | rv = dn_hash_sock(sk); | 806 | rv = dn_hash_sock(sk); |
807 | if (rv) | 807 | if (rv) |
@@ -1021,7 +1021,7 @@ static void dn_user_copy(struct sk_buff *skb, struct optdata_dn *opt) | |||
1021 | opt->opt_optl = *ptr++; | 1021 | opt->opt_optl = *ptr++; |
1022 | opt->opt_status = 0; | 1022 | opt->opt_status = 0; |
1023 | memcpy(opt->opt_data, ptr, opt->opt_optl); | 1023 | memcpy(opt->opt_data, ptr, opt->opt_optl); |
1024 | skb_pull(skb, opt->opt_optl + 1); | 1024 | skb_pull(skb, dn_ntohs(opt->opt_optl) + 1); |
1025 | 1025 | ||
1026 | } | 1026 | } |
1027 | 1027 | ||
@@ -1121,8 +1121,8 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags) | |||
1121 | 1121 | ||
1122 | skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->addr), &type)); | 1122 | skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->addr), &type)); |
1123 | skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->peer), &type)); | 1123 | skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->peer), &type)); |
1124 | *(dn_address *)(DN_SK(newsk)->peer.sdn_add.a_addr) = cb->src; | 1124 | *(__le16 *)(DN_SK(newsk)->peer.sdn_add.a_addr) = cb->src; |
1125 | *(dn_address *)(DN_SK(newsk)->addr.sdn_add.a_addr) = cb->dst; | 1125 | *(__le16 *)(DN_SK(newsk)->addr.sdn_add.a_addr) = cb->dst; |
1126 | 1126 | ||
1127 | menuver = *skb->data; | 1127 | menuver = *skb->data; |
1128 | skb_pull(skb, 1); | 1128 | skb_pull(skb, 1); |
@@ -1365,7 +1365,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us | |||
1365 | if (optlen != sizeof(struct optdata_dn)) | 1365 | if (optlen != sizeof(struct optdata_dn)) |
1366 | return -EINVAL; | 1366 | return -EINVAL; |
1367 | 1367 | ||
1368 | if (u.opt.opt_optl > 16) | 1368 | if (dn_ntohs(u.opt.opt_optl) > 16) |
1369 | return -EINVAL; | 1369 | return -EINVAL; |
1370 | 1370 | ||
1371 | memcpy(&scp->conndata_out, &u.opt, optlen); | 1371 | memcpy(&scp->conndata_out, &u.opt, optlen); |
@@ -1378,7 +1378,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us | |||
1378 | if (optlen != sizeof(struct optdata_dn)) | 1378 | if (optlen != sizeof(struct optdata_dn)) |
1379 | return -EINVAL; | 1379 | return -EINVAL; |
1380 | 1380 | ||
1381 | if (u.opt.opt_optl > 16) | 1381 | if (dn_ntohs(u.opt.opt_optl) > 16) |
1382 | return -EINVAL; | 1382 | return -EINVAL; |
1383 | 1383 | ||
1384 | memcpy(&scp->discdata_out, &u.opt, optlen); | 1384 | memcpy(&scp->discdata_out, &u.opt, optlen); |
@@ -1693,7 +1693,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1693 | if (rv) | 1693 | if (rv) |
1694 | goto out; | 1694 | goto out; |
1695 | 1695 | ||
1696 | if (flags & ~(MSG_PEEK|MSG_OOB|MSG_WAITALL|MSG_DONTWAIT|MSG_NOSIGNAL)) { | 1696 | if (flags & ~(MSG_CMSG_COMPAT|MSG_PEEK|MSG_OOB|MSG_WAITALL|MSG_DONTWAIT|MSG_NOSIGNAL)) { |
1697 | rv = -EOPNOTSUPP; | 1697 | rv = -EOPNOTSUPP; |
1698 | goto out; | 1698 | goto out; |
1699 | } | 1699 | } |
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index efbead83ba7f..cc7b9d9255ef 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c | |||
@@ -64,7 +64,7 @@ extern struct neigh_table dn_neigh_table; | |||
64 | /* | 64 | /* |
65 | * decnet_address is kept in network order. | 65 | * decnet_address is kept in network order. |
66 | */ | 66 | */ |
67 | dn_address decnet_address = 0; | 67 | __le16 decnet_address = 0; |
68 | 68 | ||
69 | static DEFINE_RWLOCK(dndev_lock); | 69 | static DEFINE_RWLOCK(dndev_lock); |
70 | static struct net_device *decnet_default_device; | 70 | static struct net_device *decnet_default_device; |
@@ -439,7 +439,7 @@ static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int de | |||
439 | *ifap = ifa1->ifa_next; | 439 | *ifap = ifa1->ifa_next; |
440 | 440 | ||
441 | if (dn_db->dev->type == ARPHRD_ETHER) { | 441 | if (dn_db->dev->type == ARPHRD_ETHER) { |
442 | if (ifa1->ifa_local != dn_htons(dn_eth2dn(dev->dev_addr))) { | 442 | if (ifa1->ifa_local != dn_eth2dn(dev->dev_addr)) { |
443 | dn_dn2eth(mac_addr, ifa1->ifa_local); | 443 | dn_dn2eth(mac_addr, ifa1->ifa_local); |
444 | dev_mc_delete(dev, mac_addr, ETH_ALEN, 0); | 444 | dev_mc_delete(dev, mac_addr, ETH_ALEN, 0); |
445 | } | 445 | } |
@@ -470,7 +470,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa) | |||
470 | } | 470 | } |
471 | 471 | ||
472 | if (dev->type == ARPHRD_ETHER) { | 472 | if (dev->type == ARPHRD_ETHER) { |
473 | if (ifa->ifa_local != dn_htons(dn_eth2dn(dev->dev_addr))) { | 473 | if (ifa->ifa_local != dn_eth2dn(dev->dev_addr)) { |
474 | dn_dn2eth(mac_addr, ifa->ifa_local); | 474 | dn_dn2eth(mac_addr, ifa->ifa_local); |
475 | dev_mc_add(dev, mac_addr, ETH_ALEN, 0); | 475 | dev_mc_add(dev, mac_addr, ETH_ALEN, 0); |
476 | dev_mc_upload(dev); | 476 | dev_mc_upload(dev); |
@@ -561,7 +561,7 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg) | |||
561 | 561 | ||
562 | switch(cmd) { | 562 | switch(cmd) { |
563 | case SIOCGIFADDR: | 563 | case SIOCGIFADDR: |
564 | *((dn_address *)sdn->sdn_nodeaddr) = ifa->ifa_local; | 564 | *((__le16 *)sdn->sdn_nodeaddr) = ifa->ifa_local; |
565 | goto rarok; | 565 | goto rarok; |
566 | 566 | ||
567 | case SIOCSIFADDR: | 567 | case SIOCSIFADDR: |
@@ -804,7 +804,7 @@ done: | |||
804 | return skb->len; | 804 | return skb->len; |
805 | } | 805 | } |
806 | 806 | ||
807 | static int dn_dev_get_first(struct net_device *dev, dn_address *addr) | 807 | static int dn_dev_get_first(struct net_device *dev, __le16 *addr) |
808 | { | 808 | { |
809 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; | 809 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; |
810 | struct dn_ifaddr *ifa; | 810 | struct dn_ifaddr *ifa; |
@@ -830,7 +830,7 @@ out: | |||
830 | * a sensible default. Eventually the routing code will take care of all the | 830 | * a sensible default. Eventually the routing code will take care of all the |
831 | * nasties for us I hope. | 831 | * nasties for us I hope. |
832 | */ | 832 | */ |
833 | int dn_dev_bind_default(dn_address *addr) | 833 | int dn_dev_bind_default(__le16 *addr) |
834 | { | 834 | { |
835 | struct net_device *dev; | 835 | struct net_device *dev; |
836 | int rv; | 836 | int rv; |
@@ -853,7 +853,7 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa) | |||
853 | { | 853 | { |
854 | struct endnode_hello_message *msg; | 854 | struct endnode_hello_message *msg; |
855 | struct sk_buff *skb = NULL; | 855 | struct sk_buff *skb = NULL; |
856 | unsigned short int *pktlen; | 856 | __le16 *pktlen; |
857 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; | 857 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; |
858 | 858 | ||
859 | if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL) | 859 | if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL) |
@@ -882,7 +882,7 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa) | |||
882 | msg->datalen = 0x02; | 882 | msg->datalen = 0x02; |
883 | memset(msg->data, 0xAA, 2); | 883 | memset(msg->data, 0xAA, 2); |
884 | 884 | ||
885 | pktlen = (unsigned short *)skb_push(skb,2); | 885 | pktlen = (__le16 *)skb_push(skb,2); |
886 | *pktlen = dn_htons(skb->len - 2); | 886 | *pktlen = dn_htons(skb->len - 2); |
887 | 887 | ||
888 | skb->nh.raw = skb->data; | 888 | skb->nh.raw = skb->data; |
@@ -926,7 +926,7 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa) | |||
926 | size_t size; | 926 | size_t size; |
927 | unsigned char *ptr; | 927 | unsigned char *ptr; |
928 | unsigned char *i1, *i2; | 928 | unsigned char *i1, *i2; |
929 | unsigned short *pktlen; | 929 | __le16 *pktlen; |
930 | char *src; | 930 | char *src; |
931 | 931 | ||
932 | if (mtu2blksize(dev) < (26 + 7)) | 932 | if (mtu2blksize(dev) < (26 + 7)) |
@@ -955,11 +955,11 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa) | |||
955 | ptr += ETH_ALEN; | 955 | ptr += ETH_ALEN; |
956 | *ptr++ = dn_db->parms.forwarding == 1 ? | 956 | *ptr++ = dn_db->parms.forwarding == 1 ? |
957 | DN_RT_INFO_L1RT : DN_RT_INFO_L2RT; | 957 | DN_RT_INFO_L1RT : DN_RT_INFO_L2RT; |
958 | *((unsigned short *)ptr) = dn_htons(mtu2blksize(dev)); | 958 | *((__le16 *)ptr) = dn_htons(mtu2blksize(dev)); |
959 | ptr += 2; | 959 | ptr += 2; |
960 | *ptr++ = dn_db->parms.priority; /* Priority */ | 960 | *ptr++ = dn_db->parms.priority; /* Priority */ |
961 | *ptr++ = 0; /* Area: Reserved */ | 961 | *ptr++ = 0; /* Area: Reserved */ |
962 | *((unsigned short *)ptr) = dn_htons((unsigned short)dn_db->parms.t3); | 962 | *((__le16 *)ptr) = dn_htons((unsigned short)dn_db->parms.t3); |
963 | ptr += 2; | 963 | ptr += 2; |
964 | *ptr++ = 0; /* MPD: Reserved */ | 964 | *ptr++ = 0; /* MPD: Reserved */ |
965 | i1 = ptr++; | 965 | i1 = ptr++; |
@@ -974,7 +974,7 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa) | |||
974 | 974 | ||
975 | skb_trim(skb, (27 + *i2)); | 975 | skb_trim(skb, (27 + *i2)); |
976 | 976 | ||
977 | pktlen = (unsigned short *)skb_push(skb, 2); | 977 | pktlen = (__le16 *)skb_push(skb, 2); |
978 | *pktlen = dn_htons(skb->len - 2); | 978 | *pktlen = dn_htons(skb->len - 2); |
979 | 979 | ||
980 | skb->nh.raw = skb->data; | 980 | skb->nh.raw = skb->data; |
@@ -1016,7 +1016,7 @@ static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa) | |||
1016 | ptr = skb_put(skb, 2 + 4 + tdlen); | 1016 | ptr = skb_put(skb, 2 + 4 + tdlen); |
1017 | 1017 | ||
1018 | *ptr++ = DN_RT_PKT_HELO; | 1018 | *ptr++ = DN_RT_PKT_HELO; |
1019 | *((dn_address *)ptr) = ifa->ifa_local; | 1019 | *((__le16 *)ptr) = ifa->ifa_local; |
1020 | ptr += 2; | 1020 | ptr += 2; |
1021 | *ptr++ = tdlen; | 1021 | *ptr++ = tdlen; |
1022 | 1022 | ||
@@ -1150,7 +1150,7 @@ struct dn_dev *dn_dev_create(struct net_device *dev, int *err) | |||
1150 | void dn_dev_up(struct net_device *dev) | 1150 | void dn_dev_up(struct net_device *dev) |
1151 | { | 1151 | { |
1152 | struct dn_ifaddr *ifa; | 1152 | struct dn_ifaddr *ifa; |
1153 | dn_address addr = decnet_address; | 1153 | __le16 addr = decnet_address; |
1154 | int maybe_default = 0; | 1154 | int maybe_default = 0; |
1155 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; | 1155 | struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; |
1156 | 1156 | ||
@@ -1173,7 +1173,7 @@ void dn_dev_up(struct net_device *dev) | |||
1173 | if (dev->type == ARPHRD_ETHER) { | 1173 | if (dev->type == ARPHRD_ETHER) { |
1174 | if (memcmp(dev->dev_addr, dn_hiord, 4) != 0) | 1174 | if (memcmp(dev->dev_addr, dn_hiord, 4) != 0) |
1175 | return; | 1175 | return; |
1176 | addr = dn_htons(dn_eth2dn(dev->dev_addr)); | 1176 | addr = dn_eth2dn(dev->dev_addr); |
1177 | maybe_default = 1; | 1177 | maybe_default = 1; |
1178 | } | 1178 | } |
1179 | 1179 | ||
@@ -1385,8 +1385,8 @@ static int dn_dev_seq_show(struct seq_file *seq, void *v) | |||
1385 | mtu2blksize(dev), | 1385 | mtu2blksize(dev), |
1386 | dn_db->parms.priority, | 1386 | dn_db->parms.priority, |
1387 | dn_db->parms.state, dn_db->parms.name, | 1387 | dn_db->parms.state, dn_db->parms.name, |
1388 | dn_db->router ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->router->primary_key), router_buf) : "", | 1388 | dn_db->router ? dn_addr2asc(dn_ntohs(*(__le16 *)dn_db->router->primary_key), router_buf) : "", |
1389 | dn_db->peer ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->peer->primary_key), peer_buf) : ""); | 1389 | dn_db->peer ? dn_addr2asc(dn_ntohs(*(__le16 *)dn_db->peer->primary_key), peer_buf) : ""); |
1390 | } | 1390 | } |
1391 | return 0; | 1391 | return 0; |
1392 | } | 1392 | } |
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c index 99bc061759c3..bd4ce8681a12 100644 --- a/net/decnet/dn_fib.c +++ b/net/decnet/dn_fib.c | |||
@@ -143,11 +143,11 @@ static inline struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi | |||
143 | return NULL; | 143 | return NULL; |
144 | } | 144 | } |
145 | 145 | ||
146 | u16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type) | 146 | __le16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type) |
147 | { | 147 | { |
148 | while(RTA_OK(attr,attrlen)) { | 148 | while(RTA_OK(attr,attrlen)) { |
149 | if (attr->rta_type == type) | 149 | if (attr->rta_type == type) |
150 | return *(u16*)RTA_DATA(attr); | 150 | return *(__le16*)RTA_DATA(attr); |
151 | attr = RTA_NEXT(attr, attrlen); | 151 | attr = RTA_NEXT(attr, attrlen); |
152 | } | 152 | } |
153 | 153 | ||
@@ -565,7 +565,7 @@ int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
565 | return skb->len; | 565 | return skb->len; |
566 | } | 566 | } |
567 | 567 | ||
568 | static void fib_magic(int cmd, int type, __u16 dst, int dst_len, struct dn_ifaddr *ifa) | 568 | static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa) |
569 | { | 569 | { |
570 | struct dn_fib_table *tb; | 570 | struct dn_fib_table *tb; |
571 | struct { | 571 | struct { |
@@ -684,7 +684,7 @@ static int dn_fib_dnaddr_event(struct notifier_block *this, unsigned long event, | |||
684 | return NOTIFY_DONE; | 684 | return NOTIFY_DONE; |
685 | } | 685 | } |
686 | 686 | ||
687 | int dn_fib_sync_down(dn_address local, struct net_device *dev, int force) | 687 | int dn_fib_sync_down(__le16 local, struct net_device *dev, int force) |
688 | { | 688 | { |
689 | int ret = 0; | 689 | int ret = 0; |
690 | int scope = RT_SCOPE_NOWHERE; | 690 | int scope = RT_SCOPE_NOWHERE; |
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index 33ab256cfd4a..7c8692c26bfe 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c | |||
@@ -95,7 +95,7 @@ static struct neigh_ops dn_phase3_ops = { | |||
95 | struct neigh_table dn_neigh_table = { | 95 | struct neigh_table dn_neigh_table = { |
96 | .family = PF_DECnet, | 96 | .family = PF_DECnet, |
97 | .entry_size = sizeof(struct dn_neigh), | 97 | .entry_size = sizeof(struct dn_neigh), |
98 | .key_len = sizeof(dn_address), | 98 | .key_len = sizeof(__le16), |
99 | .hash = dn_neigh_hash, | 99 | .hash = dn_neigh_hash, |
100 | .constructor = dn_neigh_construct, | 100 | .constructor = dn_neigh_construct, |
101 | .id = "dn_neigh_cache", | 101 | .id = "dn_neigh_cache", |
@@ -123,7 +123,7 @@ struct neigh_table dn_neigh_table = { | |||
123 | 123 | ||
124 | static u32 dn_neigh_hash(const void *pkey, const struct net_device *dev) | 124 | static u32 dn_neigh_hash(const void *pkey, const struct net_device *dev) |
125 | { | 125 | { |
126 | return jhash_2words(*(dn_address *)pkey, 0, dn_neigh_table.hash_rnd); | 126 | return jhash_2words(*(__u16 *)pkey, 0, dn_neigh_table.hash_rnd); |
127 | } | 127 | } |
128 | 128 | ||
129 | static int dn_neigh_construct(struct neighbour *neigh) | 129 | static int dn_neigh_construct(struct neighbour *neigh) |
@@ -249,14 +249,14 @@ static int dn_long_output(struct sk_buff *skb) | |||
249 | data = skb_push(skb, sizeof(struct dn_long_packet) + 3); | 249 | data = skb_push(skb, sizeof(struct dn_long_packet) + 3); |
250 | lp = (struct dn_long_packet *)(data+3); | 250 | lp = (struct dn_long_packet *)(data+3); |
251 | 251 | ||
252 | *((unsigned short *)data) = dn_htons(skb->len - 2); | 252 | *((__le16 *)data) = dn_htons(skb->len - 2); |
253 | *(data + 2) = 1 | DN_RT_F_PF; /* Padding */ | 253 | *(data + 2) = 1 | DN_RT_F_PF; /* Padding */ |
254 | 254 | ||
255 | lp->msgflg = DN_RT_PKT_LONG|(cb->rt_flags&(DN_RT_F_IE|DN_RT_F_RQR|DN_RT_F_RTS)); | 255 | lp->msgflg = DN_RT_PKT_LONG|(cb->rt_flags&(DN_RT_F_IE|DN_RT_F_RQR|DN_RT_F_RTS)); |
256 | lp->d_area = lp->d_subarea = 0; | 256 | lp->d_area = lp->d_subarea = 0; |
257 | dn_dn2eth(lp->d_id, dn_ntohs(cb->dst)); | 257 | dn_dn2eth(lp->d_id, cb->dst); |
258 | lp->s_area = lp->s_subarea = 0; | 258 | lp->s_area = lp->s_subarea = 0; |
259 | dn_dn2eth(lp->s_id, dn_ntohs(cb->src)); | 259 | dn_dn2eth(lp->s_id, cb->src); |
260 | lp->nl2 = 0; | 260 | lp->nl2 = 0; |
261 | lp->visit_ct = cb->hops & 0x3f; | 261 | lp->visit_ct = cb->hops & 0x3f; |
262 | lp->s_class = 0; | 262 | lp->s_class = 0; |
@@ -293,7 +293,7 @@ static int dn_short_output(struct sk_buff *skb) | |||
293 | } | 293 | } |
294 | 294 | ||
295 | data = skb_push(skb, sizeof(struct dn_short_packet) + 2); | 295 | data = skb_push(skb, sizeof(struct dn_short_packet) + 2); |
296 | *((unsigned short *)data) = dn_htons(skb->len - 2); | 296 | *((__le16 *)data) = dn_htons(skb->len - 2); |
297 | sp = (struct dn_short_packet *)(data+2); | 297 | sp = (struct dn_short_packet *)(data+2); |
298 | 298 | ||
299 | sp->msgflg = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS)); | 299 | sp->msgflg = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS)); |
@@ -335,7 +335,7 @@ static int dn_phase3_output(struct sk_buff *skb) | |||
335 | } | 335 | } |
336 | 336 | ||
337 | data = skb_push(skb, sizeof(struct dn_short_packet) + 2); | 337 | data = skb_push(skb, sizeof(struct dn_short_packet) + 2); |
338 | *((unsigned short *)data) = dn_htons(skb->len - 2); | 338 | *((__le16 *)data) = dn_htons(skb->len - 2); |
339 | sp = (struct dn_short_packet *)(data + 2); | 339 | sp = (struct dn_short_packet *)(data + 2); |
340 | 340 | ||
341 | sp->msgflg = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS)); | 341 | sp->msgflg = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS)); |
@@ -373,9 +373,9 @@ int dn_neigh_router_hello(struct sk_buff *skb) | |||
373 | struct neighbour *neigh; | 373 | struct neighbour *neigh; |
374 | struct dn_neigh *dn; | 374 | struct dn_neigh *dn; |
375 | struct dn_dev *dn_db; | 375 | struct dn_dev *dn_db; |
376 | dn_address src; | 376 | __le16 src; |
377 | 377 | ||
378 | src = dn_htons(dn_eth2dn(msg->id)); | 378 | src = dn_eth2dn(msg->id); |
379 | 379 | ||
380 | neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1); | 380 | neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1); |
381 | 381 | ||
@@ -409,7 +409,7 @@ int dn_neigh_router_hello(struct sk_buff *skb) | |||
409 | } | 409 | } |
410 | 410 | ||
411 | /* Only use routers in our area */ | 411 | /* Only use routers in our area */ |
412 | if ((dn_ntohs(src)>>10) == dn_ntohs((decnet_address)>>10)) { | 412 | if ((dn_ntohs(src)>>10) == (dn_ntohs((decnet_address))>>10)) { |
413 | if (!dn_db->router) { | 413 | if (!dn_db->router) { |
414 | dn_db->router = neigh_clone(neigh); | 414 | dn_db->router = neigh_clone(neigh); |
415 | } else { | 415 | } else { |
@@ -433,9 +433,9 @@ int dn_neigh_endnode_hello(struct sk_buff *skb) | |||
433 | struct endnode_hello_message *msg = (struct endnode_hello_message *)skb->data; | 433 | struct endnode_hello_message *msg = (struct endnode_hello_message *)skb->data; |
434 | struct neighbour *neigh; | 434 | struct neighbour *neigh; |
435 | struct dn_neigh *dn; | 435 | struct dn_neigh *dn; |
436 | dn_address src; | 436 | __le16 src; |
437 | 437 | ||
438 | src = dn_htons(dn_eth2dn(msg->id)); | 438 | src = dn_eth2dn(msg->id); |
439 | 439 | ||
440 | neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1); | 440 | neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1); |
441 | 441 | ||
diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c index 44bda85e678f..547523b41c81 100644 --- a/net/decnet/dn_nsp_in.c +++ b/net/decnet/dn_nsp_in.c | |||
@@ -85,7 +85,7 @@ static void dn_log_martian(struct sk_buff *skb, const char *msg) | |||
85 | if (decnet_log_martians && net_ratelimit()) { | 85 | if (decnet_log_martians && net_ratelimit()) { |
86 | char *devname = skb->dev ? skb->dev->name : "???"; | 86 | char *devname = skb->dev ? skb->dev->name : "???"; |
87 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 87 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
88 | printk(KERN_INFO "DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n", msg, devname, cb->src, cb->dst, cb->src_port, cb->dst_port); | 88 | printk(KERN_INFO "DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n", msg, devname, dn_ntohs(cb->src), dn_ntohs(cb->dst), dn_ntohs(cb->src_port), dn_ntohs(cb->dst_port)); |
89 | } | 89 | } |
90 | } | 90 | } |
91 | 91 | ||
@@ -128,7 +128,7 @@ static void dn_ack(struct sock *sk, struct sk_buff *skb, unsigned short ack) | |||
128 | */ | 128 | */ |
129 | static int dn_process_ack(struct sock *sk, struct sk_buff *skb, int oth) | 129 | static int dn_process_ack(struct sock *sk, struct sk_buff *skb, int oth) |
130 | { | 130 | { |
131 | unsigned short *ptr = (unsigned short *)skb->data; | 131 | __le16 *ptr = (__le16 *)skb->data; |
132 | int len = 0; | 132 | int len = 0; |
133 | unsigned short ack; | 133 | unsigned short ack; |
134 | 134 | ||
@@ -346,7 +346,7 @@ static void dn_nsp_conn_conf(struct sock *sk, struct sk_buff *skb) | |||
346 | ptr = skb->data; | 346 | ptr = skb->data; |
347 | cb->services = *ptr++; | 347 | cb->services = *ptr++; |
348 | cb->info = *ptr++; | 348 | cb->info = *ptr++; |
349 | cb->segsize = dn_ntohs(*(__u16 *)ptr); | 349 | cb->segsize = dn_ntohs(*(__le16 *)ptr); |
350 | 350 | ||
351 | if ((scp->state == DN_CI) || (scp->state == DN_CD)) { | 351 | if ((scp->state == DN_CI) || (scp->state == DN_CD)) { |
352 | scp->persist = 0; | 352 | scp->persist = 0; |
@@ -363,7 +363,7 @@ static void dn_nsp_conn_conf(struct sock *sk, struct sk_buff *skb) | |||
363 | if (skb->len > 0) { | 363 | if (skb->len > 0) { |
364 | unsigned char dlen = *skb->data; | 364 | unsigned char dlen = *skb->data; |
365 | if ((dlen <= 16) && (dlen <= skb->len)) { | 365 | if ((dlen <= 16) && (dlen <= skb->len)) { |
366 | scp->conndata_in.opt_optl = dlen; | 366 | scp->conndata_in.opt_optl = dn_htons((__u16)dlen); |
367 | memcpy(scp->conndata_in.opt_data, skb->data + 1, dlen); | 367 | memcpy(scp->conndata_in.opt_data, skb->data + 1, dlen); |
368 | } | 368 | } |
369 | } | 369 | } |
@@ -397,17 +397,17 @@ static void dn_nsp_disc_init(struct sock *sk, struct sk_buff *skb) | |||
397 | if (skb->len < 2) | 397 | if (skb->len < 2) |
398 | goto out; | 398 | goto out; |
399 | 399 | ||
400 | reason = dn_ntohs(*(__u16 *)skb->data); | 400 | reason = dn_ntohs(*(__le16 *)skb->data); |
401 | skb_pull(skb, 2); | 401 | skb_pull(skb, 2); |
402 | 402 | ||
403 | scp->discdata_in.opt_status = reason; | 403 | scp->discdata_in.opt_status = dn_htons(reason); |
404 | scp->discdata_in.opt_optl = 0; | 404 | scp->discdata_in.opt_optl = 0; |
405 | memset(scp->discdata_in.opt_data, 0, 16); | 405 | memset(scp->discdata_in.opt_data, 0, 16); |
406 | 406 | ||
407 | if (skb->len > 0) { | 407 | if (skb->len > 0) { |
408 | unsigned char dlen = *skb->data; | 408 | unsigned char dlen = *skb->data; |
409 | if ((dlen <= 16) && (dlen <= skb->len)) { | 409 | if ((dlen <= 16) && (dlen <= skb->len)) { |
410 | scp->discdata_in.opt_optl = dlen; | 410 | scp->discdata_in.opt_optl = dn_htons((__u16)dlen); |
411 | memcpy(scp->discdata_in.opt_data, skb->data + 1, dlen); | 411 | memcpy(scp->discdata_in.opt_data, skb->data + 1, dlen); |
412 | } | 412 | } |
413 | } | 413 | } |
@@ -464,7 +464,7 @@ static void dn_nsp_disc_conf(struct sock *sk, struct sk_buff *skb) | |||
464 | if (skb->len != 2) | 464 | if (skb->len != 2) |
465 | goto out; | 465 | goto out; |
466 | 466 | ||
467 | reason = dn_ntohs(*(__u16 *)skb->data); | 467 | reason = dn_ntohs(*(__le16 *)skb->data); |
468 | 468 | ||
469 | sk->sk_state = TCP_CLOSE; | 469 | sk->sk_state = TCP_CLOSE; |
470 | 470 | ||
@@ -513,7 +513,7 @@ static void dn_nsp_linkservice(struct sock *sk, struct sk_buff *skb) | |||
513 | if (skb->len != 4) | 513 | if (skb->len != 4) |
514 | goto out; | 514 | goto out; |
515 | 515 | ||
516 | segnum = dn_ntohs(*(__u16 *)ptr); | 516 | segnum = dn_ntohs(*(__le16 *)ptr); |
517 | ptr += 2; | 517 | ptr += 2; |
518 | lsflags = *(unsigned char *)ptr++; | 518 | lsflags = *(unsigned char *)ptr++; |
519 | fcval = *ptr; | 519 | fcval = *ptr; |
@@ -621,7 +621,7 @@ static void dn_nsp_otherdata(struct sock *sk, struct sk_buff *skb) | |||
621 | if (skb->len < 2) | 621 | if (skb->len < 2) |
622 | goto out; | 622 | goto out; |
623 | 623 | ||
624 | cb->segnum = segnum = dn_ntohs(*(__u16 *)skb->data); | 624 | cb->segnum = segnum = dn_ntohs(*(__le16 *)skb->data); |
625 | skb_pull(skb, 2); | 625 | skb_pull(skb, 2); |
626 | 626 | ||
627 | if (seq_next(scp->numoth_rcv, segnum)) { | 627 | if (seq_next(scp->numoth_rcv, segnum)) { |
@@ -649,7 +649,7 @@ static void dn_nsp_data(struct sock *sk, struct sk_buff *skb) | |||
649 | if (skb->len < 2) | 649 | if (skb->len < 2) |
650 | goto out; | 650 | goto out; |
651 | 651 | ||
652 | cb->segnum = segnum = dn_ntohs(*(__u16 *)skb->data); | 652 | cb->segnum = segnum = dn_ntohs(*(__le16 *)skb->data); |
653 | skb_pull(skb, 2); | 653 | skb_pull(skb, 2); |
654 | 654 | ||
655 | if (seq_next(scp->numdat_rcv, segnum)) { | 655 | if (seq_next(scp->numdat_rcv, segnum)) { |
@@ -760,7 +760,7 @@ static int dn_nsp_rx_packet(struct sk_buff *skb) | |||
760 | /* | 760 | /* |
761 | * Grab the destination address. | 761 | * Grab the destination address. |
762 | */ | 762 | */ |
763 | cb->dst_port = *(unsigned short *)ptr; | 763 | cb->dst_port = *(__le16 *)ptr; |
764 | cb->src_port = 0; | 764 | cb->src_port = 0; |
765 | ptr += 2; | 765 | ptr += 2; |
766 | 766 | ||
@@ -768,7 +768,7 @@ static int dn_nsp_rx_packet(struct sk_buff *skb) | |||
768 | * If not a connack, grab the source address too. | 768 | * If not a connack, grab the source address too. |
769 | */ | 769 | */ |
770 | if (pskb_may_pull(skb, 5)) { | 770 | if (pskb_may_pull(skb, 5)) { |
771 | cb->src_port = *(unsigned short *)ptr; | 771 | cb->src_port = *(__le16 *)ptr; |
772 | ptr += 2; | 772 | ptr += 2; |
773 | skb_pull(skb, 5); | 773 | skb_pull(skb, 5); |
774 | } | 774 | } |
@@ -778,7 +778,7 @@ static int dn_nsp_rx_packet(struct sk_buff *skb) | |||
778 | * Swap src & dst and look up in the normal way. | 778 | * Swap src & dst and look up in the normal way. |
779 | */ | 779 | */ |
780 | if (unlikely(cb->rt_flags & DN_RT_F_RTS)) { | 780 | if (unlikely(cb->rt_flags & DN_RT_F_RTS)) { |
781 | unsigned short tmp = cb->dst_port; | 781 | __le16 tmp = cb->dst_port; |
782 | cb->dst_port = cb->src_port; | 782 | cb->dst_port = cb->src_port; |
783 | cb->src_port = tmp; | 783 | cb->src_port = tmp; |
784 | tmp = cb->dst; | 784 | tmp = cb->dst; |
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c index c96c767b1f74..c2e21cd89b3c 100644 --- a/net/decnet/dn_nsp_out.c +++ b/net/decnet/dn_nsp_out.c | |||
@@ -287,26 +287,26 @@ int dn_nsp_xmit_timeout(struct sock *sk) | |||
287 | return 0; | 287 | return 0; |
288 | } | 288 | } |
289 | 289 | ||
290 | static inline unsigned char *dn_mk_common_header(struct dn_scp *scp, struct sk_buff *skb, unsigned char msgflag, int len) | 290 | static inline __le16 *dn_mk_common_header(struct dn_scp *scp, struct sk_buff *skb, unsigned char msgflag, int len) |
291 | { | 291 | { |
292 | unsigned char *ptr = skb_push(skb, len); | 292 | unsigned char *ptr = skb_push(skb, len); |
293 | 293 | ||
294 | BUG_ON(len < 5); | 294 | BUG_ON(len < 5); |
295 | 295 | ||
296 | *ptr++ = msgflag; | 296 | *ptr++ = msgflag; |
297 | *((unsigned short *)ptr) = scp->addrrem; | 297 | *((__le16 *)ptr) = scp->addrrem; |
298 | ptr += 2; | 298 | ptr += 2; |
299 | *((unsigned short *)ptr) = scp->addrloc; | 299 | *((__le16 *)ptr) = scp->addrloc; |
300 | ptr += 2; | 300 | ptr += 2; |
301 | return ptr; | 301 | return (__le16 __force *)ptr; |
302 | } | 302 | } |
303 | 303 | ||
304 | static unsigned short *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, unsigned char msgflag, int hlen, int other) | 304 | static __le16 *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, unsigned char msgflag, int hlen, int other) |
305 | { | 305 | { |
306 | struct dn_scp *scp = DN_SK(sk); | 306 | struct dn_scp *scp = DN_SK(sk); |
307 | unsigned short acknum = scp->numdat_rcv & 0x0FFF; | 307 | unsigned short acknum = scp->numdat_rcv & 0x0FFF; |
308 | unsigned short ackcrs = scp->numoth_rcv & 0x0FFF; | 308 | unsigned short ackcrs = scp->numoth_rcv & 0x0FFF; |
309 | unsigned short *ptr; | 309 | __le16 *ptr; |
310 | 310 | ||
311 | BUG_ON(hlen < 9); | 311 | BUG_ON(hlen < 9); |
312 | 312 | ||
@@ -325,7 +325,7 @@ static unsigned short *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, un | |||
325 | /* Set "cross subchannel" bit in ackcrs */ | 325 | /* Set "cross subchannel" bit in ackcrs */ |
326 | ackcrs |= 0x2000; | 326 | ackcrs |= 0x2000; |
327 | 327 | ||
328 | ptr = (unsigned short *)dn_mk_common_header(scp, skb, msgflag, hlen); | 328 | ptr = (__le16 *)dn_mk_common_header(scp, skb, msgflag, hlen); |
329 | 329 | ||
330 | *ptr++ = dn_htons(acknum); | 330 | *ptr++ = dn_htons(acknum); |
331 | *ptr++ = dn_htons(ackcrs); | 331 | *ptr++ = dn_htons(ackcrs); |
@@ -333,11 +333,11 @@ static unsigned short *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, un | |||
333 | return ptr; | 333 | return ptr; |
334 | } | 334 | } |
335 | 335 | ||
336 | static unsigned short *dn_nsp_mk_data_header(struct sock *sk, struct sk_buff *skb, int oth) | 336 | static __le16 *dn_nsp_mk_data_header(struct sock *sk, struct sk_buff *skb, int oth) |
337 | { | 337 | { |
338 | struct dn_scp *scp = DN_SK(sk); | 338 | struct dn_scp *scp = DN_SK(sk); |
339 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 339 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
340 | unsigned short *ptr = dn_mk_ack_header(sk, skb, cb->nsp_flags, 11, oth); | 340 | __le16 *ptr = dn_mk_ack_header(sk, skb, cb->nsp_flags, 11, oth); |
341 | 341 | ||
342 | if (unlikely(oth)) { | 342 | if (unlikely(oth)) { |
343 | cb->segnum = scp->numoth; | 343 | cb->segnum = scp->numoth; |
@@ -524,9 +524,9 @@ void dn_send_conn_conf(struct sock *sk, gfp_t gfp) | |||
524 | struct dn_scp *scp = DN_SK(sk); | 524 | struct dn_scp *scp = DN_SK(sk); |
525 | struct sk_buff *skb = NULL; | 525 | struct sk_buff *skb = NULL; |
526 | struct nsp_conn_init_msg *msg; | 526 | struct nsp_conn_init_msg *msg; |
527 | unsigned char len = scp->conndata_out.opt_optl; | 527 | __u8 len = (__u8)dn_ntohs(scp->conndata_out.opt_optl); |
528 | 528 | ||
529 | if ((skb = dn_alloc_skb(sk, 50 + scp->conndata_out.opt_optl, gfp)) == NULL) | 529 | if ((skb = dn_alloc_skb(sk, 50 + dn_ntohs(scp->conndata_out.opt_optl), gfp)) == NULL) |
530 | return; | 530 | return; |
531 | 531 | ||
532 | msg = (struct nsp_conn_init_msg *)skb_put(skb, sizeof(*msg)); | 532 | msg = (struct nsp_conn_init_msg *)skb_put(skb, sizeof(*msg)); |
@@ -553,7 +553,7 @@ void dn_send_conn_conf(struct sock *sk, gfp_t gfp) | |||
553 | static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg, | 553 | static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg, |
554 | unsigned short reason, gfp_t gfp, | 554 | unsigned short reason, gfp_t gfp, |
555 | struct dst_entry *dst, | 555 | struct dst_entry *dst, |
556 | int ddl, unsigned char *dd, __u16 rem, __u16 loc) | 556 | int ddl, unsigned char *dd, __le16 rem, __le16 loc) |
557 | { | 557 | { |
558 | struct sk_buff *skb = NULL; | 558 | struct sk_buff *skb = NULL; |
559 | int size = 7 + ddl + ((msgflg == NSP_DISCINIT) ? 1 : 0); | 559 | int size = 7 + ddl + ((msgflg == NSP_DISCINIT) ? 1 : 0); |
@@ -561,7 +561,7 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg, | |||
561 | 561 | ||
562 | if ((dst == NULL) || (rem == 0)) { | 562 | if ((dst == NULL) || (rem == 0)) { |
563 | if (net_ratelimit()) | 563 | if (net_ratelimit()) |
564 | printk(KERN_DEBUG "DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n", (unsigned)rem, dst); | 564 | printk(KERN_DEBUG "DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n", dn_ntohs(rem), dst); |
565 | return; | 565 | return; |
566 | } | 566 | } |
567 | 567 | ||
@@ -570,11 +570,11 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg, | |||
570 | 570 | ||
571 | msg = skb_put(skb, size); | 571 | msg = skb_put(skb, size); |
572 | *msg++ = msgflg; | 572 | *msg++ = msgflg; |
573 | *(__u16 *)msg = rem; | 573 | *(__le16 *)msg = rem; |
574 | msg += 2; | 574 | msg += 2; |
575 | *(__u16 *)msg = loc; | 575 | *(__le16 *)msg = loc; |
576 | msg += 2; | 576 | msg += 2; |
577 | *(__u16 *)msg = dn_htons(reason); | 577 | *(__le16 *)msg = dn_htons(reason); |
578 | msg += 2; | 578 | msg += 2; |
579 | if (msgflg == NSP_DISCINIT) | 579 | if (msgflg == NSP_DISCINIT) |
580 | *msg++ = ddl; | 580 | *msg++ = ddl; |
@@ -600,10 +600,10 @@ void dn_nsp_send_disc(struct sock *sk, unsigned char msgflg, | |||
600 | int ddl = 0; | 600 | int ddl = 0; |
601 | 601 | ||
602 | if (msgflg == NSP_DISCINIT) | 602 | if (msgflg == NSP_DISCINIT) |
603 | ddl = scp->discdata_out.opt_optl; | 603 | ddl = dn_ntohs(scp->discdata_out.opt_optl); |
604 | 604 | ||
605 | if (reason == 0) | 605 | if (reason == 0) |
606 | reason = scp->discdata_out.opt_status; | 606 | reason = dn_ntohs(scp->discdata_out.opt_status); |
607 | 607 | ||
608 | dn_nsp_do_disc(sk, msgflg, reason, gfp, sk->sk_dst_cache, ddl, | 608 | dn_nsp_do_disc(sk, msgflg, reason, gfp, sk->sk_dst_cache, ddl, |
609 | scp->discdata_out.opt_data, scp->addrrem, scp->addrloc); | 609 | scp->discdata_out.opt_data, scp->addrrem, scp->addrloc); |
@@ -708,7 +708,7 @@ void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg) | |||
708 | if (aux > 0) | 708 | if (aux > 0) |
709 | memcpy(skb_put(skb, aux), scp->accessdata.acc_acc, aux); | 709 | memcpy(skb_put(skb, aux), scp->accessdata.acc_acc, aux); |
710 | 710 | ||
711 | aux = scp->conndata_out.opt_optl; | 711 | aux = (__u8)dn_ntohs(scp->conndata_out.opt_optl); |
712 | *skb_put(skb, 1) = aux; | 712 | *skb_put(skb, 1) = aux; |
713 | if (aux > 0) | 713 | if (aux > 0) |
714 | memcpy(skb_put(skb,aux), scp->conndata_out.opt_data, aux); | 714 | memcpy(skb_put(skb,aux), scp->conndata_out.opt_data, aux); |
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 3407f190afe8..e172cf98d7fc 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c | |||
@@ -133,9 +133,9 @@ static struct dst_ops dn_dst_ops = { | |||
133 | .entries = ATOMIC_INIT(0), | 133 | .entries = ATOMIC_INIT(0), |
134 | }; | 134 | }; |
135 | 135 | ||
136 | static __inline__ unsigned dn_hash(unsigned short src, unsigned short dst) | 136 | static __inline__ unsigned dn_hash(__le16 src, __le16 dst) |
137 | { | 137 | { |
138 | unsigned short tmp = src ^ dst; | 138 | __u16 tmp = (__u16 __force)(src ^ dst); |
139 | tmp ^= (tmp >> 3); | 139 | tmp ^= (tmp >> 3); |
140 | tmp ^= (tmp >> 5); | 140 | tmp ^= (tmp >> 5); |
141 | tmp ^= (tmp >> 10); | 141 | tmp ^= (tmp >> 10); |
@@ -149,8 +149,7 @@ static inline void dnrt_free(struct dn_route *rt) | |||
149 | 149 | ||
150 | static inline void dnrt_drop(struct dn_route *rt) | 150 | static inline void dnrt_drop(struct dn_route *rt) |
151 | { | 151 | { |
152 | if (rt) | 152 | dst_release(&rt->u.dst); |
153 | dst_release(&rt->u.dst); | ||
154 | call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free); | 153 | call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free); |
155 | } | 154 | } |
156 | 155 | ||
@@ -379,9 +378,9 @@ static int dn_return_short(struct sk_buff *skb) | |||
379 | { | 378 | { |
380 | struct dn_skb_cb *cb; | 379 | struct dn_skb_cb *cb; |
381 | unsigned char *ptr; | 380 | unsigned char *ptr; |
382 | dn_address *src; | 381 | __le16 *src; |
383 | dn_address *dst; | 382 | __le16 *dst; |
384 | dn_address tmp; | 383 | __le16 tmp; |
385 | 384 | ||
386 | /* Add back headers */ | 385 | /* Add back headers */ |
387 | skb_push(skb, skb->data - skb->nh.raw); | 386 | skb_push(skb, skb->data - skb->nh.raw); |
@@ -394,9 +393,9 @@ static int dn_return_short(struct sk_buff *skb) | |||
394 | ptr = skb->data + 2; | 393 | ptr = skb->data + 2; |
395 | *ptr++ = (cb->rt_flags & ~DN_RT_F_RQR) | DN_RT_F_RTS; | 394 | *ptr++ = (cb->rt_flags & ~DN_RT_F_RQR) | DN_RT_F_RTS; |
396 | 395 | ||
397 | dst = (dn_address *)ptr; | 396 | dst = (__le16 *)ptr; |
398 | ptr += 2; | 397 | ptr += 2; |
399 | src = (dn_address *)ptr; | 398 | src = (__le16 *)ptr; |
400 | ptr += 2; | 399 | ptr += 2; |
401 | *ptr = 0; /* Zero hop count */ | 400 | *ptr = 0; /* Zero hop count */ |
402 | 401 | ||
@@ -475,7 +474,8 @@ static int dn_route_rx_packet(struct sk_buff *skb) | |||
475 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 474 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
476 | printk(KERN_DEBUG | 475 | printk(KERN_DEBUG |
477 | "DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n", | 476 | "DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n", |
478 | (int)cb->rt_flags, devname, skb->len, cb->src, cb->dst, | 477 | (int)cb->rt_flags, devname, skb->len, |
478 | dn_ntohs(cb->src), dn_ntohs(cb->dst), | ||
479 | err, skb->pkt_type); | 479 | err, skb->pkt_type); |
480 | } | 480 | } |
481 | 481 | ||
@@ -505,7 +505,7 @@ static int dn_route_rx_long(struct sk_buff *skb) | |||
505 | 505 | ||
506 | /* Destination info */ | 506 | /* Destination info */ |
507 | ptr += 2; | 507 | ptr += 2; |
508 | cb->dst = dn_htons(dn_eth2dn(ptr)); | 508 | cb->dst = dn_eth2dn(ptr); |
509 | if (memcmp(ptr, dn_hiord_addr, 4) != 0) | 509 | if (memcmp(ptr, dn_hiord_addr, 4) != 0) |
510 | goto drop_it; | 510 | goto drop_it; |
511 | ptr += 6; | 511 | ptr += 6; |
@@ -513,7 +513,7 @@ static int dn_route_rx_long(struct sk_buff *skb) | |||
513 | 513 | ||
514 | /* Source info */ | 514 | /* Source info */ |
515 | ptr += 2; | 515 | ptr += 2; |
516 | cb->src = dn_htons(dn_eth2dn(ptr)); | 516 | cb->src = dn_eth2dn(ptr); |
517 | if (memcmp(ptr, dn_hiord_addr, 4) != 0) | 517 | if (memcmp(ptr, dn_hiord_addr, 4) != 0) |
518 | goto drop_it; | 518 | goto drop_it; |
519 | ptr += 6; | 519 | ptr += 6; |
@@ -541,9 +541,9 @@ static int dn_route_rx_short(struct sk_buff *skb) | |||
541 | skb_pull(skb, 5); | 541 | skb_pull(skb, 5); |
542 | skb->h.raw = skb->data; | 542 | skb->h.raw = skb->data; |
543 | 543 | ||
544 | cb->dst = *(dn_address *)ptr; | 544 | cb->dst = *(__le16 *)ptr; |
545 | ptr += 2; | 545 | ptr += 2; |
546 | cb->src = *(dn_address *)ptr; | 546 | cb->src = *(__le16 *)ptr; |
547 | ptr += 2; | 547 | ptr += 2; |
548 | cb->hops = *ptr & 0x3f; | 548 | cb->hops = *ptr & 0x3f; |
549 | 549 | ||
@@ -575,7 +575,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type | |||
575 | { | 575 | { |
576 | struct dn_skb_cb *cb; | 576 | struct dn_skb_cb *cb; |
577 | unsigned char flags = 0; | 577 | unsigned char flags = 0; |
578 | __u16 len = dn_ntohs(*(__u16 *)skb->data); | 578 | __u16 len = dn_ntohs(*(__le16 *)skb->data); |
579 | struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr; | 579 | struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr; |
580 | unsigned char padlen = 0; | 580 | unsigned char padlen = 0; |
581 | 581 | ||
@@ -782,7 +782,7 @@ static int dn_rt_bug(struct sk_buff *skb) | |||
782 | struct dn_skb_cb *cb = DN_SKB_CB(skb); | 782 | struct dn_skb_cb *cb = DN_SKB_CB(skb); |
783 | 783 | ||
784 | printk(KERN_DEBUG "dn_rt_bug: skb from:%04x to:%04x\n", | 784 | printk(KERN_DEBUG "dn_rt_bug: skb from:%04x to:%04x\n", |
785 | cb->src, cb->dst); | 785 | dn_ntohs(cb->src), dn_ntohs(cb->dst)); |
786 | } | 786 | } |
787 | 787 | ||
788 | kfree_skb(skb); | 788 | kfree_skb(skb); |
@@ -823,7 +823,7 @@ static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res) | |||
823 | return 0; | 823 | return 0; |
824 | } | 824 | } |
825 | 825 | ||
826 | static inline int dn_match_addr(__u16 addr1, __u16 addr2) | 826 | static inline int dn_match_addr(__le16 addr1, __le16 addr2) |
827 | { | 827 | { |
828 | __u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2); | 828 | __u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2); |
829 | int match = 16; | 829 | int match = 16; |
@@ -834,9 +834,9 @@ static inline int dn_match_addr(__u16 addr1, __u16 addr2) | |||
834 | return match; | 834 | return match; |
835 | } | 835 | } |
836 | 836 | ||
837 | static __u16 dnet_select_source(const struct net_device *dev, __u16 daddr, int scope) | 837 | static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int scope) |
838 | { | 838 | { |
839 | __u16 saddr = 0; | 839 | __le16 saddr = 0; |
840 | struct dn_dev *dn_db = dev->dn_ptr; | 840 | struct dn_dev *dn_db = dev->dn_ptr; |
841 | struct dn_ifaddr *ifa; | 841 | struct dn_ifaddr *ifa; |
842 | int best_match = 0; | 842 | int best_match = 0; |
@@ -861,14 +861,14 @@ static __u16 dnet_select_source(const struct net_device *dev, __u16 daddr, int s | |||
861 | return saddr; | 861 | return saddr; |
862 | } | 862 | } |
863 | 863 | ||
864 | static inline __u16 __dn_fib_res_prefsrc(struct dn_fib_res *res) | 864 | static inline __le16 __dn_fib_res_prefsrc(struct dn_fib_res *res) |
865 | { | 865 | { |
866 | return dnet_select_source(DN_FIB_RES_DEV(*res), DN_FIB_RES_GW(*res), res->scope); | 866 | return dnet_select_source(DN_FIB_RES_DEV(*res), DN_FIB_RES_GW(*res), res->scope); |
867 | } | 867 | } |
868 | 868 | ||
869 | static inline __u16 dn_fib_rules_map_destination(__u16 daddr, struct dn_fib_res *res) | 869 | static inline __le16 dn_fib_rules_map_destination(__le16 daddr, struct dn_fib_res *res) |
870 | { | 870 | { |
871 | __u16 mask = dnet_make_mask(res->prefixlen); | 871 | __le16 mask = dnet_make_mask(res->prefixlen); |
872 | return (daddr&~mask)|res->fi->fib_nh->nh_gw; | 872 | return (daddr&~mask)|res->fi->fib_nh->nh_gw; |
873 | } | 873 | } |
874 | 874 | ||
@@ -892,12 +892,13 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old | |||
892 | struct dn_fib_res res = { .fi = NULL, .type = RTN_UNICAST }; | 892 | struct dn_fib_res res = { .fi = NULL, .type = RTN_UNICAST }; |
893 | int err; | 893 | int err; |
894 | int free_res = 0; | 894 | int free_res = 0; |
895 | __u16 gateway = 0; | 895 | __le16 gateway = 0; |
896 | 896 | ||
897 | if (decnet_debug_level & 16) | 897 | if (decnet_debug_level & 16) |
898 | printk(KERN_DEBUG | 898 | printk(KERN_DEBUG |
899 | "dn_route_output_slow: dst=%04x src=%04x mark=%d" | 899 | "dn_route_output_slow: dst=%04x src=%04x mark=%d" |
900 | " iif=%d oif=%d\n", oldflp->fld_dst, oldflp->fld_src, | 900 | " iif=%d oif=%d\n", dn_ntohs(oldflp->fld_dst), |
901 | dn_ntohs(oldflp->fld_src), | ||
901 | oldflp->fld_fwmark, loopback_dev.ifindex, oldflp->oif); | 902 | oldflp->fld_fwmark, loopback_dev.ifindex, oldflp->oif); |
902 | 903 | ||
903 | /* If we have an output interface, verify its a DECnet device */ | 904 | /* If we have an output interface, verify its a DECnet device */ |
@@ -961,8 +962,9 @@ source_ok: | |||
961 | if (decnet_debug_level & 16) | 962 | if (decnet_debug_level & 16) |
962 | printk(KERN_DEBUG | 963 | printk(KERN_DEBUG |
963 | "dn_route_output_slow: initial checks complete." | 964 | "dn_route_output_slow: initial checks complete." |
964 | " dst=%o4x src=%04x oif=%d try_hard=%d\n", fl.fld_dst, | 965 | " dst=%o4x src=%04x oif=%d try_hard=%d\n", |
965 | fl.fld_src, fl.oif, try_hard); | 966 | dn_ntohs(fl.fld_dst), dn_ntohs(fl.fld_src), |
967 | fl.oif, try_hard); | ||
966 | 968 | ||
967 | /* | 969 | /* |
968 | * N.B. If the kernel is compiled without router support then | 970 | * N.B. If the kernel is compiled without router support then |
@@ -1218,8 +1220,8 @@ static int dn_route_input_slow(struct sk_buff *skb) | |||
1218 | struct neighbour *neigh = NULL; | 1220 | struct neighbour *neigh = NULL; |
1219 | unsigned hash; | 1221 | unsigned hash; |
1220 | int flags = 0; | 1222 | int flags = 0; |
1221 | __u16 gateway = 0; | 1223 | __le16 gateway = 0; |
1222 | __u16 local_src = 0; | 1224 | __le16 local_src = 0; |
1223 | struct flowi fl = { .nl_u = { .dn_u = | 1225 | struct flowi fl = { .nl_u = { .dn_u = |
1224 | { .daddr = cb->dst, | 1226 | { .daddr = cb->dst, |
1225 | .saddr = cb->src, | 1227 | .saddr = cb->src, |
@@ -1266,7 +1268,7 @@ static int dn_route_input_slow(struct sk_buff *skb) | |||
1266 | res.type = RTN_LOCAL; | 1268 | res.type = RTN_LOCAL; |
1267 | flags |= RTCF_DIRECTSRC; | 1269 | flags |= RTCF_DIRECTSRC; |
1268 | } else { | 1270 | } else { |
1269 | __u16 src_map = fl.fld_src; | 1271 | __le16 src_map = fl.fld_src; |
1270 | free_res = 1; | 1272 | free_res = 1; |
1271 | 1273 | ||
1272 | out_dev = DN_FIB_RES_DEV(res); | 1274 | out_dev = DN_FIB_RES_DEV(res); |
diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index 1060de70bc0c..446faafe2065 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include <linux/timer.h> | 27 | #include <linux/timer.h> |
28 | #include <linux/spinlock.h> | 28 | #include <linux/spinlock.h> |
29 | #include <linux/in_route.h> | 29 | #include <linux/in_route.h> |
30 | #include <linux/list.h> | ||
31 | #include <linux/rcupdate.h> | ||
30 | #include <asm/atomic.h> | 32 | #include <asm/atomic.h> |
31 | #include <asm/uaccess.h> | 33 | #include <asm/uaccess.h> |
32 | #include <net/neighbour.h> | 34 | #include <net/neighbour.h> |
@@ -39,18 +41,18 @@ | |||
39 | 41 | ||
40 | struct dn_fib_rule | 42 | struct dn_fib_rule |
41 | { | 43 | { |
42 | struct dn_fib_rule *r_next; | 44 | struct hlist_node r_hlist; |
43 | atomic_t r_clntref; | 45 | atomic_t r_clntref; |
44 | u32 r_preference; | 46 | u32 r_preference; |
45 | unsigned char r_table; | 47 | unsigned char r_table; |
46 | unsigned char r_action; | 48 | unsigned char r_action; |
47 | unsigned char r_dst_len; | 49 | unsigned char r_dst_len; |
48 | unsigned char r_src_len; | 50 | unsigned char r_src_len; |
49 | dn_address r_src; | 51 | __le16 r_src; |
50 | dn_address r_srcmask; | 52 | __le16 r_srcmask; |
51 | dn_address r_dst; | 53 | __le16 r_dst; |
52 | dn_address r_dstmask; | 54 | __le16 r_dstmask; |
53 | dn_address r_srcmap; | 55 | __le16 r_srcmap; |
54 | u8 r_flags; | 56 | u8 r_flags; |
55 | #ifdef CONFIG_DECNET_ROUTE_FWMARK | 57 | #ifdef CONFIG_DECNET_ROUTE_FWMARK |
56 | u32 r_fwmark; | 58 | u32 r_fwmark; |
@@ -58,6 +60,7 @@ struct dn_fib_rule | |||
58 | int r_ifindex; | 60 | int r_ifindex; |
59 | char r_ifname[IFNAMSIZ]; | 61 | char r_ifname[IFNAMSIZ]; |
60 | int r_dead; | 62 | int r_dead; |
63 | struct rcu_head rcu; | ||
61 | }; | 64 | }; |
62 | 65 | ||
63 | static struct dn_fib_rule default_rule = { | 66 | static struct dn_fib_rule default_rule = { |
@@ -67,18 +70,17 @@ static struct dn_fib_rule default_rule = { | |||
67 | .r_action = RTN_UNICAST | 70 | .r_action = RTN_UNICAST |
68 | }; | 71 | }; |
69 | 72 | ||
70 | static struct dn_fib_rule *dn_fib_rules = &default_rule; | 73 | static struct hlist_head dn_fib_rules; |
71 | static DEFINE_RWLOCK(dn_fib_rules_lock); | ||
72 | |||
73 | 74 | ||
74 | int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 75 | int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
75 | { | 76 | { |
76 | struct rtattr **rta = arg; | 77 | struct rtattr **rta = arg; |
77 | struct rtmsg *rtm = NLMSG_DATA(nlh); | 78 | struct rtmsg *rtm = NLMSG_DATA(nlh); |
78 | struct dn_fib_rule *r, **rp; | 79 | struct dn_fib_rule *r; |
80 | struct hlist_node *node; | ||
79 | int err = -ESRCH; | 81 | int err = -ESRCH; |
80 | 82 | ||
81 | for(rp=&dn_fib_rules; (r=*rp) != NULL; rp = &r->r_next) { | 83 | hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) { |
82 | if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 2) == 0) && | 84 | if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 2) == 0) && |
83 | rtm->rtm_src_len == r->r_src_len && | 85 | rtm->rtm_src_len == r->r_src_len && |
84 | rtm->rtm_dst_len == r->r_dst_len && | 86 | rtm->rtm_dst_len == r->r_dst_len && |
@@ -95,10 +97,8 @@ int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
95 | if (r == &default_rule) | 97 | if (r == &default_rule) |
96 | break; | 98 | break; |
97 | 99 | ||
98 | write_lock_bh(&dn_fib_rules_lock); | 100 | hlist_del_rcu(&r->r_hlist); |
99 | *rp = r->r_next; | ||
100 | r->r_dead = 1; | 101 | r->r_dead = 1; |
101 | write_unlock_bh(&dn_fib_rules_lock); | ||
102 | dn_fib_rule_put(r); | 102 | dn_fib_rule_put(r); |
103 | err = 0; | 103 | err = 0; |
104 | break; | 104 | break; |
@@ -108,11 +108,17 @@ int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
108 | return err; | 108 | return err; |
109 | } | 109 | } |
110 | 110 | ||
111 | static inline void dn_fib_rule_put_rcu(struct rcu_head *head) | ||
112 | { | ||
113 | struct dn_fib_rule *r = container_of(head, struct dn_fib_rule, rcu); | ||
114 | kfree(r); | ||
115 | } | ||
116 | |||
111 | void dn_fib_rule_put(struct dn_fib_rule *r) | 117 | void dn_fib_rule_put(struct dn_fib_rule *r) |
112 | { | 118 | { |
113 | if (atomic_dec_and_test(&r->r_clntref)) { | 119 | if (atomic_dec_and_test(&r->r_clntref)) { |
114 | if (r->r_dead) | 120 | if (r->r_dead) |
115 | kfree(r); | 121 | call_rcu(&r->rcu, dn_fib_rule_put_rcu); |
116 | else | 122 | else |
117 | printk(KERN_DEBUG "Attempt to free alive dn_fib_rule\n"); | 123 | printk(KERN_DEBUG "Attempt to free alive dn_fib_rule\n"); |
118 | } | 124 | } |
@@ -123,7 +129,8 @@ int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
123 | { | 129 | { |
124 | struct rtattr **rta = arg; | 130 | struct rtattr **rta = arg; |
125 | struct rtmsg *rtm = NLMSG_DATA(nlh); | 131 | struct rtmsg *rtm = NLMSG_DATA(nlh); |
126 | struct dn_fib_rule *r, *new_r, **rp; | 132 | struct dn_fib_rule *r, *new_r, *last = NULL; |
133 | struct hlist_node *node = NULL; | ||
127 | unsigned char table_id; | 134 | unsigned char table_id; |
128 | 135 | ||
129 | if (rtm->rtm_src_len > 16 || rtm->rtm_dst_len > 16) | 136 | if (rtm->rtm_src_len > 16 || rtm->rtm_dst_len > 16) |
@@ -149,6 +156,7 @@ int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
149 | if (!new_r) | 156 | if (!new_r) |
150 | return -ENOMEM; | 157 | return -ENOMEM; |
151 | memset(new_r, 0, sizeof(*new_r)); | 158 | memset(new_r, 0, sizeof(*new_r)); |
159 | |||
152 | if (rta[RTA_SRC-1]) | 160 | if (rta[RTA_SRC-1]) |
153 | memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 2); | 161 | memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 2); |
154 | if (rta[RTA_DST-1]) | 162 | if (rta[RTA_DST-1]) |
@@ -179,27 +187,26 @@ int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
179 | } | 187 | } |
180 | } | 188 | } |
181 | 189 | ||
182 | rp = &dn_fib_rules; | 190 | r = container_of(dn_fib_rules.first, struct dn_fib_rule, r_hlist); |
183 | if (!new_r->r_preference) { | 191 | if (!new_r->r_preference) { |
184 | r = dn_fib_rules; | 192 | if (r && r->r_hlist.next != NULL) { |
185 | if (r && (r = r->r_next) != NULL) { | 193 | r = container_of(r->r_hlist.next, struct dn_fib_rule, r_hlist); |
186 | rp = &dn_fib_rules->r_next; | ||
187 | if (r->r_preference) | 194 | if (r->r_preference) |
188 | new_r->r_preference = r->r_preference - 1; | 195 | new_r->r_preference = r->r_preference - 1; |
189 | } | 196 | } |
190 | } | 197 | } |
191 | 198 | ||
192 | while((r=*rp) != NULL) { | 199 | hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) { |
193 | if (r->r_preference > new_r->r_preference) | 200 | if (r->r_preference > new_r->r_preference) |
194 | break; | 201 | break; |
195 | rp = &r->r_next; | 202 | last = r; |
196 | } | 203 | } |
197 | |||
198 | new_r->r_next = r; | ||
199 | atomic_inc(&new_r->r_clntref); | 204 | atomic_inc(&new_r->r_clntref); |
200 | write_lock_bh(&dn_fib_rules_lock); | 205 | |
201 | *rp = new_r; | 206 | if (last) |
202 | write_unlock_bh(&dn_fib_rules_lock); | 207 | hlist_add_after_rcu(&last->r_hlist, &new_r->r_hlist); |
208 | else | ||
209 | hlist_add_before_rcu(&new_r->r_hlist, &r->r_hlist); | ||
203 | return 0; | 210 | return 0; |
204 | } | 211 | } |
205 | 212 | ||
@@ -208,12 +215,14 @@ int dn_fib_lookup(const struct flowi *flp, struct dn_fib_res *res) | |||
208 | { | 215 | { |
209 | struct dn_fib_rule *r, *policy; | 216 | struct dn_fib_rule *r, *policy; |
210 | struct dn_fib_table *tb; | 217 | struct dn_fib_table *tb; |
211 | dn_address saddr = flp->fld_src; | 218 | __le16 saddr = flp->fld_src; |
212 | dn_address daddr = flp->fld_dst; | 219 | __le16 daddr = flp->fld_dst; |
220 | struct hlist_node *node; | ||
213 | int err; | 221 | int err; |
214 | 222 | ||
215 | read_lock(&dn_fib_rules_lock); | 223 | rcu_read_lock(); |
216 | for(r = dn_fib_rules; r; r = r->r_next) { | 224 | |
225 | hlist_for_each_entry_rcu(r, node, &dn_fib_rules, r_hlist) { | ||
217 | if (((saddr^r->r_src) & r->r_srcmask) || | 226 | if (((saddr^r->r_src) & r->r_srcmask) || |
218 | ((daddr^r->r_dst) & r->r_dstmask) || | 227 | ((daddr^r->r_dst) & r->r_dstmask) || |
219 | #ifdef CONFIG_DECNET_ROUTE_FWMARK | 228 | #ifdef CONFIG_DECNET_ROUTE_FWMARK |
@@ -228,14 +237,14 @@ int dn_fib_lookup(const struct flowi *flp, struct dn_fib_res *res) | |||
228 | policy = r; | 237 | policy = r; |
229 | break; | 238 | break; |
230 | case RTN_UNREACHABLE: | 239 | case RTN_UNREACHABLE: |
231 | read_unlock(&dn_fib_rules_lock); | 240 | rcu_read_unlock(); |
232 | return -ENETUNREACH; | 241 | return -ENETUNREACH; |
233 | default: | 242 | default: |
234 | case RTN_BLACKHOLE: | 243 | case RTN_BLACKHOLE: |
235 | read_unlock(&dn_fib_rules_lock); | 244 | rcu_read_unlock(); |
236 | return -EINVAL; | 245 | return -EINVAL; |
237 | case RTN_PROHIBIT: | 246 | case RTN_PROHIBIT: |
238 | read_unlock(&dn_fib_rules_lock); | 247 | rcu_read_unlock(); |
239 | return -EACCES; | 248 | return -EACCES; |
240 | } | 249 | } |
241 | 250 | ||
@@ -246,20 +255,20 @@ int dn_fib_lookup(const struct flowi *flp, struct dn_fib_res *res) | |||
246 | res->r = policy; | 255 | res->r = policy; |
247 | if (policy) | 256 | if (policy) |
248 | atomic_inc(&policy->r_clntref); | 257 | atomic_inc(&policy->r_clntref); |
249 | read_unlock(&dn_fib_rules_lock); | 258 | rcu_read_unlock(); |
250 | return 0; | 259 | return 0; |
251 | } | 260 | } |
252 | if (err < 0 && err != -EAGAIN) { | 261 | if (err < 0 && err != -EAGAIN) { |
253 | read_unlock(&dn_fib_rules_lock); | 262 | rcu_read_unlock(); |
254 | return err; | 263 | return err; |
255 | } | 264 | } |
256 | } | 265 | } |
257 | 266 | ||
258 | read_unlock(&dn_fib_rules_lock); | 267 | rcu_read_unlock(); |
259 | return -ESRCH; | 268 | return -ESRCH; |
260 | } | 269 | } |
261 | 270 | ||
262 | unsigned dnet_addr_type(__u16 addr) | 271 | unsigned dnet_addr_type(__le16 addr) |
263 | { | 272 | { |
264 | struct flowi fl = { .nl_u = { .dn_u = { .daddr = addr } } }; | 273 | struct flowi fl = { .nl_u = { .dn_u = { .daddr = addr } } }; |
265 | struct dn_fib_res res; | 274 | struct dn_fib_res res; |
@@ -277,7 +286,7 @@ unsigned dnet_addr_type(__u16 addr) | |||
277 | return ret; | 286 | return ret; |
278 | } | 287 | } |
279 | 288 | ||
280 | __u16 dn_fib_rules_policy(__u16 saddr, struct dn_fib_res *res, unsigned *flags) | 289 | __le16 dn_fib_rules_policy(__le16 saddr, struct dn_fib_res *res, unsigned *flags) |
281 | { | 290 | { |
282 | struct dn_fib_rule *r = res->r; | 291 | struct dn_fib_rule *r = res->r; |
283 | 292 | ||
@@ -297,27 +306,23 @@ __u16 dn_fib_rules_policy(__u16 saddr, struct dn_fib_res *res, unsigned *flags) | |||
297 | 306 | ||
298 | static void dn_fib_rules_detach(struct net_device *dev) | 307 | static void dn_fib_rules_detach(struct net_device *dev) |
299 | { | 308 | { |
309 | struct hlist_node *node; | ||
300 | struct dn_fib_rule *r; | 310 | struct dn_fib_rule *r; |
301 | 311 | ||
302 | for(r = dn_fib_rules; r; r = r->r_next) { | 312 | hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) { |
303 | if (r->r_ifindex == dev->ifindex) { | 313 | if (r->r_ifindex == dev->ifindex) |
304 | write_lock_bh(&dn_fib_rules_lock); | ||
305 | r->r_ifindex = -1; | 314 | r->r_ifindex = -1; |
306 | write_unlock_bh(&dn_fib_rules_lock); | ||
307 | } | ||
308 | } | 315 | } |
309 | } | 316 | } |
310 | 317 | ||
311 | static void dn_fib_rules_attach(struct net_device *dev) | 318 | static void dn_fib_rules_attach(struct net_device *dev) |
312 | { | 319 | { |
320 | struct hlist_node *node; | ||
313 | struct dn_fib_rule *r; | 321 | struct dn_fib_rule *r; |
314 | 322 | ||
315 | for(r = dn_fib_rules; r; r = r->r_next) { | 323 | hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) { |
316 | if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) { | 324 | if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) |
317 | write_lock_bh(&dn_fib_rules_lock); | ||
318 | r->r_ifindex = dev->ifindex; | 325 | r->r_ifindex = dev->ifindex; |
319 | write_unlock_bh(&dn_fib_rules_lock); | ||
320 | } | ||
321 | } | 326 | } |
322 | } | 327 | } |
323 | 328 | ||
@@ -387,18 +392,20 @@ rtattr_failure: | |||
387 | 392 | ||
388 | int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) | 393 | int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) |
389 | { | 394 | { |
390 | int idx; | 395 | int idx = 0; |
391 | int s_idx = cb->args[0]; | 396 | int s_idx = cb->args[0]; |
392 | struct dn_fib_rule *r; | 397 | struct dn_fib_rule *r; |
398 | struct hlist_node *node; | ||
393 | 399 | ||
394 | read_lock(&dn_fib_rules_lock); | 400 | rcu_read_lock(); |
395 | for(r = dn_fib_rules, idx = 0; r; r = r->r_next, idx++) { | 401 | hlist_for_each_entry(r, node, &dn_fib_rules, r_hlist) { |
396 | if (idx < s_idx) | 402 | if (idx < s_idx) |
397 | continue; | 403 | continue; |
398 | if (dn_fib_fill_rule(skb, r, cb, NLM_F_MULTI) < 0) | 404 | if (dn_fib_fill_rule(skb, r, cb, NLM_F_MULTI) < 0) |
399 | break; | 405 | break; |
406 | idx++; | ||
400 | } | 407 | } |
401 | read_unlock(&dn_fib_rules_lock); | 408 | rcu_read_unlock(); |
402 | cb->args[0] = idx; | 409 | cb->args[0] = idx; |
403 | 410 | ||
404 | return skb->len; | 411 | return skb->len; |
@@ -406,6 +413,8 @@ int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) | |||
406 | 413 | ||
407 | void __init dn_fib_rules_init(void) | 414 | void __init dn_fib_rules_init(void) |
408 | { | 415 | { |
416 | INIT_HLIST_HEAD(&dn_fib_rules); | ||
417 | hlist_add_head(&default_rule.r_hlist, &dn_fib_rules); | ||
409 | register_netdevice_notifier(&dn_fib_rules_notifier); | 418 | register_netdevice_notifier(&dn_fib_rules_notifier); |
410 | } | 419 | } |
411 | 420 | ||
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index 6f8b5658cb4e..0ebc46af1bdd 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c | |||
@@ -46,7 +46,7 @@ struct dn_zone | |||
46 | u32 dz_hashmask; | 46 | u32 dz_hashmask; |
47 | #define DZ_HASHMASK(dz) ((dz)->dz_hashmask) | 47 | #define DZ_HASHMASK(dz) ((dz)->dz_hashmask) |
48 | int dz_order; | 48 | int dz_order; |
49 | u16 dz_mask; | 49 | __le16 dz_mask; |
50 | #define DZ_MASK(dz) ((dz)->dz_mask) | 50 | #define DZ_MASK(dz) ((dz)->dz_mask) |
51 | }; | 51 | }; |
52 | 52 | ||
@@ -84,14 +84,14 @@ static int dn_fib_hash_zombies; | |||
84 | 84 | ||
85 | static inline dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz) | 85 | static inline dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz) |
86 | { | 86 | { |
87 | u16 h = ntohs(key.datum)>>(16 - dz->dz_order); | 87 | u16 h = dn_ntohs(key.datum)>>(16 - dz->dz_order); |
88 | h ^= (h >> 10); | 88 | h ^= (h >> 10); |
89 | h ^= (h >> 6); | 89 | h ^= (h >> 6); |
90 | h &= DZ_HASHMASK(dz); | 90 | h &= DZ_HASHMASK(dz); |
91 | return *(dn_fib_idx_t *)&h; | 91 | return *(dn_fib_idx_t *)&h; |
92 | } | 92 | } |
93 | 93 | ||
94 | static inline dn_fib_key_t dz_key(u16 dst, struct dn_zone *dz) | 94 | static inline dn_fib_key_t dz_key(__le16 dst, struct dn_zone *dz) |
95 | { | 95 | { |
96 | dn_fib_key_t k; | 96 | dn_fib_key_t k; |
97 | k.datum = dst & DZ_MASK(dz); | 97 | k.datum = dst & DZ_MASK(dz); |
@@ -250,7 +250,7 @@ static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern | |||
250 | 250 | ||
251 | for_nexthops(fi) { | 251 | for_nexthops(fi) { |
252 | int attrlen = nhlen - sizeof(struct rtnexthop); | 252 | int attrlen = nhlen - sizeof(struct rtnexthop); |
253 | dn_address gw; | 253 | __le16 gw; |
254 | 254 | ||
255 | if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0) | 255 | if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0) |
256 | return -EINVAL; | 256 | return -EINVAL; |
@@ -457,7 +457,7 @@ static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct | |||
457 | 457 | ||
458 | dz_key_0(key); | 458 | dz_key_0(key); |
459 | if (rta->rta_dst) { | 459 | if (rta->rta_dst) { |
460 | dn_address dst; | 460 | __le16 dst; |
461 | memcpy(&dst, rta->rta_dst, 2); | 461 | memcpy(&dst, rta->rta_dst, 2); |
462 | if (dst & ~DZ_MASK(dz)) | 462 | if (dst & ~DZ_MASK(dz)) |
463 | return -EINVAL; | 463 | return -EINVAL; |
@@ -593,7 +593,7 @@ static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct | |||
593 | 593 | ||
594 | dz_key_0(key); | 594 | dz_key_0(key); |
595 | if (rta->rta_dst) { | 595 | if (rta->rta_dst) { |
596 | dn_address dst; | 596 | __le16 dst; |
597 | memcpy(&dst, rta->rta_dst, 2); | 597 | memcpy(&dst, rta->rta_dst, 2); |
598 | if (dst & ~DZ_MASK(dz)) | 598 | if (dst & ~DZ_MASK(dz)) |
599 | return -EINVAL; | 599 | return -EINVAL; |
diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c index 0e9d2c571165..bda5920215fd 100644 --- a/net/decnet/sysctl_net_decnet.c +++ b/net/decnet/sysctl_net_decnet.c | |||
@@ -86,9 +86,9 @@ static void strip_it(char *str) | |||
86 | * Simple routine to parse an ascii DECnet address | 86 | * Simple routine to parse an ascii DECnet address |
87 | * into a network order address. | 87 | * into a network order address. |
88 | */ | 88 | */ |
89 | static int parse_addr(dn_address *addr, char *str) | 89 | static int parse_addr(__le16 *addr, char *str) |
90 | { | 90 | { |
91 | dn_address area, node; | 91 | __u16 area, node; |
92 | 92 | ||
93 | while(*str && !ISNUM(*str)) str++; | 93 | while(*str && !ISNUM(*str)) str++; |
94 | 94 | ||
@@ -139,7 +139,7 @@ static int dn_node_address_strategy(ctl_table *table, int __user *name, int nlen | |||
139 | void **context) | 139 | void **context) |
140 | { | 140 | { |
141 | size_t len; | 141 | size_t len; |
142 | dn_address addr; | 142 | __le16 addr; |
143 | 143 | ||
144 | if (oldval && oldlenp) { | 144 | if (oldval && oldlenp) { |
145 | if (get_user(len, oldlenp)) | 145 | if (get_user(len, oldlenp)) |
@@ -147,14 +147,14 @@ static int dn_node_address_strategy(ctl_table *table, int __user *name, int nlen | |||
147 | if (len) { | 147 | if (len) { |
148 | if (len != sizeof(unsigned short)) | 148 | if (len != sizeof(unsigned short)) |
149 | return -EINVAL; | 149 | return -EINVAL; |
150 | if (put_user(decnet_address, (unsigned short __user *)oldval)) | 150 | if (put_user(decnet_address, (__le16 __user *)oldval)) |
151 | return -EFAULT; | 151 | return -EFAULT; |
152 | } | 152 | } |
153 | } | 153 | } |
154 | if (newval && newlen) { | 154 | if (newval && newlen) { |
155 | if (newlen != sizeof(unsigned short)) | 155 | if (newlen != sizeof(unsigned short)) |
156 | return -EINVAL; | 156 | return -EINVAL; |
157 | if (get_user(addr, (unsigned short __user *)newval)) | 157 | if (get_user(addr, (__le16 __user *)newval)) |
158 | return -EFAULT; | 158 | return -EFAULT; |
159 | 159 | ||
160 | dn_dev_devices_off(); | 160 | dn_dev_devices_off(); |
@@ -173,7 +173,7 @@ static int dn_node_address_handler(ctl_table *table, int write, | |||
173 | { | 173 | { |
174 | char addr[DN_ASCBUF_LEN]; | 174 | char addr[DN_ASCBUF_LEN]; |
175 | size_t len; | 175 | size_t len; |
176 | dn_address dnaddr; | 176 | __le16 dnaddr; |
177 | 177 | ||
178 | if (!*lenp || (*ppos && !write)) { | 178 | if (!*lenp || (*ppos && !write)) { |
179 | *lenp = 0; | 179 | *lenp = 0; |
diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig index d18ccba3ea9e..dbb08528ddf5 100644 --- a/net/ieee80211/Kconfig +++ b/net/ieee80211/Kconfig | |||
@@ -66,3 +66,4 @@ config IEEE80211_CRYPT_TKIP | |||
66 | This can be compiled as a modules and it will be called | 66 | This can be compiled as a modules and it will be called |
67 | "ieee80211_crypt_tkip". | 67 | "ieee80211_crypt_tkip". |
68 | 68 | ||
69 | source "net/ieee80211/softmac/Kconfig" | ||
diff --git a/net/ieee80211/Makefile b/net/ieee80211/Makefile index f988417121da..796a7c76ee48 100644 --- a/net/ieee80211/Makefile +++ b/net/ieee80211/Makefile | |||
@@ -10,3 +10,4 @@ ieee80211-objs := \ | |||
10 | ieee80211_wx.o \ | 10 | ieee80211_wx.o \ |
11 | ieee80211_geo.o | 11 | ieee80211_geo.o |
12 | 12 | ||
13 | obj-$(CONFIG_IEEE80211_SOFTMAC) += softmac/ | ||
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index a7f2a642a512..604b7b0097bc 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c | |||
@@ -780,6 +780,80 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, | |||
780 | return 0; | 780 | return 0; |
781 | } | 781 | } |
782 | 782 | ||
783 | /* Filter out unrelated packets, call ieee80211_rx[_mgt] */ | ||
784 | int ieee80211_rx_any(struct ieee80211_device *ieee, | ||
785 | struct sk_buff *skb, struct ieee80211_rx_stats *stats) | ||
786 | { | ||
787 | struct ieee80211_hdr_4addr *hdr; | ||
788 | int is_packet_for_us; | ||
789 | u16 fc; | ||
790 | |||
791 | if (ieee->iw_mode == IW_MODE_MONITOR) | ||
792 | return ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL; | ||
793 | |||
794 | hdr = (struct ieee80211_hdr_4addr *)skb->data; | ||
795 | fc = le16_to_cpu(hdr->frame_ctl); | ||
796 | |||
797 | if ((fc & IEEE80211_FCTL_VERS) != 0) | ||
798 | return -EINVAL; | ||
799 | |||
800 | switch (fc & IEEE80211_FCTL_FTYPE) { | ||
801 | case IEEE80211_FTYPE_MGMT: | ||
802 | ieee80211_rx_mgt(ieee, hdr, stats); | ||
803 | return 0; | ||
804 | case IEEE80211_FTYPE_DATA: | ||
805 | break; | ||
806 | case IEEE80211_FTYPE_CTL: | ||
807 | return 0; | ||
808 | default: | ||
809 | return -EINVAL; | ||
810 | } | ||
811 | |||
812 | is_packet_for_us = 0; | ||
813 | switch (ieee->iw_mode) { | ||
814 | case IW_MODE_ADHOC: | ||
815 | /* our BSS and not from/to DS */ | ||
816 | if (memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) == 0) | ||
817 | if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) { | ||
818 | /* promisc: get all */ | ||
819 | if (ieee->dev->flags & IFF_PROMISC) | ||
820 | is_packet_for_us = 1; | ||
821 | /* to us */ | ||
822 | else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0) | ||
823 | is_packet_for_us = 1; | ||
824 | /* mcast */ | ||
825 | else if (is_multicast_ether_addr(hdr->addr1)) | ||
826 | is_packet_for_us = 1; | ||
827 | } | ||
828 | break; | ||
829 | case IW_MODE_INFRA: | ||
830 | /* our BSS (== from our AP) and from DS */ | ||
831 | if (memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) == 0) | ||
832 | if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) { | ||
833 | /* promisc: get all */ | ||
834 | if (ieee->dev->flags & IFF_PROMISC) | ||
835 | is_packet_for_us = 1; | ||
836 | /* to us */ | ||
837 | else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0) | ||
838 | is_packet_for_us = 1; | ||
839 | /* mcast */ | ||
840 | else if (is_multicast_ether_addr(hdr->addr1)) { | ||
841 | /* not our own packet bcasted from AP */ | ||
842 | if (memcmp(hdr->addr3, ieee->dev->dev_addr, ETH_ALEN)) | ||
843 | is_packet_for_us = 1; | ||
844 | } | ||
845 | } | ||
846 | break; | ||
847 | default: | ||
848 | /* ? */ | ||
849 | break; | ||
850 | } | ||
851 | |||
852 | if (is_packet_for_us) | ||
853 | return (ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL); | ||
854 | return 0; | ||
855 | } | ||
856 | |||
783 | #define MGMT_FRAME_FIXED_PART_LENGTH 0x24 | 857 | #define MGMT_FRAME_FIXED_PART_LENGTH 0x24 |
784 | 858 | ||
785 | static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; | 859 | static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; |
diff --git a/net/ieee80211/softmac/Kconfig b/net/ieee80211/softmac/Kconfig new file mode 100644 index 000000000000..6cd9f3427be6 --- /dev/null +++ b/net/ieee80211/softmac/Kconfig | |||
@@ -0,0 +1,10 @@ | |||
1 | config IEEE80211_SOFTMAC | ||
2 | tristate "Software MAC add-on to the IEEE 802.11 networking stack" | ||
3 | depends on IEEE80211 && EXPERIMENTAL | ||
4 | ---help--- | ||
5 | This option enables the hardware independent software MAC addon | ||
6 | for the IEEE 802.11 networking stack. | ||
7 | |||
8 | config IEEE80211_SOFTMAC_DEBUG | ||
9 | bool "Enable full debugging output" | ||
10 | depends on IEEE80211_SOFTMAC | ||
diff --git a/net/ieee80211/softmac/Makefile b/net/ieee80211/softmac/Makefile new file mode 100644 index 000000000000..bfcb391bb2c7 --- /dev/null +++ b/net/ieee80211/softmac/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | obj-$(CONFIG_IEEE80211_SOFTMAC) += ieee80211softmac.o | ||
2 | ieee80211softmac-objs := \ | ||
3 | ieee80211softmac_io.o \ | ||
4 | ieee80211softmac_auth.o \ | ||
5 | ieee80211softmac_module.o \ | ||
6 | ieee80211softmac_scan.o \ | ||
7 | ieee80211softmac_wx.o \ | ||
8 | ieee80211softmac_assoc.o \ | ||
9 | ieee80211softmac_event.o | ||
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c new file mode 100644 index 000000000000..be61de78dfa4 --- /dev/null +++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c | |||
@@ -0,0 +1,396 @@ | |||
1 | /* | ||
2 | * This file contains the softmac's association logic. | ||
3 | * | ||
4 | * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * Joseph Jezak <josejx@gentoo.org> | ||
6 | * Larry Finger <Larry.Finger@lwfinger.net> | ||
7 | * Danny van Dyk <kugelfang@gentoo.org> | ||
8 | * Michael Buesch <mbuesch@freenet.de> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * | ||
23 | * The full GNU General Public License is included in this distribution in the | ||
24 | * file called COPYING. | ||
25 | */ | ||
26 | |||
27 | #include "ieee80211softmac_priv.h" | ||
28 | |||
29 | /* | ||
30 | * Overview | ||
31 | * | ||
32 | * Before you can associate, you have to authenticate. | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | /* Sends out an association request to the desired AP */ | ||
37 | static void | ||
38 | ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net) | ||
39 | { | ||
40 | unsigned long flags; | ||
41 | |||
42 | /* Switch to correct channel for this network */ | ||
43 | mac->set_channel(mac->dev, net->channel); | ||
44 | |||
45 | /* Send association request */ | ||
46 | ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_ASSOC_REQ, 0); | ||
47 | |||
48 | dprintk(KERN_INFO PFX "sent association request!\n"); | ||
49 | |||
50 | /* Change the state to associating */ | ||
51 | spin_lock_irqsave(&mac->lock, flags); | ||
52 | mac->associnfo.associating = 1; | ||
53 | mac->associated = 0; /* just to make sure */ | ||
54 | spin_unlock_irqrestore(&mac->lock, flags); | ||
55 | |||
56 | /* Set a timer for timeout */ | ||
57 | /* FIXME: make timeout configurable */ | ||
58 | schedule_delayed_work(&mac->associnfo.timeout, 5 * HZ); | ||
59 | } | ||
60 | |||
61 | void | ||
62 | ieee80211softmac_assoc_timeout(void *d) | ||
63 | { | ||
64 | struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d; | ||
65 | unsigned long flags; | ||
66 | |||
67 | spin_lock_irqsave(&mac->lock, flags); | ||
68 | /* we might race against ieee80211softmac_handle_assoc_response, | ||
69 | * so make sure only one of us does something */ | ||
70 | if (!mac->associnfo.associating) { | ||
71 | spin_unlock_irqrestore(&mac->lock, flags); | ||
72 | return; | ||
73 | } | ||
74 | mac->associnfo.associating = 0; | ||
75 | mac->associnfo.bssvalid = 0; | ||
76 | mac->associated = 0; | ||
77 | spin_unlock_irqrestore(&mac->lock, flags); | ||
78 | |||
79 | dprintk(KERN_INFO PFX "assoc request timed out!\n"); | ||
80 | /* FIXME: we need to know the network here. that requires a bit of restructuring */ | ||
81 | ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL); | ||
82 | } | ||
83 | |||
84 | /* Sends out a disassociation request to the desired AP */ | ||
85 | static void | ||
86 | ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason) | ||
87 | { | ||
88 | unsigned long flags; | ||
89 | struct ieee80211softmac_network *found; | ||
90 | |||
91 | if (mac->associnfo.bssvalid && mac->associated) { | ||
92 | found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid); | ||
93 | if (found) | ||
94 | ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason); | ||
95 | } else if (mac->associnfo.associating) { | ||
96 | cancel_delayed_work(&mac->associnfo.timeout); | ||
97 | } | ||
98 | |||
99 | /* Change our state */ | ||
100 | spin_lock_irqsave(&mac->lock, flags); | ||
101 | /* Do NOT clear bssvalid as that will break ieee80211softmac_assoc_work! */ | ||
102 | mac->associated = 0; | ||
103 | mac->associnfo.associating = 0; | ||
104 | spin_unlock_irqrestore(&mac->lock, flags); | ||
105 | } | ||
106 | |||
107 | static inline int | ||
108 | we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len) | ||
109 | { | ||
110 | int idx, search, found; | ||
111 | u8 rate, search_rate; | ||
112 | |||
113 | for (idx = 0; idx < (from_len); idx++) { | ||
114 | rate = (from)[idx]; | ||
115 | if (!(rate & IEEE80211_BASIC_RATE_MASK)) | ||
116 | continue; | ||
117 | found = 0; | ||
118 | rate &= ~IEEE80211_BASIC_RATE_MASK; | ||
119 | for (search = 0; search < mac->ratesinfo.count; search++) { | ||
120 | search_rate = mac->ratesinfo.rates[search]; | ||
121 | search_rate &= ~IEEE80211_BASIC_RATE_MASK; | ||
122 | if (rate == search_rate) { | ||
123 | found = 1; | ||
124 | break; | ||
125 | } | ||
126 | } | ||
127 | if (!found) | ||
128 | return 0; | ||
129 | } | ||
130 | return 1; | ||
131 | } | ||
132 | |||
133 | static int | ||
134 | network_matches_request(struct ieee80211softmac_device *mac, struct ieee80211_network *net) | ||
135 | { | ||
136 | /* we cannot associate to networks whose name we don't know */ | ||
137 | if (ieee80211_is_empty_essid(net->ssid, net->ssid_len)) | ||
138 | return 0; | ||
139 | /* do not associate to a network whose BSSBasicRateSet we cannot support */ | ||
140 | if (!we_support_all_basic_rates(mac, net->rates, net->rates_len)) | ||
141 | return 0; | ||
142 | /* do we really need to check the ex rates? */ | ||
143 | if (!we_support_all_basic_rates(mac, net->rates_ex, net->rates_ex_len)) | ||
144 | return 0; | ||
145 | |||
146 | /* if 'ANY' network requested, take any that doesn't have privacy enabled */ | ||
147 | if (mac->associnfo.req_essid.len == 0 | ||
148 | && !(net->capability & WLAN_CAPABILITY_PRIVACY)) | ||
149 | return 1; | ||
150 | if (net->ssid_len != mac->associnfo.req_essid.len) | ||
151 | return 0; | ||
152 | if (!memcmp(net->ssid, mac->associnfo.req_essid.data, mac->associnfo.req_essid.len)) | ||
153 | return 1; | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static void | ||
158 | ieee80211softmac_assoc_notify(struct net_device *dev, void *context) | ||
159 | { | ||
160 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
161 | ieee80211softmac_assoc_work((void*)mac); | ||
162 | } | ||
163 | |||
164 | /* This function is called to handle userspace requests (asynchronously) */ | ||
165 | void | ||
166 | ieee80211softmac_assoc_work(void *d) | ||
167 | { | ||
168 | struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d; | ||
169 | struct ieee80211softmac_network *found = NULL; | ||
170 | struct ieee80211_network *net = NULL, *best = NULL; | ||
171 | unsigned long flags; | ||
172 | |||
173 | /* meh */ | ||
174 | if (mac->associated) | ||
175 | ieee80211softmac_disassoc(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT); | ||
176 | |||
177 | /* try to find the requested network in our list, if we found one already */ | ||
178 | if (mac->associnfo.bssvalid) | ||
179 | found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid); | ||
180 | |||
181 | /* Search the ieee80211 networks for this network if we didn't find it by bssid, | ||
182 | * but only if we've scanned at least once (to get a better list of networks to | ||
183 | * select from). If we have not scanned before, the !found logic below will be | ||
184 | * invoked and will scan. */ | ||
185 | if (!found && (mac->associnfo.scan_retry < IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT)) | ||
186 | { | ||
187 | s8 rssi = -128; /* if I don't initialise, gcc emits an invalid warning | ||
188 | because it cannot follow the best pointer logic. */ | ||
189 | spin_lock_irqsave(&mac->ieee->lock, flags); | ||
190 | list_for_each_entry(net, &mac->ieee->network_list, list) { | ||
191 | /* we're supposed to find the network with | ||
192 | * the best signal here, as we're asked to join | ||
193 | * any network with a specific ESSID, and many | ||
194 | * different ones could have that. | ||
195 | * | ||
196 | * I'll for now just go with the reported rssi. | ||
197 | * | ||
198 | * We also should take into account the rateset | ||
199 | * here to find the best BSSID to try. | ||
200 | */ | ||
201 | if (network_matches_request(mac, net)) { | ||
202 | if (!best) { | ||
203 | best = net; | ||
204 | rssi = best->stats.rssi; | ||
205 | continue; | ||
206 | } | ||
207 | /* we already had a matching network, so | ||
208 | * compare their properties to get the | ||
209 | * better of the two ... (see above) | ||
210 | */ | ||
211 | if (rssi < net->stats.rssi) { | ||
212 | best = net; | ||
213 | rssi = best->stats.rssi; | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | /* if we unlock here, we might get interrupted and the `best' | ||
218 | * pointer could go stale */ | ||
219 | if (best) { | ||
220 | found = ieee80211softmac_create_network(mac, best); | ||
221 | /* if found is still NULL, then we got -ENOMEM somewhere */ | ||
222 | if (found) | ||
223 | ieee80211softmac_add_network(mac, found); | ||
224 | } | ||
225 | spin_unlock_irqrestore(&mac->ieee->lock, flags); | ||
226 | } | ||
227 | |||
228 | if (!found) { | ||
229 | if (mac->associnfo.scan_retry > 0) { | ||
230 | spin_lock_irqsave(&mac->lock, flags); | ||
231 | mac->associnfo.scan_retry--; | ||
232 | spin_unlock_irqrestore(&mac->lock, flags); | ||
233 | |||
234 | /* We know of no such network. Let's scan. | ||
235 | * NB: this also happens if we had no memory to copy the network info... | ||
236 | * Maybe we can hope to have more memory after scanning finishes ;) | ||
237 | */ | ||
238 | dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n"); | ||
239 | ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify, NULL); | ||
240 | if (ieee80211softmac_start_scan(mac)) | ||
241 | dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n"); | ||
242 | return; | ||
243 | } | ||
244 | else { | ||
245 | spin_lock_irqsave(&mac->lock, flags); | ||
246 | mac->associnfo.associating = 0; | ||
247 | mac->associated = 0; | ||
248 | spin_unlock_irqrestore(&mac->lock, flags); | ||
249 | |||
250 | dprintk(KERN_INFO PFX "Unable to find matching network after scan!\n"); | ||
251 | ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND, NULL); | ||
252 | return; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | mac->associnfo.bssvalid = 1; | ||
257 | memcpy(mac->associnfo.bssid, found->bssid, ETH_ALEN); | ||
258 | /* copy the ESSID for displaying it */ | ||
259 | mac->associnfo.associate_essid.len = found->essid.len; | ||
260 | memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1); | ||
261 | |||
262 | /* we found a network! authenticate (if necessary) and associate to it. */ | ||
263 | if (!found->authenticated) { | ||
264 | /* This relies on the fact that _auth_req only queues the work, | ||
265 | * otherwise adding the notification would be racy. */ | ||
266 | if (!ieee80211softmac_auth_req(mac, found)) { | ||
267 | dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n"); | ||
268 | ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify, NULL, GFP_KERNEL); | ||
269 | } else { | ||
270 | printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n"); | ||
271 | ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found); | ||
272 | } | ||
273 | return; | ||
274 | } | ||
275 | /* finally! now we can start associating */ | ||
276 | ieee80211softmac_assoc(mac, found); | ||
277 | } | ||
278 | |||
279 | /* call this to do whatever is necessary when we're associated */ | ||
280 | static void | ||
281 | ieee80211softmac_associated(struct ieee80211softmac_device *mac, | ||
282 | struct ieee80211_assoc_response * resp, | ||
283 | struct ieee80211softmac_network *net) | ||
284 | { | ||
285 | mac->associnfo.associating = 0; | ||
286 | mac->associated = 1; | ||
287 | if (mac->set_bssid_filter) | ||
288 | mac->set_bssid_filter(mac->dev, net->bssid); | ||
289 | memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN); | ||
290 | netif_carrier_on(mac->dev); | ||
291 | |||
292 | mac->association_id = le16_to_cpup(&resp->aid); | ||
293 | } | ||
294 | |||
295 | /* received frame handling functions */ | ||
296 | int | ||
297 | ieee80211softmac_handle_assoc_response(struct net_device * dev, | ||
298 | struct ieee80211_assoc_response * resp, | ||
299 | struct ieee80211_network * _ieee80211_network_do_not_use) | ||
300 | { | ||
301 | /* NOTE: the network parameter has to be ignored by | ||
302 | * this code because it is the ieee80211's pointer | ||
303 | * to the struct, not ours (we made a copy) | ||
304 | */ | ||
305 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
306 | u16 status = le16_to_cpup(&resp->status); | ||
307 | struct ieee80211softmac_network *network = NULL; | ||
308 | unsigned long flags; | ||
309 | |||
310 | spin_lock_irqsave(&mac->lock, flags); | ||
311 | |||
312 | if (!mac->associnfo.associating) { | ||
313 | /* we race against the timeout function, so make sure | ||
314 | * only one of us can do work */ | ||
315 | spin_unlock_irqrestore(&mac->lock, flags); | ||
316 | return 0; | ||
317 | } | ||
318 | network = ieee80211softmac_get_network_by_bssid_locked(mac, resp->header.addr3); | ||
319 | |||
320 | /* someone sending us things without us knowing him? Ignore. */ | ||
321 | if (!network) { | ||
322 | dprintk(KERN_INFO PFX "Received unrequested assocation response from " MAC_FMT "\n", MAC_ARG(resp->header.addr3)); | ||
323 | spin_unlock_irqrestore(&mac->lock, flags); | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | /* now that we know it was for us, we can cancel the timeout */ | ||
328 | cancel_delayed_work(&mac->associnfo.timeout); | ||
329 | |||
330 | switch (status) { | ||
331 | case 0: | ||
332 | dprintk(KERN_INFO PFX "associated!\n"); | ||
333 | ieee80211softmac_associated(mac, resp, network); | ||
334 | ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATED, network); | ||
335 | break; | ||
336 | case WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH: | ||
337 | if (!network->auth_desynced_once) { | ||
338 | /* there seem to be a few rare cases where our view of | ||
339 | * the world is obscured, or buggy APs that don't DEAUTH | ||
340 | * us properly. So we handle that, but allow it only once. | ||
341 | */ | ||
342 | printkl(KERN_INFO PFX "We were not authenticated during association, retrying...\n"); | ||
343 | network->authenticated = 0; | ||
344 | /* we don't want to do this more than once ... */ | ||
345 | network->auth_desynced_once = 1; | ||
346 | schedule_work(&mac->associnfo.work); | ||
347 | break; | ||
348 | } | ||
349 | default: | ||
350 | dprintk(KERN_INFO PFX "associating failed (reason: 0x%x)!\n", status); | ||
351 | mac->associnfo.associating = 0; | ||
352 | mac->associnfo.bssvalid = 0; | ||
353 | mac->associated = 0; | ||
354 | ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network); | ||
355 | } | ||
356 | |||
357 | spin_unlock_irqrestore(&mac->lock, flags); | ||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | int | ||
362 | ieee80211softmac_handle_disassoc(struct net_device * dev, | ||
363 | struct ieee80211_disassoc *disassoc) | ||
364 | { | ||
365 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
366 | unsigned long flags; | ||
367 | if (memcmp(disassoc->header.addr2, mac->associnfo.bssid, ETH_ALEN)) | ||
368 | return 0; | ||
369 | if (memcmp(disassoc->header.addr1, mac->dev->dev_addr, ETH_ALEN)) | ||
370 | return 0; | ||
371 | dprintk(KERN_INFO PFX "got disassoc frame\n"); | ||
372 | netif_carrier_off(dev); | ||
373 | spin_lock_irqsave(&mac->lock, flags); | ||
374 | mac->associnfo.bssvalid = 0; | ||
375 | mac->associated = 0; | ||
376 | schedule_work(&mac->associnfo.work); | ||
377 | spin_unlock_irqrestore(&mac->lock, flags); | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | int | ||
383 | ieee80211softmac_handle_reassoc_req(struct net_device * dev, | ||
384 | struct ieee80211_reassoc_request * resp) | ||
385 | { | ||
386 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
387 | struct ieee80211softmac_network *network; | ||
388 | |||
389 | network = ieee80211softmac_get_network_by_bssid(mac, resp->header.addr3); | ||
390 | if (!network) { | ||
391 | dprintkl(KERN_INFO PFX "reassoc request from unknown network\n"); | ||
392 | return 0; | ||
393 | } | ||
394 | ieee80211softmac_assoc(mac, network); | ||
395 | return 0; | ||
396 | } | ||
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c new file mode 100644 index 000000000000..9a0eac6c61eb --- /dev/null +++ b/net/ieee80211/softmac/ieee80211softmac_auth.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /* | ||
2 | * This file contains the softmac's authentication logic. | ||
3 | * | ||
4 | * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * Joseph Jezak <josejx@gentoo.org> | ||
6 | * Larry Finger <Larry.Finger@lwfinger.net> | ||
7 | * Danny van Dyk <kugelfang@gentoo.org> | ||
8 | * Michael Buesch <mbuesch@freenet.de> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * | ||
23 | * The full GNU General Public License is included in this distribution in the | ||
24 | * file called COPYING. | ||
25 | */ | ||
26 | |||
27 | #include "ieee80211softmac_priv.h" | ||
28 | |||
29 | static void ieee80211softmac_auth_queue(void *data); | ||
30 | |||
31 | /* Queues an auth request to the desired AP */ | ||
32 | int | ||
33 | ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, | ||
34 | struct ieee80211softmac_network *net) | ||
35 | { | ||
36 | struct ieee80211softmac_auth_queue_item *auth; | ||
37 | unsigned long flags; | ||
38 | |||
39 | if (net->authenticating) | ||
40 | return 0; | ||
41 | |||
42 | /* Add the network if it's not already added */ | ||
43 | ieee80211softmac_add_network(mac, net); | ||
44 | |||
45 | dprintk(KERN_NOTICE PFX "Queueing Authentication Request to "MAC_FMT"\n", MAC_ARG(net->bssid)); | ||
46 | /* Queue the auth request */ | ||
47 | auth = (struct ieee80211softmac_auth_queue_item *) | ||
48 | kmalloc(sizeof(struct ieee80211softmac_auth_queue_item), GFP_KERNEL); | ||
49 | if(auth == NULL) | ||
50 | return -ENOMEM; | ||
51 | |||
52 | auth->net = net; | ||
53 | auth->mac = mac; | ||
54 | auth->retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT; | ||
55 | auth->state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST; | ||
56 | INIT_WORK(&auth->work, &ieee80211softmac_auth_queue, (void *)auth); | ||
57 | |||
58 | /* Lock (for list) */ | ||
59 | spin_lock_irqsave(&mac->lock, flags); | ||
60 | |||
61 | /* add to list */ | ||
62 | list_add_tail(&auth->list, &mac->auth_queue); | ||
63 | schedule_work(&auth->work); | ||
64 | spin_unlock_irqrestore(&mac->lock, flags); | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | |||
70 | /* Sends an auth request to the desired AP and handles timeouts */ | ||
71 | static void | ||
72 | ieee80211softmac_auth_queue(void *data) | ||
73 | { | ||
74 | struct ieee80211softmac_device *mac; | ||
75 | struct ieee80211softmac_auth_queue_item *auth; | ||
76 | struct ieee80211softmac_network *net; | ||
77 | unsigned long flags; | ||
78 | |||
79 | auth = (struct ieee80211softmac_auth_queue_item *)data; | ||
80 | net = auth->net; | ||
81 | mac = auth->mac; | ||
82 | |||
83 | if(auth->retry > 0) { | ||
84 | /* Switch to correct channel for this network */ | ||
85 | mac->set_channel(mac->dev, net->channel); | ||
86 | |||
87 | /* Lock and set flags */ | ||
88 | spin_lock_irqsave(&mac->lock, flags); | ||
89 | net->authenticated = 0; | ||
90 | net->authenticating = 1; | ||
91 | /* add a timeout call so we eventually give up waiting for an auth reply */ | ||
92 | schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT); | ||
93 | auth->retry--; | ||
94 | spin_unlock_irqrestore(&mac->lock, flags); | ||
95 | if (ieee80211softmac_send_mgt_frame(mac, auth->net, IEEE80211_STYPE_AUTH, auth->state)) | ||
96 | dprintk(KERN_NOTICE PFX "Sending Authentication Request to "MAC_FMT" failed (this shouldn't happen, wait for the timeout).\n", MAC_ARG(net->bssid)); | ||
97 | else | ||
98 | dprintk(KERN_NOTICE PFX "Sent Authentication Request to "MAC_FMT".\n", MAC_ARG(net->bssid)); | ||
99 | return; | ||
100 | } | ||
101 | |||
102 | printkl(KERN_WARNING PFX "Authentication timed out with "MAC_FMT"\n", MAC_ARG(net->bssid)); | ||
103 | /* Remove this item from the queue */ | ||
104 | spin_lock_irqsave(&mac->lock, flags); | ||
105 | ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net); | ||
106 | cancel_delayed_work(&auth->work); /* just to make sure... */ | ||
107 | list_del(&auth->list); | ||
108 | spin_unlock_irqrestore(&mac->lock, flags); | ||
109 | /* Free it */ | ||
110 | kfree(auth); | ||
111 | } | ||
112 | |||
113 | /* Handle the auth response from the AP | ||
114 | * This should be registered with ieee80211 as handle_auth | ||
115 | */ | ||
116 | int | ||
117 | ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) | ||
118 | { | ||
119 | |||
120 | struct list_head *list_ptr; | ||
121 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
122 | struct ieee80211softmac_auth_queue_item *aq = NULL; | ||
123 | struct ieee80211softmac_network *net = NULL; | ||
124 | unsigned long flags; | ||
125 | u8 * data; | ||
126 | |||
127 | /* Find correct auth queue item */ | ||
128 | spin_lock_irqsave(&mac->lock, flags); | ||
129 | list_for_each(list_ptr, &mac->auth_queue) { | ||
130 | aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list); | ||
131 | net = aq->net; | ||
132 | if (!memcmp(net->bssid, auth->header.addr2, ETH_ALEN)) | ||
133 | break; | ||
134 | else | ||
135 | aq = NULL; | ||
136 | } | ||
137 | spin_unlock_irqrestore(&mac->lock, flags); | ||
138 | |||
139 | /* Make sure that we've got an auth queue item for this request */ | ||
140 | if(aq == NULL) | ||
141 | { | ||
142 | printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but no queue item exists.\n", MAC_ARG(auth->header.addr2)); | ||
143 | /* Error #? */ | ||
144 | return -1; | ||
145 | } | ||
146 | |||
147 | /* Check for out of order authentication */ | ||
148 | if(!net->authenticating) | ||
149 | { | ||
150 | printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but did not request authentication.\n",MAC_ARG(auth->header.addr2)); | ||
151 | return -1; | ||
152 | } | ||
153 | |||
154 | /* Parse the auth packet */ | ||
155 | switch(auth->algorithm) { | ||
156 | case WLAN_AUTH_OPEN: | ||
157 | /* Check the status code of the response */ | ||
158 | |||
159 | switch(auth->status) { | ||
160 | case WLAN_STATUS_SUCCESS: | ||
161 | /* Update the status to Authenticated */ | ||
162 | spin_lock_irqsave(&mac->lock, flags); | ||
163 | net->authenticating = 0; | ||
164 | net->authenticated = 1; | ||
165 | spin_unlock_irqrestore(&mac->lock, flags); | ||
166 | |||
167 | /* Send event */ | ||
168 | printkl(KERN_NOTICE PFX "Open Authentication completed with "MAC_FMT"\n", MAC_ARG(net->bssid)); | ||
169 | ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net); | ||
170 | break; | ||
171 | default: | ||
172 | /* Lock and reset flags */ | ||
173 | spin_lock_irqsave(&mac->lock, flags); | ||
174 | net->authenticated = 0; | ||
175 | net->authenticating = 0; | ||
176 | spin_unlock_irqrestore(&mac->lock, flags); | ||
177 | |||
178 | printkl(KERN_NOTICE PFX "Open Authentication with "MAC_FMT" failed, error code: %i\n", | ||
179 | MAC_ARG(net->bssid), le16_to_cpup(&auth->status)); | ||
180 | /* Count the error? */ | ||
181 | break; | ||
182 | } | ||
183 | goto free_aq; | ||
184 | break; | ||
185 | case WLAN_AUTH_SHARED_KEY: | ||
186 | /* Figure out where we are in the process */ | ||
187 | switch(auth->transaction) { | ||
188 | case IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE: | ||
189 | /* Check to make sure we have a challenge IE */ | ||
190 | data = (u8 *)auth->info_element; | ||
191 | if(*data++ != MFIE_TYPE_CHALLENGE){ | ||
192 | printkl(KERN_NOTICE PFX "Shared Key Authentication failed due to a missing challenge.\n"); | ||
193 | break; | ||
194 | } | ||
195 | /* Save the challenge */ | ||
196 | spin_lock_irqsave(&mac->lock, flags); | ||
197 | net->challenge_len = *data++; | ||
198 | if(net->challenge_len > WLAN_AUTH_CHALLENGE_LEN) | ||
199 | net->challenge_len = WLAN_AUTH_CHALLENGE_LEN; | ||
200 | if(net->challenge != NULL) | ||
201 | kfree(net->challenge); | ||
202 | net->challenge = kmalloc(net->challenge_len, GFP_ATOMIC); | ||
203 | memcpy(net->challenge, data, net->challenge_len); | ||
204 | aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE; | ||
205 | spin_unlock_irqrestore(&mac->lock, flags); | ||
206 | |||
207 | /* Switch to correct channel for this network */ | ||
208 | mac->set_channel(mac->dev, net->channel); | ||
209 | |||
210 | /* Send our response (How to encrypt?) */ | ||
211 | ieee80211softmac_send_mgt_frame(mac, aq->net, IEEE80211_STYPE_AUTH, aq->state); | ||
212 | break; | ||
213 | case IEEE80211SOFTMAC_AUTH_SHARED_PASS: | ||
214 | /* Check the status code of the response */ | ||
215 | switch(auth->status) { | ||
216 | case WLAN_STATUS_SUCCESS: | ||
217 | /* Update the status to Authenticated */ | ||
218 | spin_lock_irqsave(&mac->lock, flags); | ||
219 | net->authenticating = 0; | ||
220 | net->authenticated = 1; | ||
221 | spin_unlock_irqrestore(&mac->lock, flags); | ||
222 | printkl(KERN_NOTICE PFX "Shared Key Authentication completed with "MAC_FMT"\n", | ||
223 | MAC_ARG(net->bssid)); | ||
224 | break; | ||
225 | default: | ||
226 | printkl(KERN_NOTICE PFX "Shared Key Authentication with "MAC_FMT" failed, error code: %i\n", | ||
227 | MAC_ARG(net->bssid), le16_to_cpup(&auth->status)); | ||
228 | /* Lock and reset flags */ | ||
229 | spin_lock_irqsave(&mac->lock, flags); | ||
230 | net->authenticating = 0; | ||
231 | net->authenticated = 0; | ||
232 | spin_unlock_irqrestore(&mac->lock, flags); | ||
233 | /* Count the error? */ | ||
234 | break; | ||
235 | } | ||
236 | goto free_aq; | ||
237 | break; | ||
238 | default: | ||
239 | printkl(KERN_WARNING PFX "Unhandled Authentication Step: %i\n", auth->transaction); | ||
240 | break; | ||
241 | } | ||
242 | goto free_aq; | ||
243 | break; | ||
244 | default: | ||
245 | /* ERROR */ | ||
246 | goto free_aq; | ||
247 | break; | ||
248 | } | ||
249 | return 0; | ||
250 | free_aq: | ||
251 | /* Cancel the timeout */ | ||
252 | spin_lock_irqsave(&mac->lock, flags); | ||
253 | cancel_delayed_work(&aq->work); | ||
254 | /* Remove this item from the queue */ | ||
255 | list_del(&aq->list); | ||
256 | spin_unlock_irqrestore(&mac->lock, flags); | ||
257 | |||
258 | /* Free it */ | ||
259 | kfree(aq); | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * Handle deauthorization | ||
265 | */ | ||
266 | static void | ||
267 | ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac, | ||
268 | struct ieee80211softmac_network *net) | ||
269 | { | ||
270 | struct ieee80211softmac_auth_queue_item *aq = NULL; | ||
271 | struct list_head *list_ptr; | ||
272 | unsigned long flags; | ||
273 | |||
274 | /* Lock and reset status flags */ | ||
275 | spin_lock_irqsave(&mac->lock, flags); | ||
276 | net->authenticating = 0; | ||
277 | net->authenticated = 0; | ||
278 | |||
279 | /* Find correct auth queue item, if it exists */ | ||
280 | list_for_each(list_ptr, &mac->auth_queue) { | ||
281 | aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list); | ||
282 | if (!memcmp(net->bssid, aq->net->bssid, ETH_ALEN)) | ||
283 | break; | ||
284 | else | ||
285 | aq = NULL; | ||
286 | } | ||
287 | |||
288 | /* Cancel pending work */ | ||
289 | if(aq != NULL) | ||
290 | /* Not entirely safe? What about running work? */ | ||
291 | cancel_delayed_work(&aq->work); | ||
292 | |||
293 | /* Free our network ref */ | ||
294 | ieee80211softmac_del_network_locked(mac, net); | ||
295 | if(net->challenge != NULL) | ||
296 | kfree(net->challenge); | ||
297 | kfree(net); | ||
298 | |||
299 | /* can't transmit data right now... */ | ||
300 | netif_carrier_off(mac->dev); | ||
301 | /* let's try to re-associate */ | ||
302 | schedule_work(&mac->associnfo.work); | ||
303 | spin_unlock_irqrestore(&mac->lock, flags); | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * Sends a deauth request to the desired AP | ||
308 | */ | ||
309 | int | ||
310 | ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac, | ||
311 | struct ieee80211softmac_network *net, int reason) | ||
312 | { | ||
313 | int ret; | ||
314 | |||
315 | /* Make sure the network is authenticated */ | ||
316 | if (!net->authenticated) | ||
317 | { | ||
318 | printkl(KERN_DEBUG PFX "Can't send deauthentication packet, network is not authenticated.\n"); | ||
319 | /* Error okay? */ | ||
320 | return -EPERM; | ||
321 | } | ||
322 | |||
323 | /* Send the de-auth packet */ | ||
324 | if((ret = ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_DEAUTH, reason))) | ||
325 | return ret; | ||
326 | |||
327 | ieee80211softmac_deauth_from_net(mac, net); | ||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | /* | ||
332 | * This should be registered with ieee80211 as handle_deauth | ||
333 | */ | ||
334 | int | ||
335 | ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth) | ||
336 | { | ||
337 | |||
338 | struct ieee80211softmac_network *net = NULL; | ||
339 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
340 | |||
341 | if (!deauth) { | ||
342 | dprintk("deauth without deauth packet. eek!\n"); | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | net = ieee80211softmac_get_network_by_bssid(mac, deauth->header.addr2); | ||
347 | |||
348 | if (net == NULL) { | ||
349 | printkl(KERN_DEBUG PFX "Received deauthentication packet from "MAC_FMT", but that network is unknown.\n", | ||
350 | MAC_ARG(deauth->header.addr2)); | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | /* Make sure the network is authenticated */ | ||
355 | if(!net->authenticated) | ||
356 | { | ||
357 | printkl(KERN_DEBUG PFX "Can't perform deauthentication, network is not authenticated.\n"); | ||
358 | /* Error okay? */ | ||
359 | return -EPERM; | ||
360 | } | ||
361 | |||
362 | ieee80211softmac_deauth_from_net(mac, net); | ||
363 | return 0; | ||
364 | } | ||
diff --git a/net/ieee80211/softmac/ieee80211softmac_event.c b/net/ieee80211/softmac/ieee80211softmac_event.c new file mode 100644 index 000000000000..0a52bbda1e4c --- /dev/null +++ b/net/ieee80211/softmac/ieee80211softmac_event.c | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * Event system | ||
3 | * Also see comments in public header file and longer explanation below. | ||
4 | * | ||
5 | * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net> | ||
6 | * Joseph Jezak <josejx@gentoo.org> | ||
7 | * Larry Finger <Larry.Finger@lwfinger.net> | ||
8 | * Danny van Dyk <kugelfang@gentoo.org> | ||
9 | * Michael Buesch <mbuesch@freenet.de> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of version 2 of the GNU General Public License as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
18 | * more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
23 | * | ||
24 | * The full GNU General Public License is included in this distribution in the | ||
25 | * file called COPYING. | ||
26 | */ | ||
27 | |||
28 | #include "ieee80211softmac_priv.h" | ||
29 | |||
30 | /* | ||
31 | * Each event has associated to it | ||
32 | * - an event type (see constants in public header) | ||
33 | * - an event context (see below) | ||
34 | * - the function to be called | ||
35 | * - a context (extra parameter to call the function with) | ||
36 | * - and the softmac struct | ||
37 | * | ||
38 | * The event context is private and can only be used from | ||
39 | * within this module. Its meaning varies with the event | ||
40 | * type: | ||
41 | * SCAN_FINISHED: no special meaning | ||
42 | * ASSOCIATED, | ||
43 | * ASSOCIATE_FAILED, | ||
44 | * ASSOCIATE_TIMEOUT, | ||
45 | * AUTHENTICATED, | ||
46 | * AUTH_FAILED, | ||
47 | * AUTH_TIMEOUT: a pointer to the network struct | ||
48 | * ... | ||
49 | * Code within this module can use the event context to be only | ||
50 | * called when the event is true for that specific context | ||
51 | * as per above table. | ||
52 | * If the event context is NULL, then the notification is always called, | ||
53 | * regardless of the event context. The event context is not passed to | ||
54 | * the callback, it is assumed that the context suffices. | ||
55 | * | ||
56 | * You can also use the event context only by setting the event type | ||
57 | * to -1 (private use only), in which case you'll be notified | ||
58 | * whenever the event context matches. | ||
59 | */ | ||
60 | |||
61 | static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = { | ||
62 | "scan finished", | ||
63 | "associated", | ||
64 | "associating failed", | ||
65 | "associating timed out", | ||
66 | "authenticated", | ||
67 | "authenticating failed", | ||
68 | "authenticating timed out", | ||
69 | "associating failed because no suitable network was found", | ||
70 | }; | ||
71 | |||
72 | |||
73 | static void | ||
74 | ieee80211softmac_notify_callback(void *d) | ||
75 | { | ||
76 | struct ieee80211softmac_event event = *(struct ieee80211softmac_event*) d; | ||
77 | kfree(d); | ||
78 | |||
79 | event.fun(event.mac->dev, event.context); | ||
80 | } | ||
81 | |||
82 | int | ||
83 | ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac, | ||
84 | int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask) | ||
85 | { | ||
86 | struct ieee80211softmac_event *eventptr; | ||
87 | unsigned long flags; | ||
88 | |||
89 | if (event < -1 || event > IEEE80211SOFTMAC_EVENT_LAST) | ||
90 | return -ENOSYS; | ||
91 | |||
92 | if (!fun) | ||
93 | return -EINVAL; | ||
94 | |||
95 | eventptr = kmalloc(sizeof(struct ieee80211softmac_event), gfp_mask); | ||
96 | if (!eventptr) | ||
97 | return -ENOMEM; | ||
98 | |||
99 | eventptr->event_type = event; | ||
100 | INIT_WORK(&eventptr->work, ieee80211softmac_notify_callback, eventptr); | ||
101 | eventptr->fun = fun; | ||
102 | eventptr->context = context; | ||
103 | eventptr->mac = mac; | ||
104 | eventptr->event_context = event_context; | ||
105 | |||
106 | spin_lock_irqsave(&mac->lock, flags); | ||
107 | list_add(&eventptr->list, &mac->events); | ||
108 | spin_unlock_irqrestore(&mac->lock, flags); | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | int | ||
114 | ieee80211softmac_notify_gfp(struct net_device *dev, | ||
115 | int event, notify_function_ptr fun, void *context, gfp_t gfp_mask) | ||
116 | { | ||
117 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
118 | |||
119 | if (event < 0 || event > IEEE80211SOFTMAC_EVENT_LAST) | ||
120 | return -ENOSYS; | ||
121 | |||
122 | return ieee80211softmac_notify_internal(mac, event, NULL, fun, context, gfp_mask); | ||
123 | } | ||
124 | EXPORT_SYMBOL_GPL(ieee80211softmac_notify_gfp); | ||
125 | |||
126 | /* private -- calling all callbacks that were specified */ | ||
127 | void | ||
128 | ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx) | ||
129 | { | ||
130 | struct ieee80211softmac_event *eventptr, *tmp; | ||
131 | union iwreq_data wrqu; | ||
132 | char *msg; | ||
133 | |||
134 | if (event >= 0) { | ||
135 | msg = event_descriptions[event]; | ||
136 | wrqu.data.length = strlen(msg); | ||
137 | wireless_send_event(mac->dev, IWEVCUSTOM, &wrqu, msg); | ||
138 | } | ||
139 | |||
140 | if (!list_empty(&mac->events)) | ||
141 | list_for_each_entry_safe(eventptr, tmp, &mac->events, list) { | ||
142 | if ((eventptr->event_type == event || eventptr->event_type == -1) | ||
143 | && (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) { | ||
144 | list_del(&eventptr->list); | ||
145 | schedule_work(&eventptr->work); | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | void | ||
151 | ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_ctx) | ||
152 | { | ||
153 | unsigned long flags; | ||
154 | |||
155 | spin_lock_irqsave(&mac->lock, flags); | ||
156 | ieee80211softmac_call_events_locked(mac, event, event_ctx); | ||
157 | |||
158 | spin_unlock_irqrestore(&mac->lock, flags); | ||
159 | } | ||
diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c new file mode 100644 index 000000000000..febc51dbb412 --- /dev/null +++ b/net/ieee80211/softmac/ieee80211softmac_io.c | |||
@@ -0,0 +1,474 @@ | |||
1 | /* | ||
2 | * Some parts based on code from net80211 | ||
3 | * Copyright (c) 2001 Atsushi Onoe | ||
4 | * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Redistribution and use in source and binary forms, with or without | ||
8 | * modification, are permitted provided that the following conditions | ||
9 | * are met: | ||
10 | * 1. Redistributions of source code must retain the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer. | ||
12 | * 2. Redistributions in binary form must reproduce the above copyright | ||
13 | * notice, this list of conditions and the following disclaimer in the | ||
14 | * documentation and/or other materials provided with the distribution. | ||
15 | * 3. The name of the author may not be used to endorse or promote products | ||
16 | * derived from this software without specific prior written permission. | ||
17 | * | ||
18 | * Alternatively, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
20 | * Software Foundation. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
24 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
25 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
27 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
31 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
32 | * | ||
33 | */ | ||
34 | |||
35 | #include "ieee80211softmac_priv.h" | ||
36 | |||
37 | /* Helper functions for inserting data into the frames */ | ||
38 | |||
39 | /* | ||
40 | * Adds an ESSID element to the frame | ||
41 | * | ||
42 | */ | ||
43 | static u8 * | ||
44 | ieee80211softmac_add_essid(u8 *dst, struct ieee80211softmac_essid *essid) | ||
45 | { | ||
46 | if (essid) { | ||
47 | *dst++ = MFIE_TYPE_SSID; | ||
48 | *dst++ = essid->len; | ||
49 | memcpy(dst, essid->data, essid->len); | ||
50 | return dst+essid->len; | ||
51 | } else { | ||
52 | *dst++ = MFIE_TYPE_SSID; | ||
53 | *dst++ = 0; | ||
54 | return dst; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | /* Adds Supported Rates and if required Extended Rates Information Element | ||
59 | * to the frame, ASSUMES WE HAVE A SORTED LIST OF RATES */ | ||
60 | static u8 * | ||
61 | ieee80211softmac_frame_add_rates(u8 *dst, const struct ieee80211softmac_ratesinfo *r) | ||
62 | { | ||
63 | int cck_len, ofdm_len; | ||
64 | *dst++ = MFIE_TYPE_RATES; | ||
65 | |||
66 | for(cck_len=0; ieee80211_is_cck_rate(r->rates[cck_len]) && (cck_len < r->count);cck_len++); | ||
67 | |||
68 | if(cck_len > IEEE80211SOFTMAC_MAX_RATES_LEN) | ||
69 | cck_len = IEEE80211SOFTMAC_MAX_RATES_LEN; | ||
70 | *dst++ = cck_len; | ||
71 | memcpy(dst, r->rates, cck_len); | ||
72 | dst += cck_len; | ||
73 | |||
74 | if(cck_len < r->count){ | ||
75 | for (ofdm_len=0; ieee80211_is_ofdm_rate(r->rates[ofdm_len + cck_len]) && (ofdm_len + cck_len < r->count); ofdm_len++); | ||
76 | if (ofdm_len > 0) { | ||
77 | if (ofdm_len > IEEE80211SOFTMAC_MAX_EX_RATES_LEN) | ||
78 | ofdm_len = IEEE80211SOFTMAC_MAX_EX_RATES_LEN; | ||
79 | *dst++ = MFIE_TYPE_RATES_EX; | ||
80 | *dst++ = ofdm_len; | ||
81 | memcpy(dst, r->rates + cck_len, ofdm_len); | ||
82 | dst += ofdm_len; | ||
83 | } | ||
84 | } | ||
85 | return dst; | ||
86 | } | ||
87 | |||
88 | /* Allocate a management frame */ | ||
89 | static u8 * | ||
90 | ieee80211softmac_alloc_mgt(u32 size) | ||
91 | { | ||
92 | u8 * data; | ||
93 | |||
94 | /* Add the header and FCS to the size */ | ||
95 | size = size + IEEE80211_3ADDR_LEN; | ||
96 | if(size > IEEE80211_DATA_LEN) | ||
97 | return NULL; | ||
98 | /* Allocate the frame */ | ||
99 | data = kmalloc(size, GFP_ATOMIC); | ||
100 | memset(data, 0, size); | ||
101 | return data; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * Add a 2 Address Header | ||
106 | */ | ||
107 | static void | ||
108 | ieee80211softmac_hdr_2addr(struct ieee80211softmac_device *mac, | ||
109 | struct ieee80211_hdr_2addr *header, u32 type, u8 *dest) | ||
110 | { | ||
111 | /* Fill in the frame control flags */ | ||
112 | header->frame_ctl = cpu_to_le16(type); | ||
113 | /* Control packets always have WEP turned off */ | ||
114 | if(type > IEEE80211_STYPE_CFENDACK && type < IEEE80211_STYPE_PSPOLL) | ||
115 | header->frame_ctl |= mac->ieee->sec.level ? cpu_to_le16(IEEE80211_FCTL_PROTECTED) : 0; | ||
116 | |||
117 | /* Fill in the duration */ | ||
118 | header->duration_id = 0; | ||
119 | /* FIXME: How do I find this? | ||
120 | * calculate. But most drivers just fill in 0 (except if it's a station id of course) */ | ||
121 | |||
122 | /* Fill in the Destination Address */ | ||
123 | if(dest == NULL) | ||
124 | memset(header->addr1, 0xFF, ETH_ALEN); | ||
125 | else | ||
126 | memcpy(header->addr1, dest, ETH_ALEN); | ||
127 | /* Fill in the Source Address */ | ||
128 | memcpy(header->addr2, mac->ieee->dev->dev_addr, ETH_ALEN); | ||
129 | |||
130 | } | ||
131 | |||
132 | |||
133 | /* Add a 3 Address Header */ | ||
134 | static void | ||
135 | ieee80211softmac_hdr_3addr(struct ieee80211softmac_device *mac, | ||
136 | struct ieee80211_hdr_3addr *header, u32 type, u8 *dest, u8 *bssid) | ||
137 | { | ||
138 | /* This is common with 2addr, so use that instead */ | ||
139 | ieee80211softmac_hdr_2addr(mac, (struct ieee80211_hdr_2addr *)header, type, dest); | ||
140 | |||
141 | /* Fill in the BSS ID */ | ||
142 | if(bssid == NULL) | ||
143 | memset(header->addr3, 0xFF, ETH_ALEN); | ||
144 | else | ||
145 | memcpy(header->addr3, bssid, ETH_ALEN); | ||
146 | |||
147 | /* Fill in the sequence # */ | ||
148 | /* FIXME: I need to add this to the softmac struct | ||
149 | * shouldn't the sequence number be in ieee80211? */ | ||
150 | } | ||
151 | |||
152 | |||
153 | /***************************************************************************** | ||
154 | * Create Management packets | ||
155 | *****************************************************************************/ | ||
156 | |||
157 | /* Creates an association request packet */ | ||
158 | static u32 | ||
159 | ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt, | ||
160 | struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net) | ||
161 | { | ||
162 | u8 *data; | ||
163 | (*pkt) = (struct ieee80211_assoc_request *)ieee80211softmac_alloc_mgt( | ||
164 | 2 + /* Capability Info */ | ||
165 | 2 + /* Listen Interval */ | ||
166 | /* SSID IE */ | ||
167 | 1 + 1 + IW_ESSID_MAX_SIZE + | ||
168 | /* Rates IE */ | ||
169 | 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN + | ||
170 | /* Extended Rates IE */ | ||
171 | 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN + | ||
172 | /* WPA IE if present */ | ||
173 | mac->wpa.IElen | ||
174 | /* Other IE's? Optional? | ||
175 | * Yeah, probably need an extra IE parameter -- lots of vendors like to | ||
176 | * fill in their own IEs */ | ||
177 | ); | ||
178 | if (unlikely((*pkt) == NULL)) | ||
179 | return 0; | ||
180 | ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid); | ||
181 | |||
182 | /* Fill in capability Info */ | ||
183 | (*pkt)->capability = (mac->ieee->iw_mode == IW_MODE_MASTER) || (mac->ieee->iw_mode == IW_MODE_INFRA) ? | ||
184 | cpu_to_le16(WLAN_CAPABILITY_ESS) : | ||
185 | cpu_to_le16(WLAN_CAPABILITY_IBSS); | ||
186 | /* Need to add this | ||
187 | (*pkt)->capability |= mac->ieee->short_slot ? | ||
188 | cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0; | ||
189 | */ | ||
190 | (*pkt)->capability |= mac->ieee->sec.level ? cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0; | ||
191 | /* Fill in Listen Interval (?) */ | ||
192 | (*pkt)->listen_interval = cpu_to_le16(10); | ||
193 | |||
194 | data = (u8 *)(*pkt)->info_element; | ||
195 | /* Add SSID */ | ||
196 | data = ieee80211softmac_add_essid(data, &net->essid); | ||
197 | /* Add Rates */ | ||
198 | data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo); | ||
199 | /* Add WPA IE */ | ||
200 | if (mac->wpa.IElen && mac->wpa.IE) { | ||
201 | memcpy(data, mac->wpa.IE, mac->wpa.IElen); | ||
202 | data += mac->wpa.IElen; | ||
203 | } | ||
204 | /* Return the number of used bytes */ | ||
205 | return (data - (u8*)(*pkt)); | ||
206 | } | ||
207 | |||
208 | /* Create a reassociation request packet */ | ||
209 | static u32 | ||
210 | ieee80211softmac_reassoc_req(struct ieee80211_reassoc_request **pkt, | ||
211 | struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net) | ||
212 | { | ||
213 | u8 *data; | ||
214 | (*pkt) = (struct ieee80211_reassoc_request *)ieee80211softmac_alloc_mgt( | ||
215 | 2 + /* Capability Info */ | ||
216 | 2 + /* Listen Interval */ | ||
217 | ETH_ALEN + /* AP MAC */ | ||
218 | /* SSID IE */ | ||
219 | 1 + 1 + IW_ESSID_MAX_SIZE + | ||
220 | /* Rates IE */ | ||
221 | 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN + | ||
222 | /* Extended Rates IE */ | ||
223 | 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN | ||
224 | /* Other IE's? */ | ||
225 | ); | ||
226 | if (unlikely((*pkt) == NULL)) | ||
227 | return 0; | ||
228 | ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_REASSOC_REQ, net->bssid, net->bssid); | ||
229 | |||
230 | /* Fill in capability Info */ | ||
231 | (*pkt)->capability = mac->ieee->iw_mode == IW_MODE_MASTER ? | ||
232 | cpu_to_le16(WLAN_CAPABILITY_ESS) : | ||
233 | cpu_to_le16(WLAN_CAPABILITY_IBSS); | ||
234 | /* | ||
235 | (*pkt)->capability |= mac->ieee->short_slot ? | ||
236 | cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0; | ||
237 | */ | ||
238 | (*pkt)->capability |= mac->ieee->sec.level ? | ||
239 | cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0; | ||
240 | |||
241 | /* Fill in Listen Interval (?) */ | ||
242 | (*pkt)->listen_interval = cpu_to_le16(10); | ||
243 | /* Fill in the current AP MAC */ | ||
244 | memcpy((*pkt)->current_ap, mac->ieee->bssid, ETH_ALEN); | ||
245 | |||
246 | data = (u8 *)(*pkt)->info_element; | ||
247 | /* Add SSID */ | ||
248 | data = ieee80211softmac_add_essid(data, &net->essid); | ||
249 | /* Add Rates */ | ||
250 | data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo); | ||
251 | /* Return packet size */ | ||
252 | return (data - (u8 *)(*pkt)); | ||
253 | } | ||
254 | |||
255 | /* Create an authentication packet */ | ||
256 | static u32 | ||
257 | ieee80211softmac_auth(struct ieee80211_auth **pkt, | ||
258 | struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, | ||
259 | u16 transaction, u16 status) | ||
260 | { | ||
261 | u8 *data; | ||
262 | /* Allocate Packet */ | ||
263 | (*pkt) = (struct ieee80211_auth *)ieee80211softmac_alloc_mgt( | ||
264 | 2 + /* Auth Algorithm */ | ||
265 | 2 + /* Auth Transaction Seq */ | ||
266 | 2 + /* Status Code */ | ||
267 | /* Challenge Text IE */ | ||
268 | mac->ieee->open_wep ? 0 : | ||
269 | 1 + 1 + WLAN_AUTH_CHALLENGE_LEN | ||
270 | ); | ||
271 | if (unlikely((*pkt) == NULL)) | ||
272 | return 0; | ||
273 | ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_AUTH, net->bssid, net->bssid); | ||
274 | |||
275 | /* Algorithm */ | ||
276 | (*pkt)->algorithm = mac->ieee->open_wep ? | ||
277 | cpu_to_le16(WLAN_AUTH_OPEN) : | ||
278 | cpu_to_le16(WLAN_AUTH_SHARED_KEY); | ||
279 | /* Transaction */ | ||
280 | (*pkt)->transaction = cpu_to_le16(transaction); | ||
281 | /* Status */ | ||
282 | (*pkt)->status = cpu_to_le16(status); | ||
283 | |||
284 | data = (u8 *)(*pkt)->info_element; | ||
285 | /* Challenge Text */ | ||
286 | if(!mac->ieee->open_wep){ | ||
287 | *data = MFIE_TYPE_CHALLENGE; | ||
288 | data++; | ||
289 | |||
290 | /* Copy the challenge in */ | ||
291 | // *data = challenge length | ||
292 | // data += sizeof(u16); | ||
293 | // memcpy(data, challenge, challenge length); | ||
294 | // data += challenge length; | ||
295 | |||
296 | /* Add the full size to the packet length */ | ||
297 | } | ||
298 | |||
299 | /* Return the packet size */ | ||
300 | return (data - (u8 *)(*pkt)); | ||
301 | } | ||
302 | |||
303 | /* Create a disassocation or deauthentication packet */ | ||
304 | static u32 | ||
305 | ieee80211softmac_disassoc_deauth(struct ieee80211_disassoc **pkt, | ||
306 | struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, | ||
307 | u16 type, u16 reason) | ||
308 | { | ||
309 | /* Allocate Packet */ | ||
310 | (*pkt) = (struct ieee80211_disassoc *)ieee80211softmac_alloc_mgt(2); | ||
311 | if (unlikely((*pkt) == NULL)) | ||
312 | return 0; | ||
313 | ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), type, net->bssid, net->bssid); | ||
314 | /* Reason */ | ||
315 | (*pkt)->reason = cpu_to_le16(reason); | ||
316 | /* Return the packet size */ | ||
317 | return (2 + IEEE80211_3ADDR_LEN); | ||
318 | } | ||
319 | |||
320 | /* Create a probe request packet */ | ||
321 | static u32 | ||
322 | ieee80211softmac_probe_req(struct ieee80211_probe_request **pkt, | ||
323 | struct ieee80211softmac_device *mac, struct ieee80211softmac_essid *essid) | ||
324 | { | ||
325 | u8 *data; | ||
326 | /* Allocate Packet */ | ||
327 | (*pkt) = (struct ieee80211_probe_request *)ieee80211softmac_alloc_mgt( | ||
328 | /* SSID of requested network */ | ||
329 | 1 + 1 + IW_ESSID_MAX_SIZE + | ||
330 | /* Rates IE */ | ||
331 | 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN + | ||
332 | /* Extended Rates IE */ | ||
333 | 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN | ||
334 | ); | ||
335 | if (unlikely((*pkt) == NULL)) | ||
336 | return 0; | ||
337 | ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_REQ, NULL, NULL); | ||
338 | |||
339 | data = (u8 *)(*pkt)->info_element; | ||
340 | /* Add ESSID (can be NULL) */ | ||
341 | data = ieee80211softmac_add_essid(data, essid); | ||
342 | /* Add Rates */ | ||
343 | data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo); | ||
344 | /* Return packet size */ | ||
345 | return (data - (u8 *)(*pkt)); | ||
346 | } | ||
347 | |||
348 | /* Create a probe response packet */ | ||
349 | /* FIXME: Not complete */ | ||
350 | static u32 | ||
351 | ieee80211softmac_probe_resp(struct ieee80211_probe_response **pkt, | ||
352 | struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net) | ||
353 | { | ||
354 | u8 *data; | ||
355 | /* Allocate Packet */ | ||
356 | (*pkt) = (struct ieee80211_probe_response *)ieee80211softmac_alloc_mgt( | ||
357 | 8 + /* Timestamp */ | ||
358 | 2 + /* Beacon Interval */ | ||
359 | 2 + /* Capability Info */ | ||
360 | /* SSID IE */ | ||
361 | 1 + 1 + IW_ESSID_MAX_SIZE + | ||
362 | 7 + /* FH Parameter Set */ | ||
363 | 2 + /* DS Parameter Set */ | ||
364 | 8 + /* CF Parameter Set */ | ||
365 | 4 /* IBSS Parameter Set */ | ||
366 | ); | ||
367 | if (unlikely((*pkt) == NULL)) | ||
368 | return 0; | ||
369 | ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_RESP, net->bssid, net->bssid); | ||
370 | data = (u8 *)(*pkt)->info_element; | ||
371 | |||
372 | /* Return the packet size */ | ||
373 | return (data - (u8 *)(*pkt)); | ||
374 | } | ||
375 | |||
376 | |||
377 | /* Sends a manangement packet | ||
378 | * FIXME: document the use of the arg parameter | ||
379 | * for _AUTH: (transaction #) | (status << 16) | ||
380 | */ | ||
381 | int | ||
382 | ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac, | ||
383 | void *ptrarg, u32 type, u32 arg) | ||
384 | { | ||
385 | void *pkt = NULL; | ||
386 | u32 pkt_size = 0; | ||
387 | |||
388 | switch(type) { | ||
389 | case IEEE80211_STYPE_ASSOC_REQ: | ||
390 | pkt_size = ieee80211softmac_assoc_req((struct ieee80211_assoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg); | ||
391 | break; | ||
392 | case IEEE80211_STYPE_REASSOC_REQ: | ||
393 | pkt_size = ieee80211softmac_reassoc_req((struct ieee80211_reassoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg); | ||
394 | break; | ||
395 | case IEEE80211_STYPE_AUTH: | ||
396 | pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16)); | ||
397 | break; | ||
398 | case IEEE80211_STYPE_DISASSOC: | ||
399 | case IEEE80211_STYPE_DEAUTH: | ||
400 | pkt_size = ieee80211softmac_disassoc_deauth((struct ieee80211_disassoc **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, type, (u16)(arg & 0xFFFF)); | ||
401 | break; | ||
402 | case IEEE80211_STYPE_PROBE_REQ: | ||
403 | pkt_size = ieee80211softmac_probe_req((struct ieee80211_probe_request **)(&pkt), mac, (struct ieee80211softmac_essid *)ptrarg); | ||
404 | break; | ||
405 | case IEEE80211_STYPE_PROBE_RESP: | ||
406 | pkt_size = ieee80211softmac_probe_resp((struct ieee80211_probe_response **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg); | ||
407 | break; | ||
408 | default: | ||
409 | printkl(KERN_DEBUG PFX "Unsupported Management Frame type: %i\n", type); | ||
410 | return -EINVAL; | ||
411 | }; | ||
412 | |||
413 | if(pkt_size == 0 || pkt == NULL) { | ||
414 | printkl(KERN_DEBUG PFX "Error, packet is nonexistant or 0 length\n"); | ||
415 | return -ENOMEM; | ||
416 | } | ||
417 | |||
418 | /* Send the packet to the ieee80211 layer for tx */ | ||
419 | /* we defined softmac->mgmt_xmit for this. Should we keep it | ||
420 | * as it is (that means we'd need to wrap this into a txb), | ||
421 | * modify the prototype (so it matches this function), | ||
422 | * or get rid of it alltogether? | ||
423 | * Does this work for you now? | ||
424 | */ | ||
425 | ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt, pkt_size); | ||
426 | |||
427 | kfree(pkt); | ||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | |||
432 | /* Create an rts/cts frame */ | ||
433 | static u32 | ||
434 | ieee80211softmac_rts_cts(struct ieee80211_hdr_2addr **pkt, | ||
435 | struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, | ||
436 | u32 type) | ||
437 | { | ||
438 | /* Allocate Packet */ | ||
439 | (*pkt) = kmalloc(IEEE80211_2ADDR_LEN, GFP_ATOMIC); | ||
440 | memset(*pkt, 0, IEEE80211_2ADDR_LEN); | ||
441 | if((*pkt) == NULL) | ||
442 | return 0; | ||
443 | ieee80211softmac_hdr_2addr(mac, (*pkt), type, net->bssid); | ||
444 | return IEEE80211_2ADDR_LEN; | ||
445 | } | ||
446 | |||
447 | |||
448 | /* Sends a control packet */ | ||
449 | static int | ||
450 | ieee80211softmac_send_ctl_frame(struct ieee80211softmac_device *mac, | ||
451 | struct ieee80211softmac_network *net, u32 type, u32 arg) | ||
452 | { | ||
453 | void *pkt = NULL; | ||
454 | u32 pkt_size = 0; | ||
455 | |||
456 | switch(type) { | ||
457 | case IEEE80211_STYPE_RTS: | ||
458 | case IEEE80211_STYPE_CTS: | ||
459 | pkt_size = ieee80211softmac_rts_cts((struct ieee80211_hdr_2addr **)(&pkt), mac, net, type); | ||
460 | break; | ||
461 | default: | ||
462 | printkl(KERN_DEBUG PFX "Unsupported Control Frame type: %i\n", type); | ||
463 | return -EINVAL; | ||
464 | } | ||
465 | |||
466 | if(pkt_size == 0) | ||
467 | return -ENOMEM; | ||
468 | |||
469 | /* Send the packet to the ieee80211 layer for tx */ | ||
470 | ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *) pkt, pkt_size); | ||
471 | |||
472 | kfree(pkt); | ||
473 | return 0; | ||
474 | } | ||
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c new file mode 100644 index 000000000000..6f99f781bff8 --- /dev/null +++ b/net/ieee80211/softmac/ieee80211softmac_module.c | |||
@@ -0,0 +1,457 @@ | |||
1 | /* | ||
2 | * Contains some basic softmac functions along with module registration code etc. | ||
3 | * | ||
4 | * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * Joseph Jezak <josejx@gentoo.org> | ||
6 | * Larry Finger <Larry.Finger@lwfinger.net> | ||
7 | * Danny van Dyk <kugelfang@gentoo.org> | ||
8 | * Michael Buesch <mbuesch@freenet.de> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * | ||
23 | * The full GNU General Public License is included in this distribution in the | ||
24 | * file called COPYING. | ||
25 | */ | ||
26 | |||
27 | #include "ieee80211softmac_priv.h" | ||
28 | #include <linux/sort.h> | ||
29 | |||
30 | struct net_device *alloc_ieee80211softmac(int sizeof_priv) | ||
31 | { | ||
32 | struct ieee80211softmac_device *softmac; | ||
33 | struct net_device *dev; | ||
34 | |||
35 | dev = alloc_ieee80211(sizeof(struct ieee80211softmac_device) + sizeof_priv); | ||
36 | softmac = ieee80211_priv(dev); | ||
37 | softmac->dev = dev; | ||
38 | softmac->ieee = netdev_priv(dev); | ||
39 | spin_lock_init(&softmac->lock); | ||
40 | |||
41 | softmac->ieee->handle_auth = ieee80211softmac_auth_resp; | ||
42 | softmac->ieee->handle_deauth = ieee80211softmac_deauth_resp; | ||
43 | softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response; | ||
44 | softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req; | ||
45 | softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc; | ||
46 | softmac->scaninfo = NULL; | ||
47 | |||
48 | /* TODO: initialise all the other callbacks in the ieee struct | ||
49 | * (once they're written) | ||
50 | */ | ||
51 | |||
52 | INIT_LIST_HEAD(&softmac->auth_queue); | ||
53 | INIT_LIST_HEAD(&softmac->network_list); | ||
54 | INIT_LIST_HEAD(&softmac->events); | ||
55 | |||
56 | INIT_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work, softmac); | ||
57 | INIT_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout, softmac); | ||
58 | softmac->start_scan = ieee80211softmac_start_scan_implementation; | ||
59 | softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation; | ||
60 | softmac->stop_scan = ieee80211softmac_stop_scan_implementation; | ||
61 | |||
62 | //TODO: The mcast rate has to be assigned dynamically somewhere (in scanning, association. Not sure...) | ||
63 | // It has to be set to the highest rate all stations in the current network can handle. | ||
64 | softmac->txrates.mcast_rate = IEEE80211_CCK_RATE_1MB; | ||
65 | softmac->txrates.mcast_fallback = IEEE80211_CCK_RATE_1MB; | ||
66 | /* This is reassigned in ieee80211softmac_start to sane values. */ | ||
67 | softmac->txrates.default_rate = IEEE80211_CCK_RATE_1MB; | ||
68 | softmac->txrates.default_fallback = IEEE80211_CCK_RATE_1MB; | ||
69 | |||
70 | /* to start with, we can't send anything ... */ | ||
71 | netif_carrier_off(dev); | ||
72 | |||
73 | return dev; | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(alloc_ieee80211softmac); | ||
76 | |||
77 | /* Clears the pending work queue items, stops all scans, etc. */ | ||
78 | void | ||
79 | ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm) | ||
80 | { | ||
81 | unsigned long flags; | ||
82 | struct ieee80211softmac_event *eventptr, *eventtmp; | ||
83 | struct ieee80211softmac_auth_queue_item *authptr, *authtmp; | ||
84 | struct ieee80211softmac_network *netptr, *nettmp; | ||
85 | |||
86 | ieee80211softmac_stop_scan(sm); | ||
87 | ieee80211softmac_wait_for_scan(sm); | ||
88 | |||
89 | spin_lock_irqsave(&sm->lock, flags); | ||
90 | /* Free all pending assoc work items */ | ||
91 | cancel_delayed_work(&sm->associnfo.work); | ||
92 | |||
93 | /* Free all pending scan work items */ | ||
94 | if(sm->scaninfo != NULL) | ||
95 | cancel_delayed_work(&sm->scaninfo->softmac_scan); | ||
96 | |||
97 | /* Free all pending auth work items */ | ||
98 | list_for_each_entry(authptr, &sm->auth_queue, list) | ||
99 | cancel_delayed_work(&authptr->work); | ||
100 | |||
101 | /* delete all pending event calls and work items */ | ||
102 | list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) | ||
103 | cancel_delayed_work(&eventptr->work); | ||
104 | |||
105 | spin_unlock_irqrestore(&sm->lock, flags); | ||
106 | flush_scheduled_work(); | ||
107 | |||
108 | /* now we should be save and no longer need locking... */ | ||
109 | spin_lock_irqsave(&sm->lock, flags); | ||
110 | /* Free all pending auth work items */ | ||
111 | list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) { | ||
112 | list_del(&authptr->list); | ||
113 | kfree(authptr); | ||
114 | } | ||
115 | |||
116 | /* delete all pending event calls and work items */ | ||
117 | list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) { | ||
118 | list_del(&eventptr->list); | ||
119 | kfree(eventptr); | ||
120 | } | ||
121 | |||
122 | /* Free all networks */ | ||
123 | list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) { | ||
124 | ieee80211softmac_del_network_locked(sm, netptr); | ||
125 | if(netptr->challenge != NULL) | ||
126 | kfree(netptr->challenge); | ||
127 | kfree(netptr); | ||
128 | } | ||
129 | |||
130 | spin_unlock_irqrestore(&sm->lock, flags); | ||
131 | } | ||
132 | EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work); | ||
133 | |||
134 | void free_ieee80211softmac(struct net_device *dev) | ||
135 | { | ||
136 | struct ieee80211softmac_device *sm = ieee80211_priv(dev); | ||
137 | ieee80211softmac_clear_pending_work(sm); | ||
138 | kfree(sm->scaninfo); | ||
139 | kfree(sm->wpa.IE); | ||
140 | free_ieee80211(dev); | ||
141 | } | ||
142 | EXPORT_SYMBOL_GPL(free_ieee80211softmac); | ||
143 | |||
144 | static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac) | ||
145 | { | ||
146 | struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo; | ||
147 | /* I took out the sorting check, we're seperating by modulation now. */ | ||
148 | if (ri->count) | ||
149 | return; | ||
150 | /* otherwise assume we hav'em all! */ | ||
151 | if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) { | ||
152 | ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB; | ||
153 | ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB; | ||
154 | ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB; | ||
155 | ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB; | ||
156 | } | ||
157 | if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) { | ||
158 | ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB; | ||
159 | ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB; | ||
160 | ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB; | ||
161 | ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB; | ||
162 | ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB; | ||
163 | ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB; | ||
164 | ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB; | ||
165 | ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | void ieee80211softmac_start(struct net_device *dev) | ||
170 | { | ||
171 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
172 | struct ieee80211_device *ieee = mac->ieee; | ||
173 | u32 change = 0; | ||
174 | struct ieee80211softmac_txrates oldrates; | ||
175 | |||
176 | ieee80211softmac_start_check_rates(mac); | ||
177 | |||
178 | /* TODO: We need some kind of state machine to lower the default rates | ||
179 | * if we loose too many packets. | ||
180 | */ | ||
181 | /* Change the default txrate to the highest possible value. | ||
182 | * The txrate machine will lower it, if it is too high. | ||
183 | */ | ||
184 | if (mac->txrates_change) | ||
185 | oldrates = mac->txrates; | ||
186 | if (ieee->modulation & IEEE80211_OFDM_MODULATION) { | ||
187 | mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB; | ||
188 | change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; | ||
189 | mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB; | ||
190 | change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; | ||
191 | } else if (ieee->modulation & IEEE80211_CCK_MODULATION) { | ||
192 | mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB; | ||
193 | change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; | ||
194 | mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB; | ||
195 | change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; | ||
196 | } else | ||
197 | assert(0); | ||
198 | if (mac->txrates_change) | ||
199 | mac->txrates_change(dev, change, &oldrates); | ||
200 | } | ||
201 | EXPORT_SYMBOL_GPL(ieee80211softmac_start); | ||
202 | |||
203 | void ieee80211softmac_stop(struct net_device *dev) | ||
204 | { | ||
205 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
206 | |||
207 | ieee80211softmac_clear_pending_work(mac); | ||
208 | } | ||
209 | EXPORT_SYMBOL_GPL(ieee80211softmac_stop); | ||
210 | |||
211 | void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates) | ||
212 | { | ||
213 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
214 | unsigned long flags; | ||
215 | |||
216 | spin_lock_irqsave(&mac->lock, flags); | ||
217 | memcpy(mac->ratesinfo.rates, rates, count); | ||
218 | mac->ratesinfo.count = count; | ||
219 | spin_unlock_irqrestore(&mac->lock, flags); | ||
220 | } | ||
221 | EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates); | ||
222 | |||
223 | static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate) | ||
224 | { | ||
225 | int i; | ||
226 | struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo; | ||
227 | |||
228 | for (i=0; i<ri->count-1; i++) { | ||
229 | if (ri->rates[i] == rate) | ||
230 | return ri->rates[i+1]; | ||
231 | } | ||
232 | /* I guess we can't go any higher... */ | ||
233 | return ri->rates[ri->count]; | ||
234 | } | ||
235 | |||
236 | u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta) | ||
237 | { | ||
238 | int i; | ||
239 | struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo; | ||
240 | |||
241 | for (i=delta; i<ri->count; i++) { | ||
242 | if (ri->rates[i] == rate) | ||
243 | return ri->rates[i-delta]; | ||
244 | } | ||
245 | /* I guess we can't go any lower... */ | ||
246 | return ri->rates[0]; | ||
247 | } | ||
248 | |||
249 | static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac, | ||
250 | int amount) | ||
251 | { | ||
252 | struct ieee80211softmac_txrates oldrates; | ||
253 | u8 default_rate = mac->txrates.default_rate; | ||
254 | u8 default_fallback = mac->txrates.default_fallback; | ||
255 | u32 changes = 0; | ||
256 | |||
257 | //TODO: This is highly experimental code. | ||
258 | // Maybe the dynamic rate selection does not work | ||
259 | // and it has to be removed again. | ||
260 | |||
261 | printk("badness %d\n", mac->txrate_badness); | ||
262 | mac->txrate_badness += amount; | ||
263 | if (mac->txrate_badness <= -1000) { | ||
264 | /* Very small badness. Try a faster bitrate. */ | ||
265 | if (mac->txrates_change) | ||
266 | memcpy(&oldrates, &mac->txrates, sizeof(oldrates)); | ||
267 | default_rate = raise_rate(mac, default_rate); | ||
268 | changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; | ||
269 | default_fallback = get_fallback_rate(mac, default_rate); | ||
270 | changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; | ||
271 | mac->txrate_badness = 0; | ||
272 | printk("Bitrate raised to %u\n", default_rate); | ||
273 | } else if (mac->txrate_badness >= 10000) { | ||
274 | /* Very high badness. Try a slower bitrate. */ | ||
275 | if (mac->txrates_change) | ||
276 | memcpy(&oldrates, &mac->txrates, sizeof(oldrates)); | ||
277 | default_rate = lower_rate(mac, default_rate); | ||
278 | changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; | ||
279 | default_fallback = get_fallback_rate(mac, default_rate); | ||
280 | changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; | ||
281 | mac->txrate_badness = 0; | ||
282 | printk("Bitrate lowered to %u\n", default_rate); | ||
283 | } | ||
284 | |||
285 | mac->txrates.default_rate = default_rate; | ||
286 | mac->txrates.default_fallback = default_fallback; | ||
287 | |||
288 | if (changes && mac->txrates_change) | ||
289 | mac->txrates_change(mac->dev, changes, &oldrates); | ||
290 | } | ||
291 | |||
292 | void ieee80211softmac_fragment_lost(struct net_device *dev, | ||
293 | u16 wl_seq) | ||
294 | { | ||
295 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
296 | unsigned long flags; | ||
297 | |||
298 | spin_lock_irqsave(&mac->lock, flags); | ||
299 | ieee80211softmac_add_txrates_badness(mac, 1000); | ||
300 | //TODO | ||
301 | |||
302 | spin_unlock_irqrestore(&mac->lock, flags); | ||
303 | } | ||
304 | EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost); | ||
305 | |||
306 | static int rate_cmp(const void *a_, const void *b_) { | ||
307 | u8 *a, *b; | ||
308 | a = (u8*)a_; | ||
309 | b = (u8*)b_; | ||
310 | return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK)); | ||
311 | } | ||
312 | |||
313 | /* Allocate a softmac network struct and fill it from a network */ | ||
314 | struct ieee80211softmac_network * | ||
315 | ieee80211softmac_create_network(struct ieee80211softmac_device *mac, | ||
316 | struct ieee80211_network *net) | ||
317 | { | ||
318 | struct ieee80211softmac_network *softnet; | ||
319 | softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC); | ||
320 | if(softnet == NULL) | ||
321 | return NULL; | ||
322 | memcpy(softnet->bssid, net->bssid, ETH_ALEN); | ||
323 | softnet->channel = net->channel; | ||
324 | softnet->essid.len = net->ssid_len; | ||
325 | memcpy(softnet->essid.data, net->ssid, softnet->essid.len); | ||
326 | |||
327 | /* copy rates over */ | ||
328 | softnet->supported_rates.count = net->rates_len; | ||
329 | memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len); | ||
330 | memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len); | ||
331 | softnet->supported_rates.count += net->rates_ex_len; | ||
332 | sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL); | ||
333 | |||
334 | softnet->capabilities = net->capability; | ||
335 | return softnet; | ||
336 | } | ||
337 | |||
338 | |||
339 | /* Add a network to the list, while locked */ | ||
340 | void | ||
341 | ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac, | ||
342 | struct ieee80211softmac_network *add_net) | ||
343 | { | ||
344 | struct list_head *list_ptr; | ||
345 | struct ieee80211softmac_network *softmac_net = NULL; | ||
346 | |||
347 | list_for_each(list_ptr, &mac->network_list) { | ||
348 | softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list); | ||
349 | if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN)) | ||
350 | break; | ||
351 | else | ||
352 | softmac_net = NULL; | ||
353 | } | ||
354 | if(softmac_net == NULL) | ||
355 | list_add(&(add_net->list), &mac->network_list); | ||
356 | } | ||
357 | |||
358 | /* Add a network to the list, with locking */ | ||
359 | void | ||
360 | ieee80211softmac_add_network(struct ieee80211softmac_device *mac, | ||
361 | struct ieee80211softmac_network *add_net) | ||
362 | { | ||
363 | unsigned long flags; | ||
364 | spin_lock_irqsave(&mac->lock, flags); | ||
365 | ieee80211softmac_add_network_locked(mac, add_net); | ||
366 | spin_unlock_irqrestore(&mac->lock, flags); | ||
367 | } | ||
368 | |||
369 | |||
370 | /* Delete a network from the list, while locked*/ | ||
371 | void | ||
372 | ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac, | ||
373 | struct ieee80211softmac_network *del_net) | ||
374 | { | ||
375 | list_del(&(del_net->list)); | ||
376 | } | ||
377 | |||
378 | /* Delete a network from the list with locking */ | ||
379 | void | ||
380 | ieee80211softmac_del_network(struct ieee80211softmac_device *mac, | ||
381 | struct ieee80211softmac_network *del_net) | ||
382 | { | ||
383 | unsigned long flags; | ||
384 | spin_lock_irqsave(&mac->lock, flags); | ||
385 | ieee80211softmac_del_network_locked(mac, del_net); | ||
386 | spin_unlock_irqrestore(&mac->lock, flags); | ||
387 | } | ||
388 | |||
389 | /* Get a network from the list by MAC while locked */ | ||
390 | struct ieee80211softmac_network * | ||
391 | ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac, | ||
392 | u8 *bssid) | ||
393 | { | ||
394 | struct list_head *list_ptr; | ||
395 | struct ieee80211softmac_network *softmac_net = NULL; | ||
396 | list_for_each(list_ptr, &mac->network_list) { | ||
397 | softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list); | ||
398 | if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN)) | ||
399 | break; | ||
400 | else | ||
401 | softmac_net = NULL; | ||
402 | } | ||
403 | return softmac_net; | ||
404 | } | ||
405 | |||
406 | /* Get a network from the list by BSSID with locking */ | ||
407 | struct ieee80211softmac_network * | ||
408 | ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac, | ||
409 | u8 *bssid) | ||
410 | { | ||
411 | unsigned long flags; | ||
412 | struct ieee80211softmac_network *softmac_net; | ||
413 | |||
414 | spin_lock_irqsave(&mac->lock, flags); | ||
415 | softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid); | ||
416 | spin_unlock_irqrestore(&mac->lock, flags); | ||
417 | return softmac_net; | ||
418 | } | ||
419 | |||
420 | /* Get a network from the list by ESSID while locked */ | ||
421 | struct ieee80211softmac_network * | ||
422 | ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac, | ||
423 | struct ieee80211softmac_essid *essid) | ||
424 | { | ||
425 | struct list_head *list_ptr; | ||
426 | struct ieee80211softmac_network *softmac_net = NULL; | ||
427 | |||
428 | list_for_each(list_ptr, &mac->network_list) { | ||
429 | softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list); | ||
430 | if (softmac_net->essid.len == essid->len && | ||
431 | !memcmp(softmac_net->essid.data, essid->data, essid->len)) | ||
432 | return softmac_net; | ||
433 | } | ||
434 | return NULL; | ||
435 | } | ||
436 | |||
437 | /* Get a network from the list by ESSID with locking */ | ||
438 | struct ieee80211softmac_network * | ||
439 | ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac, | ||
440 | struct ieee80211softmac_essid *essid) | ||
441 | { | ||
442 | unsigned long flags; | ||
443 | struct ieee80211softmac_network *softmac_net = NULL; | ||
444 | |||
445 | spin_lock_irqsave(&mac->lock, flags); | ||
446 | softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid); | ||
447 | spin_unlock_irqrestore(&mac->lock, flags); | ||
448 | return softmac_net; | ||
449 | } | ||
450 | |||
451 | MODULE_LICENSE("GPL"); | ||
452 | MODULE_AUTHOR("Johannes Berg"); | ||
453 | MODULE_AUTHOR("Joseph Jezak"); | ||
454 | MODULE_AUTHOR("Larry Finger"); | ||
455 | MODULE_AUTHOR("Danny van Dyk"); | ||
456 | MODULE_AUTHOR("Michael Buesch"); | ||
457 | MODULE_DESCRIPTION("802.11 software MAC"); | ||
diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h new file mode 100644 index 000000000000..9ba7dbd161eb --- /dev/null +++ b/net/ieee80211/softmac/ieee80211softmac_priv.h | |||
@@ -0,0 +1,230 @@ | |||
1 | /* | ||
2 | * Internal softmac API definitions. | ||
3 | * | ||
4 | * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * Joseph Jezak <josejx@gentoo.org> | ||
6 | * Larry Finger <Larry.Finger@lwfinger.net> | ||
7 | * Danny van Dyk <kugelfang@gentoo.org> | ||
8 | * Michael Buesch <mbuesch@freenet.de> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * | ||
23 | * The full GNU General Public License is included in this distribution in the | ||
24 | * file called COPYING. | ||
25 | */ | ||
26 | |||
27 | #ifndef IEEE80211SOFTMAC_PRIV_H_ | ||
28 | #define IEEE80211SOFTMAC_PRIV_H_ | ||
29 | |||
30 | #include <net/ieee80211softmac.h> | ||
31 | #include <net/ieee80211softmac_wx.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/stringify.h> | ||
34 | |||
35 | |||
36 | #define PFX "SoftMAC: " | ||
37 | |||
38 | #ifdef assert | ||
39 | # undef assert | ||
40 | #endif | ||
41 | #ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG | ||
42 | #define assert(expr) \ | ||
43 | do { \ | ||
44 | if (unlikely(!(expr))) { \ | ||
45 | printkl(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", #expr, \ | ||
46 | __FILE__, __LINE__, __FUNCTION__); \ | ||
47 | } \ | ||
48 | } while (0) | ||
49 | #else | ||
50 | #define assert(expr) do {} while (0) | ||
51 | #endif | ||
52 | |||
53 | /* rate limited printk(). */ | ||
54 | #ifdef printkl | ||
55 | # undef printkl | ||
56 | #endif | ||
57 | #define printkl(f, x...) do { if (printk_ratelimit()) printk(f ,##x); } while (0) | ||
58 | /* rate limited printk() for debugging */ | ||
59 | #ifdef dprintkl | ||
60 | # undef dprintkl | ||
61 | #endif | ||
62 | #ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG | ||
63 | # define dprintkl printkl | ||
64 | #else | ||
65 | # define dprintkl(f, x...) do { /* nothing */ } while (0) | ||
66 | #endif | ||
67 | |||
68 | /* debugging printk() */ | ||
69 | #ifdef dprintk | ||
70 | # undef dprintk | ||
71 | #endif | ||
72 | #ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG | ||
73 | # define dprintk(f, x...) do { printk(f ,##x); } while (0) | ||
74 | #else | ||
75 | # define dprintk(f, x...) do { /* nothing */ } while (0) | ||
76 | #endif | ||
77 | |||
78 | /* private definitions and prototypes */ | ||
79 | |||
80 | /*** prototypes from _scan.c */ | ||
81 | void ieee80211softmac_scan(void *sm); | ||
82 | /* for internal use if scanning is needed */ | ||
83 | int ieee80211softmac_start_scan(struct ieee80211softmac_device *mac); | ||
84 | void ieee80211softmac_stop_scan(struct ieee80211softmac_device *mac); | ||
85 | void ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *mac); | ||
86 | |||
87 | /* for use by _module.c to assign to the callbacks */ | ||
88 | int ieee80211softmac_start_scan_implementation(struct net_device *dev); | ||
89 | void ieee80211softmac_stop_scan_implementation(struct net_device *dev); | ||
90 | void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev); | ||
91 | |||
92 | /*** Network prototypes from _module.c */ | ||
93 | struct ieee80211softmac_network * ieee80211softmac_create_network( | ||
94 | struct ieee80211softmac_device *mac, struct ieee80211_network *net); | ||
95 | void ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac, | ||
96 | struct ieee80211softmac_network *net); | ||
97 | void ieee80211softmac_add_network(struct ieee80211softmac_device *mac, | ||
98 | struct ieee80211softmac_network *net); | ||
99 | void ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac, | ||
100 | struct ieee80211softmac_network *net); | ||
101 | void ieee80211softmac_del_network(struct ieee80211softmac_device *mac, | ||
102 | struct ieee80211softmac_network *net); | ||
103 | struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid_locked( | ||
104 | struct ieee80211softmac_device *mac, u8 *ea); | ||
105 | struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid( | ||
106 | struct ieee80211softmac_device *mac, u8 *ea); | ||
107 | struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid_locked( | ||
108 | struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len); | ||
109 | struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid( | ||
110 | struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len); | ||
111 | struct ieee80211softmac_network * | ||
112 | ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac, | ||
113 | struct ieee80211softmac_essid *essid); | ||
114 | struct ieee80211softmac_network * | ||
115 | ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac, | ||
116 | struct ieee80211softmac_essid *essid); | ||
117 | |||
118 | /* Rates related */ | ||
119 | u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta); | ||
120 | static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) { | ||
121 | return ieee80211softmac_lower_rate_delta(mac, rate, 1); | ||
122 | } | ||
123 | |||
124 | static inline u8 get_fallback_rate(struct ieee80211softmac_device *mac, u8 rate) | ||
125 | { | ||
126 | return ieee80211softmac_lower_rate_delta(mac, rate, 2); | ||
127 | } | ||
128 | |||
129 | |||
130 | /*** prototypes from _io.c */ | ||
131 | int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac, | ||
132 | void* ptrarg, u32 type, u32 arg); | ||
133 | |||
134 | /*** prototypes from _auth.c */ | ||
135 | /* do these have to go into the public header? */ | ||
136 | int ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net); | ||
137 | int ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, int reason); | ||
138 | |||
139 | /* for use by _module.c to assign to the callbacks */ | ||
140 | int ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth); | ||
141 | int ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth); | ||
142 | |||
143 | /*** prototypes from _assoc.c */ | ||
144 | void ieee80211softmac_assoc_work(void *d); | ||
145 | int ieee80211softmac_handle_assoc_response(struct net_device * dev, | ||
146 | struct ieee80211_assoc_response * resp, | ||
147 | struct ieee80211_network * network); | ||
148 | int ieee80211softmac_handle_disassoc(struct net_device * dev, | ||
149 | struct ieee80211_disassoc * disassoc); | ||
150 | int ieee80211softmac_handle_reassoc_req(struct net_device * dev, | ||
151 | struct ieee80211_reassoc_request * reassoc); | ||
152 | void ieee80211softmac_assoc_timeout(void *d); | ||
153 | |||
154 | /* some helper functions */ | ||
155 | static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm) | ||
156 | { | ||
157 | return (sm->start_scan == ieee80211softmac_start_scan_implementation) && | ||
158 | (sm->stop_scan == ieee80211softmac_stop_scan_implementation) && | ||
159 | (sm->wait_for_scan == ieee80211softmac_wait_for_scan_implementation); | ||
160 | } | ||
161 | |||
162 | static inline int ieee80211softmac_scan_sanity_check(struct ieee80211softmac_device *sm) | ||
163 | { | ||
164 | return ((sm->start_scan != ieee80211softmac_start_scan_implementation) && | ||
165 | (sm->stop_scan != ieee80211softmac_stop_scan_implementation) && | ||
166 | (sm->wait_for_scan != ieee80211softmac_wait_for_scan_implementation) | ||
167 | ) || ieee80211softmac_scan_handlers_check_self(sm); | ||
168 | } | ||
169 | |||
170 | #define IEEE80211SOFTMAC_PROBE_DELAY HZ/2 | ||
171 | #define IEEE80211SOFTMAC_WORKQUEUE_NAME_LEN (17 + IFNAMSIZ) | ||
172 | |||
173 | struct ieee80211softmac_network { | ||
174 | struct list_head list; /* List */ | ||
175 | /* Network information copied from ieee80211_network */ | ||
176 | u8 bssid[ETH_ALEN]; | ||
177 | u8 channel; | ||
178 | struct ieee80211softmac_essid essid; | ||
179 | |||
180 | struct ieee80211softmac_ratesinfo supported_rates; | ||
181 | |||
182 | /* SoftMAC specific */ | ||
183 | u16 authenticating:1, /* Status Flags */ | ||
184 | authenticated:1, | ||
185 | auth_desynced_once:1; | ||
186 | |||
187 | u16 capabilities; /* Capabilities bitfield */ | ||
188 | u8 challenge_len; /* Auth Challenge length */ | ||
189 | char *challenge; /* Challenge Text */ | ||
190 | }; | ||
191 | |||
192 | /* structure used to keep track of networks we're auth'ing to */ | ||
193 | struct ieee80211softmac_auth_queue_item { | ||
194 | struct list_head list; /* List head */ | ||
195 | struct ieee80211softmac_network *net; /* Network to auth */ | ||
196 | struct ieee80211softmac_device *mac; /* SoftMAC device */ | ||
197 | u8 retry; /* Retry limit */ | ||
198 | u8 state; /* Auth State */ | ||
199 | struct work_struct work; /* Work queue */ | ||
200 | }; | ||
201 | |||
202 | /* scanning information */ | ||
203 | struct ieee80211softmac_scaninfo { | ||
204 | u8 current_channel_idx, | ||
205 | number_channels; | ||
206 | struct ieee80211_channel *channels; | ||
207 | u8 started:1, | ||
208 | stop:1; | ||
209 | u8 skip_flags; | ||
210 | struct completion finished; | ||
211 | struct work_struct softmac_scan; | ||
212 | }; | ||
213 | |||
214 | /* private event struct */ | ||
215 | struct ieee80211softmac_event { | ||
216 | struct list_head list; | ||
217 | int event_type; | ||
218 | void *event_context; | ||
219 | struct work_struct work; | ||
220 | notify_function_ptr fun; | ||
221 | void *context; | ||
222 | struct ieee80211softmac_device *mac; | ||
223 | }; | ||
224 | |||
225 | void ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_context); | ||
226 | void ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_context); | ||
227 | int ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac, | ||
228 | int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask); | ||
229 | |||
230 | #endif /* IEEE80211SOFTMAC_PRIV_H_ */ | ||
diff --git a/net/ieee80211/softmac/ieee80211softmac_scan.c b/net/ieee80211/softmac/ieee80211softmac_scan.c new file mode 100644 index 000000000000..bb9ab8b45d09 --- /dev/null +++ b/net/ieee80211/softmac/ieee80211softmac_scan.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* | ||
2 | * Scanning routines. | ||
3 | * | ||
4 | * These are not exported because they're assigned to the function pointers. | ||
5 | * | ||
6 | * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net> | ||
7 | * Joseph Jezak <josejx@gentoo.org> | ||
8 | * Larry Finger <Larry.Finger@lwfinger.net> | ||
9 | * Danny van Dyk <kugelfang@gentoo.org> | ||
10 | * Michael Buesch <mbuesch@freenet.de> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of version 2 of the GNU General Public License as | ||
14 | * published by the Free Software Foundation. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
17 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
19 | * more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | * The full GNU General Public License is included in this distribution in the | ||
26 | * file called COPYING. | ||
27 | */ | ||
28 | |||
29 | #include <linux/completion.h> | ||
30 | #include "ieee80211softmac_priv.h" | ||
31 | |||
32 | /* internal, use to trigger scanning if needed. | ||
33 | * Returns -EBUSY if already scanning, | ||
34 | * result of start_scan otherwise */ | ||
35 | int | ||
36 | ieee80211softmac_start_scan(struct ieee80211softmac_device *sm) | ||
37 | { | ||
38 | unsigned long flags; | ||
39 | int ret; | ||
40 | |||
41 | spin_lock_irqsave(&sm->lock, flags); | ||
42 | if (sm->scanning) | ||
43 | { | ||
44 | spin_unlock_irqrestore(&sm->lock, flags); | ||
45 | return -EINPROGRESS; | ||
46 | } | ||
47 | sm->scanning = 1; | ||
48 | spin_unlock_irqrestore(&sm->lock, flags); | ||
49 | |||
50 | ret = sm->start_scan(sm->dev); | ||
51 | if (ret) { | ||
52 | spin_lock_irqsave(&sm->lock, flags); | ||
53 | sm->scanning = 0; | ||
54 | spin_unlock_irqrestore(&sm->lock, flags); | ||
55 | } | ||
56 | return ret; | ||
57 | } | ||
58 | |||
59 | void | ||
60 | ieee80211softmac_stop_scan(struct ieee80211softmac_device *sm) | ||
61 | { | ||
62 | unsigned long flags; | ||
63 | |||
64 | spin_lock_irqsave(&sm->lock, flags); | ||
65 | |||
66 | if (!sm->scanning) { | ||
67 | spin_unlock_irqrestore(&sm->lock, flags); | ||
68 | return; | ||
69 | } | ||
70 | |||
71 | spin_unlock_irqrestore(&sm->lock, flags); | ||
72 | sm->stop_scan(sm->dev); | ||
73 | } | ||
74 | |||
75 | void | ||
76 | ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *sm) | ||
77 | { | ||
78 | unsigned long flags; | ||
79 | |||
80 | spin_lock_irqsave(&sm->lock, flags); | ||
81 | |||
82 | if (!sm->scanning) { | ||
83 | spin_unlock_irqrestore(&sm->lock, flags); | ||
84 | return; | ||
85 | } | ||
86 | |||
87 | spin_unlock_irqrestore(&sm->lock, flags); | ||
88 | sm->wait_for_scan(sm->dev); | ||
89 | } | ||
90 | |||
91 | |||
92 | /* internal scanning implementation follows */ | ||
93 | void ieee80211softmac_scan(void *d) | ||
94 | { | ||
95 | int invalid_channel; | ||
96 | u8 current_channel_idx; | ||
97 | struct ieee80211softmac_device *sm = (struct ieee80211softmac_device *)d; | ||
98 | struct ieee80211softmac_scaninfo *si = sm->scaninfo; | ||
99 | unsigned long flags; | ||
100 | |||
101 | while (!(si->stop) && (si->current_channel_idx < si->number_channels)) { | ||
102 | current_channel_idx = si->current_channel_idx; | ||
103 | si->current_channel_idx++; /* go to the next channel */ | ||
104 | |||
105 | invalid_channel = (si->skip_flags & si->channels[current_channel_idx].flags); | ||
106 | |||
107 | if (!invalid_channel) { | ||
108 | sm->set_channel(sm->dev, si->channels[current_channel_idx].channel); | ||
109 | // FIXME make this user configurable (active/passive) | ||
110 | if(ieee80211softmac_send_mgt_frame(sm, NULL, IEEE80211_STYPE_PROBE_REQ, 0)) | ||
111 | printkl(KERN_DEBUG PFX "Sending Probe Request Failed\n"); | ||
112 | |||
113 | /* also send directed management frame for the network we're looking for */ | ||
114 | // TODO: is this if correct, or should we do this only if scanning from assoc request? | ||
115 | if (sm->associnfo.req_essid.len) | ||
116 | ieee80211softmac_send_mgt_frame(sm, &sm->associnfo.req_essid, IEEE80211_STYPE_PROBE_REQ, 0); | ||
117 | schedule_delayed_work(&si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY); | ||
118 | return; | ||
119 | } else { | ||
120 | dprintk(PFX "Not probing Channel %d (not allowed here)\n", si->channels[current_channel_idx].channel); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | spin_lock_irqsave(&sm->lock, flags); | ||
125 | cancel_delayed_work(&si->softmac_scan); | ||
126 | si->started = 0; | ||
127 | spin_unlock_irqrestore(&sm->lock, flags); | ||
128 | |||
129 | dprintk(PFX "Scanning finished\n"); | ||
130 | ieee80211softmac_scan_finished(sm); | ||
131 | complete_all(&sm->scaninfo->finished); | ||
132 | } | ||
133 | |||
134 | static inline struct ieee80211softmac_scaninfo *allocate_scaninfo(struct ieee80211softmac_device *mac) | ||
135 | { | ||
136 | /* ugh. can we call this without having the spinlock held? */ | ||
137 | struct ieee80211softmac_scaninfo *info = kmalloc(sizeof(struct ieee80211softmac_scaninfo), GFP_ATOMIC); | ||
138 | if (unlikely(!info)) | ||
139 | return NULL; | ||
140 | INIT_WORK(&info->softmac_scan, ieee80211softmac_scan, mac); | ||
141 | init_completion(&info->finished); | ||
142 | return info; | ||
143 | } | ||
144 | |||
145 | int ieee80211softmac_start_scan_implementation(struct net_device *dev) | ||
146 | { | ||
147 | struct ieee80211softmac_device *sm = ieee80211_priv(dev); | ||
148 | unsigned long flags; | ||
149 | |||
150 | if (!(dev->flags & IFF_UP)) | ||
151 | return -ENODEV; | ||
152 | |||
153 | assert(ieee80211softmac_scan_handlers_check_self(sm)); | ||
154 | if (!ieee80211softmac_scan_handlers_check_self(sm)) | ||
155 | return -EINVAL; | ||
156 | |||
157 | spin_lock_irqsave(&sm->lock, flags); | ||
158 | /* it looks like we need to hold the lock here | ||
159 | * to make sure we don't allocate two of these... */ | ||
160 | if (unlikely(!sm->scaninfo)) | ||
161 | sm->scaninfo = allocate_scaninfo(sm); | ||
162 | if (unlikely(!sm->scaninfo)) { | ||
163 | spin_unlock_irqrestore(&sm->lock, flags); | ||
164 | return -ENOMEM; | ||
165 | } | ||
166 | |||
167 | sm->scaninfo->skip_flags = IEEE80211_CH_INVALID; | ||
168 | if (0 /* not scanning in IEEE802.11b */)//TODO | ||
169 | sm->scaninfo->skip_flags |= IEEE80211_CH_B_ONLY; | ||
170 | if (0 /* IEEE802.11a */) {//TODO | ||
171 | sm->scaninfo->channels = sm->ieee->geo.a; | ||
172 | sm->scaninfo->number_channels = sm->ieee->geo.a_channels; | ||
173 | } else { | ||
174 | sm->scaninfo->channels = sm->ieee->geo.bg; | ||
175 | sm->scaninfo->number_channels = sm->ieee->geo.bg_channels; | ||
176 | } | ||
177 | dprintk(PFX "Start scanning with channel: %d\n", sm->scaninfo->channels[0].channel); | ||
178 | dprintk(PFX "Scanning %d channels\n", sm->scaninfo->number_channels); | ||
179 | sm->scaninfo->current_channel_idx = 0; | ||
180 | sm->scaninfo->started = 1; | ||
181 | sm->scaninfo->stop = 0; | ||
182 | INIT_COMPLETION(sm->scaninfo->finished); | ||
183 | schedule_work(&sm->scaninfo->softmac_scan); | ||
184 | spin_unlock_irqrestore(&sm->lock, flags); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | void ieee80211softmac_stop_scan_implementation(struct net_device *dev) | ||
189 | { | ||
190 | struct ieee80211softmac_device *sm = ieee80211_priv(dev); | ||
191 | unsigned long flags; | ||
192 | |||
193 | assert(ieee80211softmac_scan_handlers_check_self(sm)); | ||
194 | if (!ieee80211softmac_scan_handlers_check_self(sm)) | ||
195 | return; | ||
196 | |||
197 | spin_lock_irqsave(&sm->lock, flags); | ||
198 | assert(sm->scaninfo != NULL); | ||
199 | if (sm->scaninfo) { | ||
200 | if (sm->scaninfo->started) | ||
201 | sm->scaninfo->stop = 1; | ||
202 | else | ||
203 | complete_all(&sm->scaninfo->finished); | ||
204 | } | ||
205 | spin_unlock_irqrestore(&sm->lock, flags); | ||
206 | } | ||
207 | |||
208 | void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev) | ||
209 | { | ||
210 | struct ieee80211softmac_device *sm = ieee80211_priv(dev); | ||
211 | unsigned long flags; | ||
212 | |||
213 | assert(ieee80211softmac_scan_handlers_check_self(sm)); | ||
214 | if (!ieee80211softmac_scan_handlers_check_self(sm)) | ||
215 | return; | ||
216 | |||
217 | spin_lock_irqsave(&sm->lock, flags); | ||
218 | if (!sm->scaninfo->started) { | ||
219 | spin_unlock_irqrestore(&sm->lock, flags); | ||
220 | return; | ||
221 | } | ||
222 | spin_unlock_irqrestore(&sm->lock, flags); | ||
223 | wait_for_completion(&sm->scaninfo->finished); | ||
224 | } | ||
225 | |||
226 | /* this is what drivers (that do scanning) call when they're done */ | ||
227 | void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm) | ||
228 | { | ||
229 | unsigned long flags; | ||
230 | |||
231 | spin_lock_irqsave(&sm->lock, flags); | ||
232 | sm->scanning = 0; | ||
233 | spin_unlock_irqrestore(&sm->lock, flags); | ||
234 | |||
235 | if (sm->associnfo.bssvalid) { | ||
236 | struct ieee80211softmac_network *net; | ||
237 | |||
238 | net = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid); | ||
239 | if (net) | ||
240 | sm->set_channel(sm->dev, net->channel); | ||
241 | } | ||
242 | ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL); | ||
243 | } | ||
244 | EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished); | ||
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c new file mode 100644 index 000000000000..e1a9bc6d36ff --- /dev/null +++ b/net/ieee80211/softmac/ieee80211softmac_wx.c | |||
@@ -0,0 +1,412 @@ | |||
1 | /* | ||
2 | * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them | ||
3 | * | ||
4 | * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * Joseph Jezak <josejx@gentoo.org> | ||
6 | * Larry Finger <Larry.Finger@lwfinger.net> | ||
7 | * Danny van Dyk <kugelfang@gentoo.org> | ||
8 | * Michael Buesch <mbuesch@freenet.de> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * | ||
23 | * The full GNU General Public License is included in this distribution in the | ||
24 | * file called COPYING. | ||
25 | */ | ||
26 | |||
27 | #include "ieee80211softmac_priv.h" | ||
28 | |||
29 | #include <net/iw_handler.h> | ||
30 | |||
31 | |||
32 | int | ||
33 | ieee80211softmac_wx_trigger_scan(struct net_device *net_dev, | ||
34 | struct iw_request_info *info, | ||
35 | union iwreq_data *data, | ||
36 | char *extra) | ||
37 | { | ||
38 | struct ieee80211softmac_device *sm = ieee80211_priv(net_dev); | ||
39 | return ieee80211softmac_start_scan(sm); | ||
40 | } | ||
41 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan); | ||
42 | |||
43 | |||
44 | int | ||
45 | ieee80211softmac_wx_get_scan_results(struct net_device *net_dev, | ||
46 | struct iw_request_info *info, | ||
47 | union iwreq_data *data, | ||
48 | char *extra) | ||
49 | { | ||
50 | struct ieee80211softmac_device *sm = ieee80211_priv(net_dev); | ||
51 | return ieee80211_wx_get_scan(sm->ieee, info, data, extra); | ||
52 | } | ||
53 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results); | ||
54 | |||
55 | int | ||
56 | ieee80211softmac_wx_set_essid(struct net_device *net_dev, | ||
57 | struct iw_request_info *info, | ||
58 | union iwreq_data *data, | ||
59 | char *extra) | ||
60 | { | ||
61 | struct ieee80211softmac_device *sm = ieee80211_priv(net_dev); | ||
62 | int length = 0; | ||
63 | unsigned long flags; | ||
64 | |||
65 | spin_lock_irqsave(&sm->lock, flags); | ||
66 | |||
67 | sm->associnfo.static_essid = 0; | ||
68 | |||
69 | if (data->essid.flags && data->essid.length && extra /*required?*/) { | ||
70 | length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE); | ||
71 | if (length) { | ||
72 | memcpy(sm->associnfo.req_essid.data, extra, length); | ||
73 | sm->associnfo.static_essid = 1; | ||
74 | } | ||
75 | } | ||
76 | sm->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT; | ||
77 | |||
78 | /* set our requested ESSID length. | ||
79 | * If applicable, we have already copied the data in */ | ||
80 | sm->associnfo.req_essid.len = length; | ||
81 | |||
82 | /* queue lower level code to do work (if necessary) */ | ||
83 | schedule_work(&sm->associnfo.work); | ||
84 | |||
85 | spin_unlock_irqrestore(&sm->lock, flags); | ||
86 | return 0; | ||
87 | } | ||
88 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid); | ||
89 | |||
90 | int | ||
91 | ieee80211softmac_wx_get_essid(struct net_device *net_dev, | ||
92 | struct iw_request_info *info, | ||
93 | union iwreq_data *data, | ||
94 | char *extra) | ||
95 | { | ||
96 | struct ieee80211softmac_device *sm = ieee80211_priv(net_dev); | ||
97 | unsigned long flags; | ||
98 | |||
99 | /* avoid getting inconsistent information */ | ||
100 | spin_lock_irqsave(&sm->lock, flags); | ||
101 | /* If all fails, return ANY (empty) */ | ||
102 | data->essid.length = 0; | ||
103 | data->essid.flags = 0; /* active */ | ||
104 | |||
105 | /* If we have a statically configured ESSID then return it */ | ||
106 | if (sm->associnfo.static_essid) { | ||
107 | data->essid.length = sm->associnfo.req_essid.len; | ||
108 | data->essid.flags = 1; /* active */ | ||
109 | memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len); | ||
110 | } | ||
111 | |||
112 | /* If we're associating/associated, return that */ | ||
113 | if (sm->associated || sm->associnfo.associating) { | ||
114 | data->essid.length = sm->associnfo.associate_essid.len; | ||
115 | data->essid.flags = 1; /* active */ | ||
116 | memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len); | ||
117 | } | ||
118 | spin_unlock_irqrestore(&sm->lock, flags); | ||
119 | return 0; | ||
120 | } | ||
121 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid); | ||
122 | |||
123 | int | ||
124 | ieee80211softmac_wx_set_rate(struct net_device *net_dev, | ||
125 | struct iw_request_info *info, | ||
126 | union iwreq_data *data, | ||
127 | char *extra) | ||
128 | { | ||
129 | struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); | ||
130 | struct ieee80211_device *ieee = mac->ieee; | ||
131 | unsigned long flags; | ||
132 | s32 in_rate = data->bitrate.value; | ||
133 | u8 rate; | ||
134 | int is_ofdm = 0; | ||
135 | int err = -EINVAL; | ||
136 | |||
137 | if (in_rate == -1) { | ||
138 | /* automatic detect */ | ||
139 | if (ieee->modulation & IEEE80211_OFDM_MODULATION) | ||
140 | in_rate = 54000000; | ||
141 | else | ||
142 | in_rate = 11000000; | ||
143 | } | ||
144 | |||
145 | switch (in_rate) { | ||
146 | case 1000000: | ||
147 | rate = IEEE80211_CCK_RATE_1MB; | ||
148 | break; | ||
149 | case 2000000: | ||
150 | rate = IEEE80211_CCK_RATE_2MB; | ||
151 | break; | ||
152 | case 5500000: | ||
153 | rate = IEEE80211_CCK_RATE_5MB; | ||
154 | break; | ||
155 | case 11000000: | ||
156 | rate = IEEE80211_CCK_RATE_11MB; | ||
157 | break; | ||
158 | case 6000000: | ||
159 | rate = IEEE80211_OFDM_RATE_6MB; | ||
160 | is_ofdm = 1; | ||
161 | break; | ||
162 | case 9000000: | ||
163 | rate = IEEE80211_OFDM_RATE_9MB; | ||
164 | is_ofdm = 1; | ||
165 | break; | ||
166 | case 12000000: | ||
167 | rate = IEEE80211_OFDM_RATE_12MB; | ||
168 | is_ofdm = 1; | ||
169 | break; | ||
170 | case 18000000: | ||
171 | rate = IEEE80211_OFDM_RATE_18MB; | ||
172 | is_ofdm = 1; | ||
173 | break; | ||
174 | case 24000000: | ||
175 | rate = IEEE80211_OFDM_RATE_24MB; | ||
176 | is_ofdm = 1; | ||
177 | break; | ||
178 | case 36000000: | ||
179 | rate = IEEE80211_OFDM_RATE_36MB; | ||
180 | is_ofdm = 1; | ||
181 | break; | ||
182 | case 48000000: | ||
183 | rate = IEEE80211_OFDM_RATE_48MB; | ||
184 | is_ofdm = 1; | ||
185 | break; | ||
186 | case 54000000: | ||
187 | rate = IEEE80211_OFDM_RATE_54MB; | ||
188 | is_ofdm = 1; | ||
189 | break; | ||
190 | default: | ||
191 | goto out; | ||
192 | } | ||
193 | |||
194 | spin_lock_irqsave(&mac->lock, flags); | ||
195 | |||
196 | /* Check if correct modulation for this PHY. */ | ||
197 | if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION)) | ||
198 | goto out_unlock; | ||
199 | |||
200 | mac->txrates.default_rate = rate; | ||
201 | mac->txrates.default_fallback = lower_rate(mac, rate); | ||
202 | err = 0; | ||
203 | |||
204 | out_unlock: | ||
205 | spin_unlock_irqrestore(&mac->lock, flags); | ||
206 | out: | ||
207 | return err; | ||
208 | } | ||
209 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate); | ||
210 | |||
211 | int | ||
212 | ieee80211softmac_wx_get_rate(struct net_device *net_dev, | ||
213 | struct iw_request_info *info, | ||
214 | union iwreq_data *data, | ||
215 | char *extra) | ||
216 | { | ||
217 | struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); | ||
218 | unsigned long flags; | ||
219 | int err = -EINVAL; | ||
220 | |||
221 | spin_lock_irqsave(&mac->lock, flags); | ||
222 | switch (mac->txrates.default_rate) { | ||
223 | case IEEE80211_CCK_RATE_1MB: | ||
224 | data->bitrate.value = 1000000; | ||
225 | break; | ||
226 | case IEEE80211_CCK_RATE_2MB: | ||
227 | data->bitrate.value = 2000000; | ||
228 | break; | ||
229 | case IEEE80211_CCK_RATE_5MB: | ||
230 | data->bitrate.value = 5500000; | ||
231 | break; | ||
232 | case IEEE80211_CCK_RATE_11MB: | ||
233 | data->bitrate.value = 11000000; | ||
234 | break; | ||
235 | case IEEE80211_OFDM_RATE_6MB: | ||
236 | data->bitrate.value = 6000000; | ||
237 | break; | ||
238 | case IEEE80211_OFDM_RATE_9MB: | ||
239 | data->bitrate.value = 9000000; | ||
240 | break; | ||
241 | case IEEE80211_OFDM_RATE_12MB: | ||
242 | data->bitrate.value = 12000000; | ||
243 | break; | ||
244 | case IEEE80211_OFDM_RATE_18MB: | ||
245 | data->bitrate.value = 18000000; | ||
246 | break; | ||
247 | case IEEE80211_OFDM_RATE_24MB: | ||
248 | data->bitrate.value = 24000000; | ||
249 | break; | ||
250 | case IEEE80211_OFDM_RATE_36MB: | ||
251 | data->bitrate.value = 36000000; | ||
252 | break; | ||
253 | case IEEE80211_OFDM_RATE_48MB: | ||
254 | data->bitrate.value = 48000000; | ||
255 | break; | ||
256 | case IEEE80211_OFDM_RATE_54MB: | ||
257 | data->bitrate.value = 54000000; | ||
258 | break; | ||
259 | default: | ||
260 | assert(0); | ||
261 | goto out_unlock; | ||
262 | } | ||
263 | err = 0; | ||
264 | out_unlock: | ||
265 | spin_unlock_irqrestore(&mac->lock, flags); | ||
266 | |||
267 | return err; | ||
268 | } | ||
269 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate); | ||
270 | |||
271 | int | ||
272 | ieee80211softmac_wx_get_wap(struct net_device *net_dev, | ||
273 | struct iw_request_info *info, | ||
274 | union iwreq_data *data, | ||
275 | char *extra) | ||
276 | { | ||
277 | struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); | ||
278 | int err = 0; | ||
279 | unsigned long flags; | ||
280 | |||
281 | spin_lock_irqsave(&mac->lock, flags); | ||
282 | if (mac->associnfo.bssvalid) | ||
283 | memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN); | ||
284 | else | ||
285 | memset(data->ap_addr.sa_data, 0xff, ETH_ALEN); | ||
286 | data->ap_addr.sa_family = ARPHRD_ETHER; | ||
287 | spin_unlock_irqrestore(&mac->lock, flags); | ||
288 | return err; | ||
289 | } | ||
290 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap); | ||
291 | |||
292 | int | ||
293 | ieee80211softmac_wx_set_wap(struct net_device *net_dev, | ||
294 | struct iw_request_info *info, | ||
295 | union iwreq_data *data, | ||
296 | char *extra) | ||
297 | { | ||
298 | struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); | ||
299 | static const unsigned char any[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | ||
300 | static const unsigned char off[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
301 | unsigned long flags; | ||
302 | |||
303 | /* sanity check */ | ||
304 | if (data->ap_addr.sa_family != ARPHRD_ETHER) { | ||
305 | return -EINVAL; | ||
306 | } | ||
307 | |||
308 | spin_lock_irqsave(&mac->lock, flags); | ||
309 | if (!memcmp(any, data->ap_addr.sa_data, ETH_ALEN) || | ||
310 | !memcmp(off, data->ap_addr.sa_data, ETH_ALEN)) { | ||
311 | schedule_work(&mac->associnfo.work); | ||
312 | goto out; | ||
313 | } else { | ||
314 | if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) { | ||
315 | if (mac->associnfo.associating || mac->associated) { | ||
316 | /* bssid unchanged and associated or associating - just return */ | ||
317 | goto out; | ||
318 | } | ||
319 | } else { | ||
320 | /* copy new value in data->ap_addr.sa_data to bssid */ | ||
321 | memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN); | ||
322 | } | ||
323 | /* queue associate if new bssid or (old one again and not associated) */ | ||
324 | schedule_work(&mac->associnfo.work); | ||
325 | } | ||
326 | |||
327 | out: | ||
328 | spin_unlock_irqrestore(&mac->lock, flags); | ||
329 | return 0; | ||
330 | } | ||
331 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap); | ||
332 | |||
333 | int | ||
334 | ieee80211softmac_wx_set_genie(struct net_device *dev, | ||
335 | struct iw_request_info *info, | ||
336 | union iwreq_data *wrqu, | ||
337 | char *extra) | ||
338 | { | ||
339 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
340 | unsigned long flags; | ||
341 | int err = 0; | ||
342 | char *buf; | ||
343 | int i; | ||
344 | |||
345 | spin_lock_irqsave(&mac->lock, flags); | ||
346 | /* bleh. shouldn't be locked for that kmalloc... */ | ||
347 | |||
348 | if (wrqu->data.length) { | ||
349 | if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) { | ||
350 | /* this is an IE, so the length must be | ||
351 | * correct. Is it possible though that | ||
352 | * more than one IE is passed in? | ||
353 | */ | ||
354 | err = -EINVAL; | ||
355 | goto out; | ||
356 | } | ||
357 | if (mac->wpa.IEbuflen <= wrqu->data.length) { | ||
358 | buf = kmalloc(wrqu->data.length, GFP_ATOMIC); | ||
359 | if (!buf) { | ||
360 | err = -ENOMEM; | ||
361 | goto out; | ||
362 | } | ||
363 | kfree(mac->wpa.IE); | ||
364 | mac->wpa.IE = buf; | ||
365 | mac->wpa.IEbuflen = wrqu->data.length; | ||
366 | } | ||
367 | memcpy(mac->wpa.IE, extra, wrqu->data.length); | ||
368 | dprintk(KERN_INFO PFX "generic IE set to "); | ||
369 | for (i=0;i<wrqu->data.length;i++) | ||
370 | dprintk("%.2x", mac->wpa.IE[i]); | ||
371 | dprintk("\n"); | ||
372 | mac->wpa.IElen = wrqu->data.length; | ||
373 | } else { | ||
374 | kfree(mac->wpa.IE); | ||
375 | mac->wpa.IE = NULL; | ||
376 | mac->wpa.IElen = 0; | ||
377 | mac->wpa.IEbuflen = 0; | ||
378 | } | ||
379 | |||
380 | out: | ||
381 | spin_unlock_irqrestore(&mac->lock, flags); | ||
382 | return err; | ||
383 | } | ||
384 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie); | ||
385 | |||
386 | int | ||
387 | ieee80211softmac_wx_get_genie(struct net_device *dev, | ||
388 | struct iw_request_info *info, | ||
389 | union iwreq_data *wrqu, | ||
390 | char *extra) | ||
391 | { | ||
392 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
393 | unsigned long flags; | ||
394 | int err = 0; | ||
395 | int space = wrqu->data.length; | ||
396 | |||
397 | spin_lock_irqsave(&mac->lock, flags); | ||
398 | |||
399 | wrqu->data.length = 0; | ||
400 | |||
401 | if (mac->wpa.IE && mac->wpa.IElen) { | ||
402 | wrqu->data.length = mac->wpa.IElen; | ||
403 | if (mac->wpa.IElen <= space) | ||
404 | memcpy(extra, mac->wpa.IE, mac->wpa.IElen); | ||
405 | else | ||
406 | err = -E2BIG; | ||
407 | } | ||
408 | spin_unlock_irqrestore(&mac->lock, flags); | ||
409 | return err; | ||
410 | } | ||
411 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie); | ||
412 | |||
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 97c276f95b35..dc206f1f914f 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -788,45 +788,53 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
788 | } | 788 | } |
789 | 789 | ||
790 | const struct proto_ops inet_stream_ops = { | 790 | const struct proto_ops inet_stream_ops = { |
791 | .family = PF_INET, | 791 | .family = PF_INET, |
792 | .owner = THIS_MODULE, | 792 | .owner = THIS_MODULE, |
793 | .release = inet_release, | 793 | .release = inet_release, |
794 | .bind = inet_bind, | 794 | .bind = inet_bind, |
795 | .connect = inet_stream_connect, | 795 | .connect = inet_stream_connect, |
796 | .socketpair = sock_no_socketpair, | 796 | .socketpair = sock_no_socketpair, |
797 | .accept = inet_accept, | 797 | .accept = inet_accept, |
798 | .getname = inet_getname, | 798 | .getname = inet_getname, |
799 | .poll = tcp_poll, | 799 | .poll = tcp_poll, |
800 | .ioctl = inet_ioctl, | 800 | .ioctl = inet_ioctl, |
801 | .listen = inet_listen, | 801 | .listen = inet_listen, |
802 | .shutdown = inet_shutdown, | 802 | .shutdown = inet_shutdown, |
803 | .setsockopt = sock_common_setsockopt, | 803 | .setsockopt = sock_common_setsockopt, |
804 | .getsockopt = sock_common_getsockopt, | 804 | .getsockopt = sock_common_getsockopt, |
805 | .sendmsg = inet_sendmsg, | 805 | .sendmsg = inet_sendmsg, |
806 | .recvmsg = sock_common_recvmsg, | 806 | .recvmsg = sock_common_recvmsg, |
807 | .mmap = sock_no_mmap, | 807 | .mmap = sock_no_mmap, |
808 | .sendpage = tcp_sendpage | 808 | .sendpage = tcp_sendpage, |
809 | #ifdef CONFIG_COMPAT | ||
810 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
811 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
812 | #endif | ||
809 | }; | 813 | }; |
810 | 814 | ||
811 | const struct proto_ops inet_dgram_ops = { | 815 | const struct proto_ops inet_dgram_ops = { |
812 | .family = PF_INET, | 816 | .family = PF_INET, |
813 | .owner = THIS_MODULE, | 817 | .owner = THIS_MODULE, |
814 | .release = inet_release, | 818 | .release = inet_release, |
815 | .bind = inet_bind, | 819 | .bind = inet_bind, |
816 | .connect = inet_dgram_connect, | 820 | .connect = inet_dgram_connect, |
817 | .socketpair = sock_no_socketpair, | 821 | .socketpair = sock_no_socketpair, |
818 | .accept = sock_no_accept, | 822 | .accept = sock_no_accept, |
819 | .getname = inet_getname, | 823 | .getname = inet_getname, |
820 | .poll = udp_poll, | 824 | .poll = udp_poll, |
821 | .ioctl = inet_ioctl, | 825 | .ioctl = inet_ioctl, |
822 | .listen = sock_no_listen, | 826 | .listen = sock_no_listen, |
823 | .shutdown = inet_shutdown, | 827 | .shutdown = inet_shutdown, |
824 | .setsockopt = sock_common_setsockopt, | 828 | .setsockopt = sock_common_setsockopt, |
825 | .getsockopt = sock_common_getsockopt, | 829 | .getsockopt = sock_common_getsockopt, |
826 | .sendmsg = inet_sendmsg, | 830 | .sendmsg = inet_sendmsg, |
827 | .recvmsg = sock_common_recvmsg, | 831 | .recvmsg = sock_common_recvmsg, |
828 | .mmap = sock_no_mmap, | 832 | .mmap = sock_no_mmap, |
829 | .sendpage = inet_sendpage, | 833 | .sendpage = inet_sendpage, |
834 | #ifdef CONFIG_COMPAT | ||
835 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
836 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
837 | #endif | ||
830 | }; | 838 | }; |
831 | 839 | ||
832 | /* | 840 | /* |
@@ -834,24 +842,28 @@ const struct proto_ops inet_dgram_ops = { | |||
834 | * udp_poll | 842 | * udp_poll |
835 | */ | 843 | */ |
836 | static const struct proto_ops inet_sockraw_ops = { | 844 | static const struct proto_ops inet_sockraw_ops = { |
837 | .family = PF_INET, | 845 | .family = PF_INET, |
838 | .owner = THIS_MODULE, | 846 | .owner = THIS_MODULE, |
839 | .release = inet_release, | 847 | .release = inet_release, |
840 | .bind = inet_bind, | 848 | .bind = inet_bind, |
841 | .connect = inet_dgram_connect, | 849 | .connect = inet_dgram_connect, |
842 | .socketpair = sock_no_socketpair, | 850 | .socketpair = sock_no_socketpair, |
843 | .accept = sock_no_accept, | 851 | .accept = sock_no_accept, |
844 | .getname = inet_getname, | 852 | .getname = inet_getname, |
845 | .poll = datagram_poll, | 853 | .poll = datagram_poll, |
846 | .ioctl = inet_ioctl, | 854 | .ioctl = inet_ioctl, |
847 | .listen = sock_no_listen, | 855 | .listen = sock_no_listen, |
848 | .shutdown = inet_shutdown, | 856 | .shutdown = inet_shutdown, |
849 | .setsockopt = sock_common_setsockopt, | 857 | .setsockopt = sock_common_setsockopt, |
850 | .getsockopt = sock_common_getsockopt, | 858 | .getsockopt = sock_common_getsockopt, |
851 | .sendmsg = inet_sendmsg, | 859 | .sendmsg = inet_sendmsg, |
852 | .recvmsg = sock_common_recvmsg, | 860 | .recvmsg = sock_common_recvmsg, |
853 | .mmap = sock_no_mmap, | 861 | .mmap = sock_no_mmap, |
854 | .sendpage = inet_sendpage, | 862 | .sendpage = inet_sendpage, |
863 | #ifdef CONFIG_COMPAT | ||
864 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
865 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
866 | #endif | ||
855 | }; | 867 | }; |
856 | 868 | ||
857 | static struct net_proto_family inet_family_ops = { | 869 | static struct net_proto_family inet_family_ops = { |
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index aed537fa2c88..e16d8b42b953 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c | |||
@@ -97,6 +97,7 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) | |||
97 | ah->reserved = 0; | 97 | ah->reserved = 0; |
98 | ah->spi = x->id.spi; | 98 | ah->spi = x->id.spi; |
99 | ah->seq_no = htonl(++x->replay.oseq); | 99 | ah->seq_no = htonl(++x->replay.oseq); |
100 | xfrm_aevent_doreplay(x); | ||
100 | ahp->icv(ahp, skb, ah->auth_data); | 101 | ahp->icv(ahp, skb, ah->auth_data); |
101 | 102 | ||
102 | top_iph->tos = iph->tos; | 103 | top_iph->tos = iph->tos; |
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index accdefedfed7..041dadde31af 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c | |||
@@ -879,16 +879,16 @@ static int arp_process(struct sk_buff *skb) | |||
879 | 879 | ||
880 | n = __neigh_lookup(&arp_tbl, &sip, dev, 0); | 880 | n = __neigh_lookup(&arp_tbl, &sip, dev, 0); |
881 | 881 | ||
882 | #ifdef CONFIG_IP_ACCEPT_UNSOLICITED_ARP | 882 | if (ipv4_devconf.arp_accept) { |
883 | /* Unsolicited ARP is not accepted by default. | 883 | /* Unsolicited ARP is not accepted by default. |
884 | It is possible, that this option should be enabled for some | 884 | It is possible, that this option should be enabled for some |
885 | devices (strip is candidate) | 885 | devices (strip is candidate) |
886 | */ | 886 | */ |
887 | if (n == NULL && | 887 | if (n == NULL && |
888 | arp->ar_op == htons(ARPOP_REPLY) && | 888 | arp->ar_op == htons(ARPOP_REPLY) && |
889 | inet_addr_type(sip) == RTN_UNICAST) | 889 | inet_addr_type(sip) == RTN_UNICAST) |
890 | n = __neigh_lookup(&arp_tbl, &sip, dev, -1); | 890 | n = __neigh_lookup(&arp_tbl, &sip, dev, -1); |
891 | #endif | 891 | } |
892 | 892 | ||
893 | if (n) { | 893 | if (n) { |
894 | int state = NUD_REACHABLE; | 894 | int state = NUD_REACHABLE; |
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 3ffa60dadc0c..44fdf1413e2c 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -1394,6 +1394,14 @@ static struct devinet_sysctl_table { | |||
1394 | .proc_handler = &proc_dointvec, | 1394 | .proc_handler = &proc_dointvec, |
1395 | }, | 1395 | }, |
1396 | { | 1396 | { |
1397 | .ctl_name = NET_IPV4_CONF_ARP_ACCEPT, | ||
1398 | .procname = "arp_accept", | ||
1399 | .data = &ipv4_devconf.arp_accept, | ||
1400 | .maxlen = sizeof(int), | ||
1401 | .mode = 0644, | ||
1402 | .proc_handler = &proc_dointvec, | ||
1403 | }, | ||
1404 | { | ||
1397 | .ctl_name = NET_IPV4_CONF_NOXFRM, | 1405 | .ctl_name = NET_IPV4_CONF_NOXFRM, |
1398 | .procname = "disable_xfrm", | 1406 | .procname = "disable_xfrm", |
1399 | .data = &ipv4_devconf.no_xfrm, | 1407 | .data = &ipv4_devconf.no_xfrm, |
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 09590f356086..bf88c620a954 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c | |||
@@ -90,6 +90,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) | |||
90 | 90 | ||
91 | esph->spi = x->id.spi; | 91 | esph->spi = x->id.spi; |
92 | esph->seq_no = htonl(++x->replay.oseq); | 92 | esph->seq_no = htonl(++x->replay.oseq); |
93 | xfrm_aevent_doreplay(x); | ||
93 | 94 | ||
94 | if (esp->conf.ivlen) | 95 | if (esp->conf.ivlen) |
95 | crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); | 96 | crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); |
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 0dd4d06e456d..ec566f3e66c7 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c | |||
@@ -40,6 +40,8 @@ | |||
40 | #include <linux/skbuff.h> | 40 | #include <linux/skbuff.h> |
41 | #include <linux/netlink.h> | 41 | #include <linux/netlink.h> |
42 | #include <linux/init.h> | 42 | #include <linux/init.h> |
43 | #include <linux/list.h> | ||
44 | #include <linux/rcupdate.h> | ||
43 | 45 | ||
44 | #include <net/ip.h> | 46 | #include <net/ip.h> |
45 | #include <net/protocol.h> | 47 | #include <net/protocol.h> |
@@ -52,7 +54,7 @@ | |||
52 | 54 | ||
53 | struct fib_rule | 55 | struct fib_rule |
54 | { | 56 | { |
55 | struct fib_rule *r_next; | 57 | struct hlist_node hlist; |
56 | atomic_t r_clntref; | 58 | atomic_t r_clntref; |
57 | u32 r_preference; | 59 | u32 r_preference; |
58 | unsigned char r_table; | 60 | unsigned char r_table; |
@@ -75,6 +77,7 @@ struct fib_rule | |||
75 | #endif | 77 | #endif |
76 | char r_ifname[IFNAMSIZ]; | 78 | char r_ifname[IFNAMSIZ]; |
77 | int r_dead; | 79 | int r_dead; |
80 | struct rcu_head rcu; | ||
78 | }; | 81 | }; |
79 | 82 | ||
80 | static struct fib_rule default_rule = { | 83 | static struct fib_rule default_rule = { |
@@ -85,7 +88,6 @@ static struct fib_rule default_rule = { | |||
85 | }; | 88 | }; |
86 | 89 | ||
87 | static struct fib_rule main_rule = { | 90 | static struct fib_rule main_rule = { |
88 | .r_next = &default_rule, | ||
89 | .r_clntref = ATOMIC_INIT(2), | 91 | .r_clntref = ATOMIC_INIT(2), |
90 | .r_preference = 0x7FFE, | 92 | .r_preference = 0x7FFE, |
91 | .r_table = RT_TABLE_MAIN, | 93 | .r_table = RT_TABLE_MAIN, |
@@ -93,23 +95,26 @@ static struct fib_rule main_rule = { | |||
93 | }; | 95 | }; |
94 | 96 | ||
95 | static struct fib_rule local_rule = { | 97 | static struct fib_rule local_rule = { |
96 | .r_next = &main_rule, | ||
97 | .r_clntref = ATOMIC_INIT(2), | 98 | .r_clntref = ATOMIC_INIT(2), |
98 | .r_table = RT_TABLE_LOCAL, | 99 | .r_table = RT_TABLE_LOCAL, |
99 | .r_action = RTN_UNICAST, | 100 | .r_action = RTN_UNICAST, |
100 | }; | 101 | }; |
101 | 102 | ||
102 | static struct fib_rule *fib_rules = &local_rule; | 103 | static struct hlist_head fib_rules; |
103 | static DEFINE_RWLOCK(fib_rules_lock); | 104 | |
105 | /* writer func called from netlink -- rtnl_sem hold*/ | ||
106 | |||
107 | static void rtmsg_rule(int, struct fib_rule *); | ||
104 | 108 | ||
105 | int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 109 | int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
106 | { | 110 | { |
107 | struct rtattr **rta = arg; | 111 | struct rtattr **rta = arg; |
108 | struct rtmsg *rtm = NLMSG_DATA(nlh); | 112 | struct rtmsg *rtm = NLMSG_DATA(nlh); |
109 | struct fib_rule *r, **rp; | 113 | struct fib_rule *r; |
114 | struct hlist_node *node; | ||
110 | int err = -ESRCH; | 115 | int err = -ESRCH; |
111 | 116 | ||
112 | for (rp=&fib_rules; (r=*rp) != NULL; rp=&r->r_next) { | 117 | hlist_for_each_entry(r, node, &fib_rules, hlist) { |
113 | if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) && | 118 | if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) && |
114 | rtm->rtm_src_len == r->r_src_len && | 119 | rtm->rtm_src_len == r->r_src_len && |
115 | rtm->rtm_dst_len == r->r_dst_len && | 120 | rtm->rtm_dst_len == r->r_dst_len && |
@@ -126,10 +131,9 @@ int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
126 | if (r == &local_rule) | 131 | if (r == &local_rule) |
127 | break; | 132 | break; |
128 | 133 | ||
129 | write_lock_bh(&fib_rules_lock); | 134 | hlist_del_rcu(&r->hlist); |
130 | *rp = r->r_next; | ||
131 | r->r_dead = 1; | 135 | r->r_dead = 1; |
132 | write_unlock_bh(&fib_rules_lock); | 136 | rtmsg_rule(RTM_DELRULE, r); |
133 | fib_rule_put(r); | 137 | fib_rule_put(r); |
134 | err = 0; | 138 | err = 0; |
135 | break; | 139 | break; |
@@ -150,21 +154,30 @@ static struct fib_table *fib_empty_table(void) | |||
150 | return NULL; | 154 | return NULL; |
151 | } | 155 | } |
152 | 156 | ||
157 | static inline void fib_rule_put_rcu(struct rcu_head *head) | ||
158 | { | ||
159 | struct fib_rule *r = container_of(head, struct fib_rule, rcu); | ||
160 | kfree(r); | ||
161 | } | ||
162 | |||
153 | void fib_rule_put(struct fib_rule *r) | 163 | void fib_rule_put(struct fib_rule *r) |
154 | { | 164 | { |
155 | if (atomic_dec_and_test(&r->r_clntref)) { | 165 | if (atomic_dec_and_test(&r->r_clntref)) { |
156 | if (r->r_dead) | 166 | if (r->r_dead) |
157 | kfree(r); | 167 | call_rcu(&r->rcu, fib_rule_put_rcu); |
158 | else | 168 | else |
159 | printk("Freeing alive rule %p\n", r); | 169 | printk("Freeing alive rule %p\n", r); |
160 | } | 170 | } |
161 | } | 171 | } |
162 | 172 | ||
173 | /* writer func called from netlink -- rtnl_sem hold*/ | ||
174 | |||
163 | int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 175 | int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) |
164 | { | 176 | { |
165 | struct rtattr **rta = arg; | 177 | struct rtattr **rta = arg; |
166 | struct rtmsg *rtm = NLMSG_DATA(nlh); | 178 | struct rtmsg *rtm = NLMSG_DATA(nlh); |
167 | struct fib_rule *r, *new_r, **rp; | 179 | struct fib_rule *r, *new_r, *last = NULL; |
180 | struct hlist_node *node = NULL; | ||
168 | unsigned char table_id; | 181 | unsigned char table_id; |
169 | 182 | ||
170 | if (rtm->rtm_src_len > 32 || rtm->rtm_dst_len > 32 || | 183 | if (rtm->rtm_src_len > 32 || rtm->rtm_dst_len > 32 || |
@@ -188,6 +201,7 @@ int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
188 | if (!new_r) | 201 | if (!new_r) |
189 | return -ENOMEM; | 202 | return -ENOMEM; |
190 | memset(new_r, 0, sizeof(*new_r)); | 203 | memset(new_r, 0, sizeof(*new_r)); |
204 | |||
191 | if (rta[RTA_SRC-1]) | 205 | if (rta[RTA_SRC-1]) |
192 | memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 4); | 206 | memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 4); |
193 | if (rta[RTA_DST-1]) | 207 | if (rta[RTA_DST-1]) |
@@ -220,28 +234,29 @@ int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
220 | if (rta[RTA_FLOW-1]) | 234 | if (rta[RTA_FLOW-1]) |
221 | memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4); | 235 | memcpy(&new_r->r_tclassid, RTA_DATA(rta[RTA_FLOW-1]), 4); |
222 | #endif | 236 | #endif |
237 | r = container_of(fib_rules.first, struct fib_rule, hlist); | ||
223 | 238 | ||
224 | rp = &fib_rules; | ||
225 | if (!new_r->r_preference) { | 239 | if (!new_r->r_preference) { |
226 | r = fib_rules; | 240 | if (r && r->hlist.next != NULL) { |
227 | if (r && (r = r->r_next) != NULL) { | 241 | r = container_of(r->hlist.next, struct fib_rule, hlist); |
228 | rp = &fib_rules->r_next; | ||
229 | if (r->r_preference) | 242 | if (r->r_preference) |
230 | new_r->r_preference = r->r_preference - 1; | 243 | new_r->r_preference = r->r_preference - 1; |
231 | } | 244 | } |
232 | } | 245 | } |
233 | 246 | ||
234 | while ( (r = *rp) != NULL ) { | 247 | hlist_for_each_entry(r, node, &fib_rules, hlist) { |
235 | if (r->r_preference > new_r->r_preference) | 248 | if (r->r_preference > new_r->r_preference) |
236 | break; | 249 | break; |
237 | rp = &r->r_next; | 250 | last = r; |
238 | } | 251 | } |
239 | |||
240 | new_r->r_next = r; | ||
241 | atomic_inc(&new_r->r_clntref); | 252 | atomic_inc(&new_r->r_clntref); |
242 | write_lock_bh(&fib_rules_lock); | 253 | |
243 | *rp = new_r; | 254 | if (last) |
244 | write_unlock_bh(&fib_rules_lock); | 255 | hlist_add_after_rcu(&last->hlist, &new_r->hlist); |
256 | else | ||
257 | hlist_add_before_rcu(&new_r->hlist, &r->hlist); | ||
258 | |||
259 | rtmsg_rule(RTM_NEWRULE, new_r); | ||
245 | return 0; | 260 | return 0; |
246 | } | 261 | } |
247 | 262 | ||
@@ -254,30 +269,30 @@ u32 fib_rules_tclass(struct fib_result *res) | |||
254 | } | 269 | } |
255 | #endif | 270 | #endif |
256 | 271 | ||
272 | /* callers should hold rtnl semaphore */ | ||
257 | 273 | ||
258 | static void fib_rules_detach(struct net_device *dev) | 274 | static void fib_rules_detach(struct net_device *dev) |
259 | { | 275 | { |
276 | struct hlist_node *node; | ||
260 | struct fib_rule *r; | 277 | struct fib_rule *r; |
261 | 278 | ||
262 | for (r=fib_rules; r; r=r->r_next) { | 279 | hlist_for_each_entry(r, node, &fib_rules, hlist) { |
263 | if (r->r_ifindex == dev->ifindex) { | 280 | if (r->r_ifindex == dev->ifindex) |
264 | write_lock_bh(&fib_rules_lock); | ||
265 | r->r_ifindex = -1; | 281 | r->r_ifindex = -1; |
266 | write_unlock_bh(&fib_rules_lock); | 282 | |
267 | } | ||
268 | } | 283 | } |
269 | } | 284 | } |
270 | 285 | ||
286 | /* callers should hold rtnl semaphore */ | ||
287 | |||
271 | static void fib_rules_attach(struct net_device *dev) | 288 | static void fib_rules_attach(struct net_device *dev) |
272 | { | 289 | { |
290 | struct hlist_node *node; | ||
273 | struct fib_rule *r; | 291 | struct fib_rule *r; |
274 | 292 | ||
275 | for (r=fib_rules; r; r=r->r_next) { | 293 | hlist_for_each_entry(r, node, &fib_rules, hlist) { |
276 | if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) { | 294 | if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) |
277 | write_lock_bh(&fib_rules_lock); | ||
278 | r->r_ifindex = dev->ifindex; | 295 | r->r_ifindex = dev->ifindex; |
279 | write_unlock_bh(&fib_rules_lock); | ||
280 | } | ||
281 | } | 296 | } |
282 | } | 297 | } |
283 | 298 | ||
@@ -286,14 +301,17 @@ int fib_lookup(const struct flowi *flp, struct fib_result *res) | |||
286 | int err; | 301 | int err; |
287 | struct fib_rule *r, *policy; | 302 | struct fib_rule *r, *policy; |
288 | struct fib_table *tb; | 303 | struct fib_table *tb; |
304 | struct hlist_node *node; | ||
289 | 305 | ||
290 | u32 daddr = flp->fl4_dst; | 306 | u32 daddr = flp->fl4_dst; |
291 | u32 saddr = flp->fl4_src; | 307 | u32 saddr = flp->fl4_src; |
292 | 308 | ||
293 | FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ", | 309 | FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ", |
294 | NIPQUAD(flp->fl4_dst), NIPQUAD(flp->fl4_src)); | 310 | NIPQUAD(flp->fl4_dst), NIPQUAD(flp->fl4_src)); |
295 | read_lock(&fib_rules_lock); | 311 | |
296 | for (r = fib_rules; r; r=r->r_next) { | 312 | rcu_read_lock(); |
313 | |||
314 | hlist_for_each_entry_rcu(r, node, &fib_rules, hlist) { | ||
297 | if (((saddr^r->r_src) & r->r_srcmask) || | 315 | if (((saddr^r->r_src) & r->r_srcmask) || |
298 | ((daddr^r->r_dst) & r->r_dstmask) || | 316 | ((daddr^r->r_dst) & r->r_dstmask) || |
299 | (r->r_tos && r->r_tos != flp->fl4_tos) || | 317 | (r->r_tos && r->r_tos != flp->fl4_tos) || |
@@ -309,14 +327,14 @@ FRprintk("tb %d r %d ", r->r_table, r->r_action); | |||
309 | policy = r; | 327 | policy = r; |
310 | break; | 328 | break; |
311 | case RTN_UNREACHABLE: | 329 | case RTN_UNREACHABLE: |
312 | read_unlock(&fib_rules_lock); | 330 | rcu_read_unlock(); |
313 | return -ENETUNREACH; | 331 | return -ENETUNREACH; |
314 | default: | 332 | default: |
315 | case RTN_BLACKHOLE: | 333 | case RTN_BLACKHOLE: |
316 | read_unlock(&fib_rules_lock); | 334 | rcu_read_unlock(); |
317 | return -EINVAL; | 335 | return -EINVAL; |
318 | case RTN_PROHIBIT: | 336 | case RTN_PROHIBIT: |
319 | read_unlock(&fib_rules_lock); | 337 | rcu_read_unlock(); |
320 | return -EACCES; | 338 | return -EACCES; |
321 | } | 339 | } |
322 | 340 | ||
@@ -327,16 +345,16 @@ FRprintk("tb %d r %d ", r->r_table, r->r_action); | |||
327 | res->r = policy; | 345 | res->r = policy; |
328 | if (policy) | 346 | if (policy) |
329 | atomic_inc(&policy->r_clntref); | 347 | atomic_inc(&policy->r_clntref); |
330 | read_unlock(&fib_rules_lock); | 348 | rcu_read_unlock(); |
331 | return 0; | 349 | return 0; |
332 | } | 350 | } |
333 | if (err < 0 && err != -EAGAIN) { | 351 | if (err < 0 && err != -EAGAIN) { |
334 | read_unlock(&fib_rules_lock); | 352 | rcu_read_unlock(); |
335 | return err; | 353 | return err; |
336 | } | 354 | } |
337 | } | 355 | } |
338 | FRprintk("FAILURE\n"); | 356 | FRprintk("FAILURE\n"); |
339 | read_unlock(&fib_rules_lock); | 357 | rcu_read_unlock(); |
340 | return -ENETUNREACH; | 358 | return -ENETUNREACH; |
341 | } | 359 | } |
342 | 360 | ||
@@ -368,14 +386,14 @@ static struct notifier_block fib_rules_notifier = { | |||
368 | 386 | ||
369 | static __inline__ int inet_fill_rule(struct sk_buff *skb, | 387 | static __inline__ int inet_fill_rule(struct sk_buff *skb, |
370 | struct fib_rule *r, | 388 | struct fib_rule *r, |
371 | struct netlink_callback *cb, | 389 | u32 pid, u32 seq, int event, |
372 | unsigned int flags) | 390 | unsigned int flags) |
373 | { | 391 | { |
374 | struct rtmsg *rtm; | 392 | struct rtmsg *rtm; |
375 | struct nlmsghdr *nlh; | 393 | struct nlmsghdr *nlh; |
376 | unsigned char *b = skb->tail; | 394 | unsigned char *b = skb->tail; |
377 | 395 | ||
378 | nlh = NLMSG_NEW_ANSWER(skb, cb, RTM_NEWRULE, sizeof(*rtm), flags); | 396 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*rtm), flags); |
379 | rtm = NLMSG_DATA(nlh); | 397 | rtm = NLMSG_DATA(nlh); |
380 | rtm->rtm_family = AF_INET; | 398 | rtm->rtm_family = AF_INET; |
381 | rtm->rtm_dst_len = r->r_dst_len; | 399 | rtm->rtm_dst_len = r->r_dst_len; |
@@ -414,20 +432,42 @@ rtattr_failure: | |||
414 | return -1; | 432 | return -1; |
415 | } | 433 | } |
416 | 434 | ||
435 | /* callers should hold rtnl semaphore */ | ||
436 | |||
437 | static void rtmsg_rule(int event, struct fib_rule *r) | ||
438 | { | ||
439 | int size = NLMSG_SPACE(sizeof(struct rtmsg) + 128); | ||
440 | struct sk_buff *skb = alloc_skb(size, GFP_KERNEL); | ||
441 | |||
442 | if (!skb) | ||
443 | netlink_set_err(rtnl, 0, RTNLGRP_IPV4_RULE, ENOBUFS); | ||
444 | else if (inet_fill_rule(skb, r, 0, 0, event, 0) < 0) { | ||
445 | kfree_skb(skb); | ||
446 | netlink_set_err(rtnl, 0, RTNLGRP_IPV4_RULE, EINVAL); | ||
447 | } else { | ||
448 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_IPV4_RULE, GFP_KERNEL); | ||
449 | } | ||
450 | } | ||
451 | |||
417 | int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) | 452 | int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) |
418 | { | 453 | { |
419 | int idx; | 454 | int idx = 0; |
420 | int s_idx = cb->args[0]; | 455 | int s_idx = cb->args[0]; |
421 | struct fib_rule *r; | 456 | struct fib_rule *r; |
457 | struct hlist_node *node; | ||
458 | |||
459 | rcu_read_lock(); | ||
460 | hlist_for_each_entry(r, node, &fib_rules, hlist) { | ||
422 | 461 | ||
423 | read_lock(&fib_rules_lock); | ||
424 | for (r=fib_rules, idx=0; r; r = r->r_next, idx++) { | ||
425 | if (idx < s_idx) | 462 | if (idx < s_idx) |
426 | continue; | 463 | continue; |
427 | if (inet_fill_rule(skb, r, cb, NLM_F_MULTI) < 0) | 464 | if (inet_fill_rule(skb, r, NETLINK_CB(cb->skb).pid, |
465 | cb->nlh->nlmsg_seq, | ||
466 | RTM_NEWRULE, NLM_F_MULTI) < 0) | ||
428 | break; | 467 | break; |
468 | idx++; | ||
429 | } | 469 | } |
430 | read_unlock(&fib_rules_lock); | 470 | rcu_read_unlock(); |
431 | cb->args[0] = idx; | 471 | cb->args[0] = idx; |
432 | 472 | ||
433 | return skb->len; | 473 | return skb->len; |
@@ -435,5 +475,9 @@ int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) | |||
435 | 475 | ||
436 | void __init fib_rules_init(void) | 476 | void __init fib_rules_init(void) |
437 | { | 477 | { |
478 | INIT_HLIST_HEAD(&fib_rules); | ||
479 | hlist_add_head(&local_rule.hlist, &fib_rules); | ||
480 | hlist_add_after(&local_rule.hlist, &main_rule.hlist); | ||
481 | hlist_add_after(&main_rule.hlist, &default_rule.hlist); | ||
438 | register_netdevice_notifier(&fib_rules_notifier); | 482 | register_netdevice_notifier(&fib_rules_notifier); |
439 | } | 483 | } |
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index e320b32373e5..ccd3efc6a173 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -50,7 +50,7 @@ | |||
50 | * Patrick McHardy <kaber@trash.net> | 50 | * Patrick McHardy <kaber@trash.net> |
51 | */ | 51 | */ |
52 | 52 | ||
53 | #define VERSION "0.404" | 53 | #define VERSION "0.406" |
54 | 54 | ||
55 | #include <linux/config.h> | 55 | #include <linux/config.h> |
56 | #include <asm/uaccess.h> | 56 | #include <asm/uaccess.h> |
@@ -84,7 +84,7 @@ | |||
84 | #include "fib_lookup.h" | 84 | #include "fib_lookup.h" |
85 | 85 | ||
86 | #undef CONFIG_IP_FIB_TRIE_STATS | 86 | #undef CONFIG_IP_FIB_TRIE_STATS |
87 | #define MAX_CHILDS 16384 | 87 | #define MAX_STAT_DEPTH 32 |
88 | 88 | ||
89 | #define KEYLENGTH (8*sizeof(t_key)) | 89 | #define KEYLENGTH (8*sizeof(t_key)) |
90 | #define MASK_PFX(k, l) (((l)==0)?0:(k >> (KEYLENGTH-l)) << (KEYLENGTH-l)) | 90 | #define MASK_PFX(k, l) (((l)==0)?0:(k >> (KEYLENGTH-l)) << (KEYLENGTH-l)) |
@@ -154,7 +154,7 @@ struct trie_stat { | |||
154 | unsigned int tnodes; | 154 | unsigned int tnodes; |
155 | unsigned int leaves; | 155 | unsigned int leaves; |
156 | unsigned int nullpointers; | 156 | unsigned int nullpointers; |
157 | unsigned int nodesizes[MAX_CHILDS]; | 157 | unsigned int nodesizes[MAX_STAT_DEPTH]; |
158 | }; | 158 | }; |
159 | 159 | ||
160 | struct trie { | 160 | struct trie { |
@@ -2040,7 +2040,15 @@ rescan: | |||
2040 | static struct node *fib_trie_get_first(struct fib_trie_iter *iter, | 2040 | static struct node *fib_trie_get_first(struct fib_trie_iter *iter, |
2041 | struct trie *t) | 2041 | struct trie *t) |
2042 | { | 2042 | { |
2043 | struct node *n = rcu_dereference(t->trie); | 2043 | struct node *n ; |
2044 | |||
2045 | if(!t) | ||
2046 | return NULL; | ||
2047 | |||
2048 | n = rcu_dereference(t->trie); | ||
2049 | |||
2050 | if(!iter) | ||
2051 | return NULL; | ||
2044 | 2052 | ||
2045 | if (n && IS_TNODE(n)) { | 2053 | if (n && IS_TNODE(n)) { |
2046 | iter->tnode = (struct tnode *) n; | 2054 | iter->tnode = (struct tnode *) n; |
@@ -2072,7 +2080,9 @@ static void trie_collect_stats(struct trie *t, struct trie_stat *s) | |||
2072 | int i; | 2080 | int i; |
2073 | 2081 | ||
2074 | s->tnodes++; | 2082 | s->tnodes++; |
2075 | s->nodesizes[tn->bits]++; | 2083 | if(tn->bits < MAX_STAT_DEPTH) |
2084 | s->nodesizes[tn->bits]++; | ||
2085 | |||
2076 | for (i = 0; i < (1<<tn->bits); i++) | 2086 | for (i = 0; i < (1<<tn->bits); i++) |
2077 | if (!tn->child[i]) | 2087 | if (!tn->child[i]) |
2078 | s->nullpointers++; | 2088 | s->nullpointers++; |
@@ -2102,8 +2112,8 @@ static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat) | |||
2102 | seq_printf(seq, "\tInternal nodes: %d\n\t", stat->tnodes); | 2112 | seq_printf(seq, "\tInternal nodes: %d\n\t", stat->tnodes); |
2103 | bytes += sizeof(struct tnode) * stat->tnodes; | 2113 | bytes += sizeof(struct tnode) * stat->tnodes; |
2104 | 2114 | ||
2105 | max = MAX_CHILDS-1; | 2115 | max = MAX_STAT_DEPTH; |
2106 | while (max >= 0 && stat->nodesizes[max] == 0) | 2116 | while (max > 0 && stat->nodesizes[max-1] == 0) |
2107 | max--; | 2117 | max--; |
2108 | 2118 | ||
2109 | pointers = 0; | 2119 | pointers = 0; |
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 64ce52bf0485..d512239a1473 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
@@ -1382,7 +1382,7 @@ static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr) | |||
1382 | dev = ip_dev_find(imr->imr_address.s_addr); | 1382 | dev = ip_dev_find(imr->imr_address.s_addr); |
1383 | if (!dev) | 1383 | if (!dev) |
1384 | return NULL; | 1384 | return NULL; |
1385 | __dev_put(dev); | 1385 | dev_put(dev); |
1386 | } | 1386 | } |
1387 | 1387 | ||
1388 | if (!dev && !ip_route_output_key(&rt, &fl)) { | 1388 | if (!dev && !ip_route_output_key(&rt, &fl)) { |
@@ -1730,7 +1730,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) | |||
1730 | if (!MULTICAST(addr)) | 1730 | if (!MULTICAST(addr)) |
1731 | return -EINVAL; | 1731 | return -EINVAL; |
1732 | 1732 | ||
1733 | rtnl_shlock(); | 1733 | rtnl_lock(); |
1734 | 1734 | ||
1735 | in_dev = ip_mc_find_dev(imr); | 1735 | in_dev = ip_mc_find_dev(imr); |
1736 | 1736 | ||
@@ -1763,7 +1763,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) | |||
1763 | ip_mc_inc_group(in_dev, addr); | 1763 | ip_mc_inc_group(in_dev, addr); |
1764 | err = 0; | 1764 | err = 0; |
1765 | done: | 1765 | done: |
1766 | rtnl_shunlock(); | 1766 | rtnl_unlock(); |
1767 | return err; | 1767 | return err; |
1768 | } | 1768 | } |
1769 | 1769 | ||
@@ -1837,7 +1837,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct | |||
1837 | if (!MULTICAST(addr)) | 1837 | if (!MULTICAST(addr)) |
1838 | return -EINVAL; | 1838 | return -EINVAL; |
1839 | 1839 | ||
1840 | rtnl_shlock(); | 1840 | rtnl_lock(); |
1841 | 1841 | ||
1842 | imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr; | 1842 | imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr; |
1843 | imr.imr_address.s_addr = mreqs->imr_interface; | 1843 | imr.imr_address.s_addr = mreqs->imr_interface; |
@@ -1947,7 +1947,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct | |||
1947 | ip_mc_add_src(in_dev, &mreqs->imr_multiaddr, omode, 1, | 1947 | ip_mc_add_src(in_dev, &mreqs->imr_multiaddr, omode, 1, |
1948 | &mreqs->imr_sourceaddr, 1); | 1948 | &mreqs->imr_sourceaddr, 1); |
1949 | done: | 1949 | done: |
1950 | rtnl_shunlock(); | 1950 | rtnl_unlock(); |
1951 | if (leavegroup) | 1951 | if (leavegroup) |
1952 | return ip_mc_leave_group(sk, &imr); | 1952 | return ip_mc_leave_group(sk, &imr); |
1953 | return err; | 1953 | return err; |
@@ -1970,7 +1970,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) | |||
1970 | msf->imsf_fmode != MCAST_EXCLUDE) | 1970 | msf->imsf_fmode != MCAST_EXCLUDE) |
1971 | return -EINVAL; | 1971 | return -EINVAL; |
1972 | 1972 | ||
1973 | rtnl_shlock(); | 1973 | rtnl_lock(); |
1974 | 1974 | ||
1975 | imr.imr_multiaddr.s_addr = msf->imsf_multiaddr; | 1975 | imr.imr_multiaddr.s_addr = msf->imsf_multiaddr; |
1976 | imr.imr_address.s_addr = msf->imsf_interface; | 1976 | imr.imr_address.s_addr = msf->imsf_interface; |
@@ -2030,7 +2030,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) | |||
2030 | pmc->sfmode = msf->imsf_fmode; | 2030 | pmc->sfmode = msf->imsf_fmode; |
2031 | err = 0; | 2031 | err = 0; |
2032 | done: | 2032 | done: |
2033 | rtnl_shunlock(); | 2033 | rtnl_unlock(); |
2034 | if (leavegroup) | 2034 | if (leavegroup) |
2035 | err = ip_mc_leave_group(sk, &imr); | 2035 | err = ip_mc_leave_group(sk, &imr); |
2036 | return err; | 2036 | return err; |
@@ -2050,7 +2050,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, | |||
2050 | if (!MULTICAST(addr)) | 2050 | if (!MULTICAST(addr)) |
2051 | return -EINVAL; | 2051 | return -EINVAL; |
2052 | 2052 | ||
2053 | rtnl_shlock(); | 2053 | rtnl_lock(); |
2054 | 2054 | ||
2055 | imr.imr_multiaddr.s_addr = msf->imsf_multiaddr; | 2055 | imr.imr_multiaddr.s_addr = msf->imsf_multiaddr; |
2056 | imr.imr_address.s_addr = msf->imsf_interface; | 2056 | imr.imr_address.s_addr = msf->imsf_interface; |
@@ -2072,7 +2072,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, | |||
2072 | goto done; | 2072 | goto done; |
2073 | msf->imsf_fmode = pmc->sfmode; | 2073 | msf->imsf_fmode = pmc->sfmode; |
2074 | psl = pmc->sflist; | 2074 | psl = pmc->sflist; |
2075 | rtnl_shunlock(); | 2075 | rtnl_unlock(); |
2076 | if (!psl) { | 2076 | if (!psl) { |
2077 | len = 0; | 2077 | len = 0; |
2078 | count = 0; | 2078 | count = 0; |
@@ -2091,7 +2091,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, | |||
2091 | return -EFAULT; | 2091 | return -EFAULT; |
2092 | return 0; | 2092 | return 0; |
2093 | done: | 2093 | done: |
2094 | rtnl_shunlock(); | 2094 | rtnl_unlock(); |
2095 | return err; | 2095 | return err; |
2096 | } | 2096 | } |
2097 | 2097 | ||
@@ -2112,7 +2112,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, | |||
2112 | if (!MULTICAST(addr)) | 2112 | if (!MULTICAST(addr)) |
2113 | return -EINVAL; | 2113 | return -EINVAL; |
2114 | 2114 | ||
2115 | rtnl_shlock(); | 2115 | rtnl_lock(); |
2116 | 2116 | ||
2117 | err = -EADDRNOTAVAIL; | 2117 | err = -EADDRNOTAVAIL; |
2118 | 2118 | ||
@@ -2125,7 +2125,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, | |||
2125 | goto done; | 2125 | goto done; |
2126 | gsf->gf_fmode = pmc->sfmode; | 2126 | gsf->gf_fmode = pmc->sfmode; |
2127 | psl = pmc->sflist; | 2127 | psl = pmc->sflist; |
2128 | rtnl_shunlock(); | 2128 | rtnl_unlock(); |
2129 | count = psl ? psl->sl_count : 0; | 2129 | count = psl ? psl->sl_count : 0; |
2130 | copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; | 2130 | copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; |
2131 | gsf->gf_numsrc = count; | 2131 | gsf->gf_numsrc = count; |
@@ -2146,7 +2146,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, | |||
2146 | } | 2146 | } |
2147 | return 0; | 2147 | return 0; |
2148 | done: | 2148 | done: |
2149 | rtnl_shunlock(); | 2149 | rtnl_unlock(); |
2150 | return err; | 2150 | return err; |
2151 | } | 2151 | } |
2152 | 2152 | ||
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index ae20281d8deb..9a01bb81f8bf 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c | |||
@@ -648,3 +648,52 @@ void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr) | |||
648 | } | 648 | } |
649 | 649 | ||
650 | EXPORT_SYMBOL_GPL(inet_csk_addr2sockaddr); | 650 | EXPORT_SYMBOL_GPL(inet_csk_addr2sockaddr); |
651 | |||
652 | int inet_csk_ctl_sock_create(struct socket **sock, unsigned short family, | ||
653 | unsigned short type, unsigned char protocol) | ||
654 | { | ||
655 | int rc = sock_create_kern(family, type, protocol, sock); | ||
656 | |||
657 | if (rc == 0) { | ||
658 | (*sock)->sk->sk_allocation = GFP_ATOMIC; | ||
659 | inet_sk((*sock)->sk)->uc_ttl = -1; | ||
660 | /* | ||
661 | * Unhash it so that IP input processing does not even see it, | ||
662 | * we do not wish this socket to see incoming packets. | ||
663 | */ | ||
664 | (*sock)->sk->sk_prot->unhash((*sock)->sk); | ||
665 | } | ||
666 | return rc; | ||
667 | } | ||
668 | |||
669 | EXPORT_SYMBOL_GPL(inet_csk_ctl_sock_create); | ||
670 | |||
671 | #ifdef CONFIG_COMPAT | ||
672 | int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname, | ||
673 | char __user *optval, int __user *optlen) | ||
674 | { | ||
675 | const struct inet_connection_sock *icsk = inet_csk(sk); | ||
676 | |||
677 | if (icsk->icsk_af_ops->compat_getsockopt != NULL) | ||
678 | return icsk->icsk_af_ops->compat_getsockopt(sk, level, optname, | ||
679 | optval, optlen); | ||
680 | return icsk->icsk_af_ops->getsockopt(sk, level, optname, | ||
681 | optval, optlen); | ||
682 | } | ||
683 | |||
684 | EXPORT_SYMBOL_GPL(inet_csk_compat_getsockopt); | ||
685 | |||
686 | int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname, | ||
687 | char __user *optval, int optlen) | ||
688 | { | ||
689 | const struct inet_connection_sock *icsk = inet_csk(sk); | ||
690 | |||
691 | if (icsk->icsk_af_ops->compat_setsockopt != NULL) | ||
692 | return icsk->icsk_af_ops->compat_setsockopt(sk, level, optname, | ||
693 | optval, optlen); | ||
694 | return icsk->icsk_af_ops->setsockopt(sk, level, optname, | ||
695 | optval, optlen); | ||
696 | } | ||
697 | |||
698 | EXPORT_SYMBOL_GPL(inet_csk_compat_setsockopt); | ||
699 | #endif | ||
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 8ee4d016740d..f75ff1d96551 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
@@ -1249,11 +1249,7 @@ int ip_push_pending_frames(struct sock *sk) | |||
1249 | iph->tos = inet->tos; | 1249 | iph->tos = inet->tos; |
1250 | iph->tot_len = htons(skb->len); | 1250 | iph->tot_len = htons(skb->len); |
1251 | iph->frag_off = df; | 1251 | iph->frag_off = df; |
1252 | if (!df) { | 1252 | ip_select_ident(iph, &rt->u.dst, sk); |
1253 | __ip_select_ident(iph, &rt->u.dst, 0); | ||
1254 | } else { | ||
1255 | iph->id = htons(inet->id++); | ||
1256 | } | ||
1257 | iph->ttl = ttl; | 1253 | iph->ttl = ttl; |
1258 | iph->protocol = sk->sk_protocol; | 1254 | iph->protocol = sk->sk_protocol; |
1259 | iph->saddr = rt->rt_src; | 1255 | iph->saddr = rt->rt_src; |
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 2bf8d782f678..12e0bf19f24a 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #define IP_CMSG_TOS 4 | 50 | #define IP_CMSG_TOS 4 |
51 | #define IP_CMSG_RECVOPTS 8 | 51 | #define IP_CMSG_RECVOPTS 8 |
52 | #define IP_CMSG_RETOPTS 16 | 52 | #define IP_CMSG_RETOPTS 16 |
53 | #define IP_CMSG_PASSSEC 32 | ||
53 | 54 | ||
54 | /* | 55 | /* |
55 | * SOL_IP control messages. | 56 | * SOL_IP control messages. |
@@ -109,6 +110,19 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb) | |||
109 | put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data); | 110 | put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data); |
110 | } | 111 | } |
111 | 112 | ||
113 | static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb) | ||
114 | { | ||
115 | char *secdata; | ||
116 | u32 seclen; | ||
117 | int err; | ||
118 | |||
119 | err = security_socket_getpeersec_dgram(skb, &secdata, &seclen); | ||
120 | if (err) | ||
121 | return; | ||
122 | |||
123 | put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata); | ||
124 | } | ||
125 | |||
112 | 126 | ||
113 | void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) | 127 | void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) |
114 | { | 128 | { |
@@ -138,6 +152,11 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) | |||
138 | 152 | ||
139 | if (flags & 1) | 153 | if (flags & 1) |
140 | ip_cmsg_recv_retopts(msg, skb); | 154 | ip_cmsg_recv_retopts(msg, skb); |
155 | if ((flags>>=1) == 0) | ||
156 | return; | ||
157 | |||
158 | if (flags & 1) | ||
159 | ip_cmsg_recv_security(msg, skb); | ||
141 | } | 160 | } |
142 | 161 | ||
143 | int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc) | 162 | int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc) |
@@ -380,20 +399,19 @@ out: | |||
380 | * an IP socket. | 399 | * an IP socket. |
381 | */ | 400 | */ |
382 | 401 | ||
383 | int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) | 402 | static int do_ip_setsockopt(struct sock *sk, int level, |
403 | int optname, char __user *optval, int optlen) | ||
384 | { | 404 | { |
385 | struct inet_sock *inet = inet_sk(sk); | 405 | struct inet_sock *inet = inet_sk(sk); |
386 | int val=0,err; | 406 | int val=0,err; |
387 | 407 | ||
388 | if (level != SOL_IP) | ||
389 | return -ENOPROTOOPT; | ||
390 | |||
391 | if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) | | 408 | if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) | |
392 | (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) | | 409 | (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) | |
393 | (1<<IP_RETOPTS) | (1<<IP_TOS) | | 410 | (1<<IP_RETOPTS) | (1<<IP_TOS) | |
394 | (1<<IP_TTL) | (1<<IP_HDRINCL) | | 411 | (1<<IP_TTL) | (1<<IP_HDRINCL) | |
395 | (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) | | 412 | (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) | |
396 | (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND))) || | 413 | (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) | |
414 | (1<<IP_PASSSEC))) || | ||
397 | optname == IP_MULTICAST_TTL || | 415 | optname == IP_MULTICAST_TTL || |
398 | optname == IP_MULTICAST_LOOP) { | 416 | optname == IP_MULTICAST_LOOP) { |
399 | if (optlen >= sizeof(int)) { | 417 | if (optlen >= sizeof(int)) { |
@@ -478,6 +496,12 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
478 | else | 496 | else |
479 | inet->cmsg_flags &= ~IP_CMSG_RETOPTS; | 497 | inet->cmsg_flags &= ~IP_CMSG_RETOPTS; |
480 | break; | 498 | break; |
499 | case IP_PASSSEC: | ||
500 | if (val) | ||
501 | inet->cmsg_flags |= IP_CMSG_PASSSEC; | ||
502 | else | ||
503 | inet->cmsg_flags &= ~IP_CMSG_PASSSEC; | ||
504 | break; | ||
481 | case IP_TOS: /* This sets both TOS and Precedence */ | 505 | case IP_TOS: /* This sets both TOS and Precedence */ |
482 | if (sk->sk_type == SOCK_STREAM) { | 506 | if (sk->sk_type == SOCK_STREAM) { |
483 | val &= ~3; | 507 | val &= ~3; |
@@ -849,12 +873,7 @@ mc_msf_out: | |||
849 | break; | 873 | break; |
850 | 874 | ||
851 | default: | 875 | default: |
852 | #ifdef CONFIG_NETFILTER | ||
853 | err = nf_setsockopt(sk, PF_INET, optname, optval, | ||
854 | optlen); | ||
855 | #else | ||
856 | err = -ENOPROTOOPT; | 876 | err = -ENOPROTOOPT; |
857 | #endif | ||
858 | break; | 877 | break; |
859 | } | 878 | } |
860 | release_sock(sk); | 879 | release_sock(sk); |
@@ -865,12 +884,68 @@ e_inval: | |||
865 | return -EINVAL; | 884 | return -EINVAL; |
866 | } | 885 | } |
867 | 886 | ||
887 | int ip_setsockopt(struct sock *sk, int level, | ||
888 | int optname, char __user *optval, int optlen) | ||
889 | { | ||
890 | int err; | ||
891 | |||
892 | if (level != SOL_IP) | ||
893 | return -ENOPROTOOPT; | ||
894 | |||
895 | err = do_ip_setsockopt(sk, level, optname, optval, optlen); | ||
896 | #ifdef CONFIG_NETFILTER | ||
897 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
898 | if (err == -ENOPROTOOPT && optname != IP_HDRINCL && | ||
899 | optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY | ||
900 | #ifdef CONFIG_IP_MROUTE | ||
901 | && (optname < MRT_BASE || optname > (MRT_BASE + 10)) | ||
902 | #endif | ||
903 | ) { | ||
904 | lock_sock(sk); | ||
905 | err = nf_setsockopt(sk, PF_INET, optname, optval, optlen); | ||
906 | release_sock(sk); | ||
907 | } | ||
908 | #endif | ||
909 | return err; | ||
910 | } | ||
911 | |||
912 | #ifdef CONFIG_COMPAT | ||
913 | int compat_ip_setsockopt(struct sock *sk, int level, int optname, | ||
914 | char __user *optval, int optlen) | ||
915 | { | ||
916 | int err; | ||
917 | |||
918 | if (level != SOL_IP) | ||
919 | return -ENOPROTOOPT; | ||
920 | |||
921 | err = do_ip_setsockopt(sk, level, optname, optval, optlen); | ||
922 | #ifdef CONFIG_NETFILTER | ||
923 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
924 | if (err == -ENOPROTOOPT && optname != IP_HDRINCL && | ||
925 | optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY | ||
926 | #ifdef CONFIG_IP_MROUTE | ||
927 | && (optname < MRT_BASE || optname > (MRT_BASE + 10)) | ||
928 | #endif | ||
929 | ) { | ||
930 | lock_sock(sk); | ||
931 | err = compat_nf_setsockopt(sk, PF_INET, optname, | ||
932 | optval, optlen); | ||
933 | release_sock(sk); | ||
934 | } | ||
935 | #endif | ||
936 | return err; | ||
937 | } | ||
938 | |||
939 | EXPORT_SYMBOL(compat_ip_setsockopt); | ||
940 | #endif | ||
941 | |||
868 | /* | 942 | /* |
869 | * Get the options. Note for future reference. The GET of IP options gets the | 943 | * Get the options. Note for future reference. The GET of IP options gets the |
870 | * _received_ ones. The set sets the _sent_ ones. | 944 | * _received_ ones. The set sets the _sent_ ones. |
871 | */ | 945 | */ |
872 | 946 | ||
873 | int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) | 947 | static int do_ip_getsockopt(struct sock *sk, int level, int optname, |
948 | char __user *optval, int __user *optlen) | ||
874 | { | 949 | { |
875 | struct inet_sock *inet = inet_sk(sk); | 950 | struct inet_sock *inet = inet_sk(sk); |
876 | int val; | 951 | int val; |
@@ -932,6 +1007,9 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
932 | case IP_RETOPTS: | 1007 | case IP_RETOPTS: |
933 | val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0; | 1008 | val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0; |
934 | break; | 1009 | break; |
1010 | case IP_PASSSEC: | ||
1011 | val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0; | ||
1012 | break; | ||
935 | case IP_TOS: | 1013 | case IP_TOS: |
936 | val = inet->tos; | 1014 | val = inet->tos; |
937 | break; | 1015 | break; |
@@ -1051,17 +1129,8 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
1051 | val = inet->freebind; | 1129 | val = inet->freebind; |
1052 | break; | 1130 | break; |
1053 | default: | 1131 | default: |
1054 | #ifdef CONFIG_NETFILTER | ||
1055 | val = nf_getsockopt(sk, PF_INET, optname, optval, | ||
1056 | &len); | ||
1057 | release_sock(sk); | ||
1058 | if (val >= 0) | ||
1059 | val = put_user(len, optlen); | ||
1060 | return val; | ||
1061 | #else | ||
1062 | release_sock(sk); | 1132 | release_sock(sk); |
1063 | return -ENOPROTOOPT; | 1133 | return -ENOPROTOOPT; |
1064 | #endif | ||
1065 | } | 1134 | } |
1066 | release_sock(sk); | 1135 | release_sock(sk); |
1067 | 1136 | ||
@@ -1082,6 +1151,67 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
1082 | return 0; | 1151 | return 0; |
1083 | } | 1152 | } |
1084 | 1153 | ||
1154 | int ip_getsockopt(struct sock *sk, int level, | ||
1155 | int optname, char __user *optval, int __user *optlen) | ||
1156 | { | ||
1157 | int err; | ||
1158 | |||
1159 | err = do_ip_getsockopt(sk, level, optname, optval, optlen); | ||
1160 | #ifdef CONFIG_NETFILTER | ||
1161 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
1162 | if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS | ||
1163 | #ifdef CONFIG_IP_MROUTE | ||
1164 | && (optname < MRT_BASE || optname > MRT_BASE+10) | ||
1165 | #endif | ||
1166 | ) { | ||
1167 | int len; | ||
1168 | |||
1169 | if(get_user(len,optlen)) | ||
1170 | return -EFAULT; | ||
1171 | |||
1172 | lock_sock(sk); | ||
1173 | err = nf_getsockopt(sk, PF_INET, optname, optval, | ||
1174 | &len); | ||
1175 | release_sock(sk); | ||
1176 | if (err >= 0) | ||
1177 | err = put_user(len, optlen); | ||
1178 | return err; | ||
1179 | } | ||
1180 | #endif | ||
1181 | return err; | ||
1182 | } | ||
1183 | |||
1184 | #ifdef CONFIG_COMPAT | ||
1185 | int compat_ip_getsockopt(struct sock *sk, int level, int optname, | ||
1186 | char __user *optval, int __user *optlen) | ||
1187 | { | ||
1188 | int err = do_ip_getsockopt(sk, level, optname, optval, optlen); | ||
1189 | #ifdef CONFIG_NETFILTER | ||
1190 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
1191 | if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS | ||
1192 | #ifdef CONFIG_IP_MROUTE | ||
1193 | && (optname < MRT_BASE || optname > MRT_BASE+10) | ||
1194 | #endif | ||
1195 | ) { | ||
1196 | int len; | ||
1197 | |||
1198 | if (get_user(len, optlen)) | ||
1199 | return -EFAULT; | ||
1200 | |||
1201 | lock_sock(sk); | ||
1202 | err = compat_nf_getsockopt(sk, PF_INET, optname, optval, &len); | ||
1203 | release_sock(sk); | ||
1204 | if (err >= 0) | ||
1205 | err = put_user(len, optlen); | ||
1206 | return err; | ||
1207 | } | ||
1208 | #endif | ||
1209 | return err; | ||
1210 | } | ||
1211 | |||
1212 | EXPORT_SYMBOL(compat_ip_getsockopt); | ||
1213 | #endif | ||
1214 | |||
1085 | EXPORT_SYMBOL(ip_cmsg_recv); | 1215 | EXPORT_SYMBOL(ip_cmsg_recv); |
1086 | 1216 | ||
1087 | EXPORT_SYMBOL(ip_getsockopt); | 1217 | EXPORT_SYMBOL(ip_getsockopt); |
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index d64e2ec8da7b..c95020f7c81e 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
25 | #include <linux/vmalloc.h> | 25 | #include <linux/vmalloc.h> |
26 | #include <linux/rtnetlink.h> | 26 | #include <linux/rtnetlink.h> |
27 | #include <linux/mutex.h> | ||
27 | #include <net/ip.h> | 28 | #include <net/ip.h> |
28 | #include <net/xfrm.h> | 29 | #include <net/xfrm.h> |
29 | #include <net/icmp.h> | 30 | #include <net/icmp.h> |
@@ -36,7 +37,7 @@ struct ipcomp_tfms { | |||
36 | int users; | 37 | int users; |
37 | }; | 38 | }; |
38 | 39 | ||
39 | static DECLARE_MUTEX(ipcomp_resource_sem); | 40 | static DEFINE_MUTEX(ipcomp_resource_mutex); |
40 | static void **ipcomp_scratches; | 41 | static void **ipcomp_scratches; |
41 | static int ipcomp_scratch_users; | 42 | static int ipcomp_scratch_users; |
42 | static LIST_HEAD(ipcomp_tfms_list); | 43 | static LIST_HEAD(ipcomp_tfms_list); |
@@ -253,7 +254,7 @@ error: | |||
253 | } | 254 | } |
254 | 255 | ||
255 | /* | 256 | /* |
256 | * Must be protected by xfrm_cfg_sem. State and tunnel user references are | 257 | * Must be protected by xfrm_cfg_mutex. State and tunnel user references are |
257 | * always incremented on success. | 258 | * always incremented on success. |
258 | */ | 259 | */ |
259 | static int ipcomp_tunnel_attach(struct xfrm_state *x) | 260 | static int ipcomp_tunnel_attach(struct xfrm_state *x) |
@@ -411,9 +412,9 @@ static void ipcomp_destroy(struct xfrm_state *x) | |||
411 | if (!ipcd) | 412 | if (!ipcd) |
412 | return; | 413 | return; |
413 | xfrm_state_delete_tunnel(x); | 414 | xfrm_state_delete_tunnel(x); |
414 | down(&ipcomp_resource_sem); | 415 | mutex_lock(&ipcomp_resource_mutex); |
415 | ipcomp_free_data(ipcd); | 416 | ipcomp_free_data(ipcd); |
416 | up(&ipcomp_resource_sem); | 417 | mutex_unlock(&ipcomp_resource_mutex); |
417 | kfree(ipcd); | 418 | kfree(ipcd); |
418 | } | 419 | } |
419 | 420 | ||
@@ -440,14 +441,14 @@ static int ipcomp_init_state(struct xfrm_state *x) | |||
440 | if (x->props.mode) | 441 | if (x->props.mode) |
441 | x->props.header_len += sizeof(struct iphdr); | 442 | x->props.header_len += sizeof(struct iphdr); |
442 | 443 | ||
443 | down(&ipcomp_resource_sem); | 444 | mutex_lock(&ipcomp_resource_mutex); |
444 | if (!ipcomp_alloc_scratches()) | 445 | if (!ipcomp_alloc_scratches()) |
445 | goto error; | 446 | goto error; |
446 | 447 | ||
447 | ipcd->tfms = ipcomp_alloc_tfms(x->calg->alg_name); | 448 | ipcd->tfms = ipcomp_alloc_tfms(x->calg->alg_name); |
448 | if (!ipcd->tfms) | 449 | if (!ipcd->tfms) |
449 | goto error; | 450 | goto error; |
450 | up(&ipcomp_resource_sem); | 451 | mutex_unlock(&ipcomp_resource_mutex); |
451 | 452 | ||
452 | if (x->props.mode) { | 453 | if (x->props.mode) { |
453 | err = ipcomp_tunnel_attach(x); | 454 | err = ipcomp_tunnel_attach(x); |
@@ -464,10 +465,10 @@ out: | |||
464 | return err; | 465 | return err; |
465 | 466 | ||
466 | error_tunnel: | 467 | error_tunnel: |
467 | down(&ipcomp_resource_sem); | 468 | mutex_lock(&ipcomp_resource_mutex); |
468 | error: | 469 | error: |
469 | ipcomp_free_data(ipcd); | 470 | ipcomp_free_data(ipcd); |
470 | up(&ipcomp_resource_sem); | 471 | mutex_unlock(&ipcomp_resource_mutex); |
471 | kfree(ipcd); | 472 | kfree(ipcd); |
472 | goto out; | 473 | goto out; |
473 | } | 474 | } |
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index bb3613ec448c..cb8a92f18ef6 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c | |||
@@ -186,7 +186,7 @@ static int __init ic_open_devs(void) | |||
186 | unsigned short oflags; | 186 | unsigned short oflags; |
187 | 187 | ||
188 | last = &ic_first_dev; | 188 | last = &ic_first_dev; |
189 | rtnl_shlock(); | 189 | rtnl_lock(); |
190 | 190 | ||
191 | /* bring loopback device up first */ | 191 | /* bring loopback device up first */ |
192 | if (dev_change_flags(&loopback_dev, loopback_dev.flags | IFF_UP) < 0) | 192 | if (dev_change_flags(&loopback_dev, loopback_dev.flags | IFF_UP) < 0) |
@@ -215,7 +215,7 @@ static int __init ic_open_devs(void) | |||
215 | continue; | 215 | continue; |
216 | } | 216 | } |
217 | if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL))) { | 217 | if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL))) { |
218 | rtnl_shunlock(); | 218 | rtnl_unlock(); |
219 | return -1; | 219 | return -1; |
220 | } | 220 | } |
221 | d->dev = dev; | 221 | d->dev = dev; |
@@ -232,7 +232,7 @@ static int __init ic_open_devs(void) | |||
232 | dev->name, able, d->xid)); | 232 | dev->name, able, d->xid)); |
233 | } | 233 | } |
234 | } | 234 | } |
235 | rtnl_shunlock(); | 235 | rtnl_unlock(); |
236 | 236 | ||
237 | *last = NULL; | 237 | *last = NULL; |
238 | 238 | ||
@@ -251,7 +251,7 @@ static void __init ic_close_devs(void) | |||
251 | struct ic_device *d, *next; | 251 | struct ic_device *d, *next; |
252 | struct net_device *dev; | 252 | struct net_device *dev; |
253 | 253 | ||
254 | rtnl_shlock(); | 254 | rtnl_lock(); |
255 | next = ic_first_dev; | 255 | next = ic_first_dev; |
256 | while ((d = next)) { | 256 | while ((d = next)) { |
257 | next = d->next; | 257 | next = d->next; |
@@ -262,7 +262,7 @@ static void __init ic_close_devs(void) | |||
262 | } | 262 | } |
263 | kfree(d); | 263 | kfree(d); |
264 | } | 264 | } |
265 | rtnl_shunlock(); | 265 | rtnl_unlock(); |
266 | } | 266 | } |
267 | 267 | ||
268 | /* | 268 | /* |
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 5c94c222e3f3..717ab7d6d7b6 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
@@ -415,10 +415,10 @@ static int vif_add(struct vifctl *vifc, int mrtsock) | |||
415 | return -ENOBUFS; | 415 | return -ENOBUFS; |
416 | break; | 416 | break; |
417 | case 0: | 417 | case 0: |
418 | dev=ip_dev_find(vifc->vifc_lcl_addr.s_addr); | 418 | dev = ip_dev_find(vifc->vifc_lcl_addr.s_addr); |
419 | if (!dev) | 419 | if (!dev) |
420 | return -EADDRNOTAVAIL; | 420 | return -EADDRNOTAVAIL; |
421 | __dev_put(dev); | 421 | dev_put(dev); |
422 | break; | 422 | break; |
423 | default: | 423 | default: |
424 | return -EINVAL; | 424 | return -EINVAL; |
diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c index 9b176a942ac5..e7752334d296 100644 --- a/net/ipv4/ipvs/ip_vs_app.c +++ b/net/ipv4/ipvs/ip_vs_app.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/stat.h> | 31 | #include <linux/stat.h> |
32 | #include <linux/proc_fs.h> | 32 | #include <linux/proc_fs.h> |
33 | #include <linux/seq_file.h> | 33 | #include <linux/seq_file.h> |
34 | #include <linux/mutex.h> | ||
34 | 35 | ||
35 | #include <net/ip_vs.h> | 36 | #include <net/ip_vs.h> |
36 | 37 | ||
@@ -40,7 +41,7 @@ EXPORT_SYMBOL(register_ip_vs_app_inc); | |||
40 | 41 | ||
41 | /* ipvs application list head */ | 42 | /* ipvs application list head */ |
42 | static LIST_HEAD(ip_vs_app_list); | 43 | static LIST_HEAD(ip_vs_app_list); |
43 | static DECLARE_MUTEX(__ip_vs_app_mutex); | 44 | static DEFINE_MUTEX(__ip_vs_app_mutex); |
44 | 45 | ||
45 | 46 | ||
46 | /* | 47 | /* |
@@ -173,11 +174,11 @@ register_ip_vs_app_inc(struct ip_vs_app *app, __u16 proto, __u16 port) | |||
173 | { | 174 | { |
174 | int result; | 175 | int result; |
175 | 176 | ||
176 | down(&__ip_vs_app_mutex); | 177 | mutex_lock(&__ip_vs_app_mutex); |
177 | 178 | ||
178 | result = ip_vs_app_inc_new(app, proto, port); | 179 | result = ip_vs_app_inc_new(app, proto, port); |
179 | 180 | ||
180 | up(&__ip_vs_app_mutex); | 181 | mutex_unlock(&__ip_vs_app_mutex); |
181 | 182 | ||
182 | return result; | 183 | return result; |
183 | } | 184 | } |
@@ -191,11 +192,11 @@ int register_ip_vs_app(struct ip_vs_app *app) | |||
191 | /* increase the module use count */ | 192 | /* increase the module use count */ |
192 | ip_vs_use_count_inc(); | 193 | ip_vs_use_count_inc(); |
193 | 194 | ||
194 | down(&__ip_vs_app_mutex); | 195 | mutex_lock(&__ip_vs_app_mutex); |
195 | 196 | ||
196 | list_add(&app->a_list, &ip_vs_app_list); | 197 | list_add(&app->a_list, &ip_vs_app_list); |
197 | 198 | ||
198 | up(&__ip_vs_app_mutex); | 199 | mutex_unlock(&__ip_vs_app_mutex); |
199 | 200 | ||
200 | return 0; | 201 | return 0; |
201 | } | 202 | } |
@@ -209,7 +210,7 @@ void unregister_ip_vs_app(struct ip_vs_app *app) | |||
209 | { | 210 | { |
210 | struct ip_vs_app *inc, *nxt; | 211 | struct ip_vs_app *inc, *nxt; |
211 | 212 | ||
212 | down(&__ip_vs_app_mutex); | 213 | mutex_lock(&__ip_vs_app_mutex); |
213 | 214 | ||
214 | list_for_each_entry_safe(inc, nxt, &app->incs_list, a_list) { | 215 | list_for_each_entry_safe(inc, nxt, &app->incs_list, a_list) { |
215 | ip_vs_app_inc_release(inc); | 216 | ip_vs_app_inc_release(inc); |
@@ -217,7 +218,7 @@ void unregister_ip_vs_app(struct ip_vs_app *app) | |||
217 | 218 | ||
218 | list_del(&app->a_list); | 219 | list_del(&app->a_list); |
219 | 220 | ||
220 | up(&__ip_vs_app_mutex); | 221 | mutex_unlock(&__ip_vs_app_mutex); |
221 | 222 | ||
222 | /* decrease the module use count */ | 223 | /* decrease the module use count */ |
223 | ip_vs_use_count_dec(); | 224 | ip_vs_use_count_dec(); |
@@ -498,7 +499,7 @@ static struct ip_vs_app *ip_vs_app_idx(loff_t pos) | |||
498 | 499 | ||
499 | static void *ip_vs_app_seq_start(struct seq_file *seq, loff_t *pos) | 500 | static void *ip_vs_app_seq_start(struct seq_file *seq, loff_t *pos) |
500 | { | 501 | { |
501 | down(&__ip_vs_app_mutex); | 502 | mutex_lock(&__ip_vs_app_mutex); |
502 | 503 | ||
503 | return *pos ? ip_vs_app_idx(*pos - 1) : SEQ_START_TOKEN; | 504 | return *pos ? ip_vs_app_idx(*pos - 1) : SEQ_START_TOKEN; |
504 | } | 505 | } |
@@ -530,7 +531,7 @@ static void *ip_vs_app_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
530 | 531 | ||
531 | static void ip_vs_app_seq_stop(struct seq_file *seq, void *v) | 532 | static void ip_vs_app_seq_stop(struct seq_file *seq, void *v) |
532 | { | 533 | { |
533 | up(&__ip_vs_app_mutex); | 534 | mutex_unlock(&__ip_vs_app_mutex); |
534 | } | 535 | } |
535 | 536 | ||
536 | static int ip_vs_app_seq_show(struct seq_file *seq, void *v) | 537 | static int ip_vs_app_seq_show(struct seq_file *seq, void *v) |
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index db783036e4d8..882b842c25d4 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -168,6 +168,26 @@ config IP_NF_PPTP | |||
168 | If you want to compile it as a module, say M here and read | 168 | If you want to compile it as a module, say M here and read |
169 | Documentation/modules.txt. If unsure, say `N'. | 169 | Documentation/modules.txt. If unsure, say `N'. |
170 | 170 | ||
171 | config IP_NF_H323 | ||
172 | tristate 'H.323 protocol support' | ||
173 | depends on IP_NF_CONNTRACK | ||
174 | help | ||
175 | H.323 is a VoIP signalling protocol from ITU-T. As one of the most | ||
176 | important VoIP protocols, it is widely used by voice hardware and | ||
177 | software including voice gateways, IP phones, Netmeeting, OpenPhone, | ||
178 | Gnomemeeting, etc. | ||
179 | |||
180 | With this module you can support H.323 on a connection tracking/NAT | ||
181 | firewall. | ||
182 | |||
183 | This module supports RAS, Fast-start, H.245 tunnelling, RTP/RTCP | ||
184 | and T.120 based data and applications including audio, video, FAX, | ||
185 | chat, whiteboard, file transfer, etc. For more information, please | ||
186 | see http://nath323.sourceforge.net/. | ||
187 | |||
188 | If you want to compile it as a module, say 'M' here and read | ||
189 | Documentation/modules.txt. If unsure, say 'N'. | ||
190 | |||
171 | config IP_NF_QUEUE | 191 | config IP_NF_QUEUE |
172 | tristate "IP Userspace queueing via NETLINK (OBSOLETE)" | 192 | tristate "IP Userspace queueing via NETLINK (OBSOLETE)" |
173 | help | 193 | help |
@@ -303,16 +323,6 @@ config IP_NF_MATCH_HASHLIMIT | |||
303 | destination IP' or `500pps from any given source IP' with a single | 323 | destination IP' or `500pps from any given source IP' with a single |
304 | IPtables rule. | 324 | IPtables rule. |
305 | 325 | ||
306 | config IP_NF_MATCH_POLICY | ||
307 | tristate "IPsec policy match support" | ||
308 | depends on IP_NF_IPTABLES && XFRM | ||
309 | help | ||
310 | Policy matching allows you to match packets based on the | ||
311 | IPsec policy that was used during decapsulation/will | ||
312 | be used during encapsulation. | ||
313 | |||
314 | To compile it as a module, choose M here. If unsure, say N. | ||
315 | |||
316 | # `filter', generic and specific targets | 326 | # `filter', generic and specific targets |
317 | config IP_NF_FILTER | 327 | config IP_NF_FILTER |
318 | tristate "Packet filtering" | 328 | tristate "Packet filtering" |
@@ -494,6 +504,12 @@ config IP_NF_NAT_PPTP | |||
494 | default IP_NF_NAT if IP_NF_PPTP=y | 504 | default IP_NF_NAT if IP_NF_PPTP=y |
495 | default m if IP_NF_PPTP=m | 505 | default m if IP_NF_PPTP=m |
496 | 506 | ||
507 | config IP_NF_NAT_H323 | ||
508 | tristate | ||
509 | depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n | ||
510 | default IP_NF_NAT if IP_NF_H323=y | ||
511 | default m if IP_NF_H323=m | ||
512 | |||
497 | # mangle + specific targets | 513 | # mangle + specific targets |
498 | config IP_NF_MANGLE | 514 | config IP_NF_MANGLE |
499 | tristate "Packet mangling" | 515 | tristate "Packet mangling" |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index e5c5b3202f02..f2cd9a6c5b91 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
@@ -10,6 +10,9 @@ iptable_nat-objs := ip_nat_rule.o ip_nat_standalone.o | |||
10 | ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o | 10 | ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o |
11 | ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o | 11 | ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o |
12 | 12 | ||
13 | ip_conntrack_h323-objs := ip_conntrack_helper_h323.o ip_conntrack_helper_h323_asn1.o | ||
14 | ip_nat_h323-objs := ip_nat_helper_h323.o | ||
15 | |||
13 | # connection tracking | 16 | # connection tracking |
14 | obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o | 17 | obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o |
15 | obj-$(CONFIG_IP_NF_NAT) += ip_nat.o | 18 | obj-$(CONFIG_IP_NF_NAT) += ip_nat.o |
@@ -22,6 +25,7 @@ obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o | |||
22 | obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o | 25 | obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o |
23 | 26 | ||
24 | # connection tracking helpers | 27 | # connection tracking helpers |
28 | obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o | ||
25 | obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o | 29 | obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o |
26 | obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o | 30 | obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o |
27 | obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o | 31 | obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o |
@@ -30,6 +34,7 @@ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o | |||
30 | obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o | 34 | obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o |
31 | 35 | ||
32 | # NAT helpers | 36 | # NAT helpers |
37 | obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o | ||
33 | obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o | 38 | obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o |
34 | obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o | 39 | obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o |
35 | obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o | 40 | obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o |
@@ -57,7 +62,6 @@ obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o | |||
57 | obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o | 62 | obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o |
58 | obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o | 63 | obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o |
59 | obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o | 64 | obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o |
60 | obj-$(CONFIG_IP_NF_MATCH_POLICY) += ipt_policy.o | ||
61 | 65 | ||
62 | # targets | 66 | # targets |
63 | obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o | 67 | obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o |
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 7d7ab94a7a2e..ff0c594a4198 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | 23 | ||
24 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
25 | #include <asm/semaphore.h> | 25 | #include <linux/mutex.h> |
26 | 26 | ||
27 | #include <linux/netfilter/x_tables.h> | 27 | #include <linux/netfilter/x_tables.h> |
28 | #include <linux/netfilter_arp/arp_tables.h> | 28 | #include <linux/netfilter_arp/arp_tables.h> |
@@ -208,6 +208,7 @@ static unsigned int arpt_error(struct sk_buff **pskb, | |||
208 | const struct net_device *in, | 208 | const struct net_device *in, |
209 | const struct net_device *out, | 209 | const struct net_device *out, |
210 | unsigned int hooknum, | 210 | unsigned int hooknum, |
211 | const struct xt_target *target, | ||
211 | const void *targinfo, | 212 | const void *targinfo, |
212 | void *userinfo) | 213 | void *userinfo) |
213 | { | 214 | { |
@@ -300,6 +301,7 @@ unsigned int arpt_do_table(struct sk_buff **pskb, | |||
300 | verdict = t->u.kernel.target->target(pskb, | 301 | verdict = t->u.kernel.target->target(pskb, |
301 | in, out, | 302 | in, out, |
302 | hook, | 303 | hook, |
304 | t->u.kernel.target, | ||
303 | t->data, | 305 | t->data, |
304 | userdata); | 306 | userdata); |
305 | 307 | ||
@@ -480,26 +482,31 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i | |||
480 | } | 482 | } |
481 | t->u.kernel.target = target; | 483 | t->u.kernel.target = target; |
482 | 484 | ||
485 | ret = xt_check_target(target, NF_ARP, t->u.target_size - sizeof(*t), | ||
486 | name, e->comefrom, 0, 0); | ||
487 | if (ret) | ||
488 | goto err; | ||
489 | |||
483 | if (t->u.kernel.target == &arpt_standard_target) { | 490 | if (t->u.kernel.target == &arpt_standard_target) { |
484 | if (!standard_check(t, size)) { | 491 | if (!standard_check(t, size)) { |
485 | ret = -EINVAL; | 492 | ret = -EINVAL; |
486 | goto out; | 493 | goto out; |
487 | } | 494 | } |
488 | } else if (t->u.kernel.target->checkentry | 495 | } else if (t->u.kernel.target->checkentry |
489 | && !t->u.kernel.target->checkentry(name, e, t->data, | 496 | && !t->u.kernel.target->checkentry(name, e, target, t->data, |
490 | t->u.target_size | 497 | t->u.target_size |
491 | - sizeof(*t), | 498 | - sizeof(*t), |
492 | e->comefrom)) { | 499 | e->comefrom)) { |
493 | module_put(t->u.kernel.target->me); | ||
494 | duprintf("arp_tables: check failed for `%s'.\n", | 500 | duprintf("arp_tables: check failed for `%s'.\n", |
495 | t->u.kernel.target->name); | 501 | t->u.kernel.target->name); |
496 | ret = -EINVAL; | 502 | ret = -EINVAL; |
497 | goto out; | 503 | goto err; |
498 | } | 504 | } |
499 | 505 | ||
500 | (*i)++; | 506 | (*i)++; |
501 | return 0; | 507 | return 0; |
502 | 508 | err: | |
509 | module_put(t->u.kernel.target->me); | ||
503 | out: | 510 | out: |
504 | return ret; | 511 | return ret; |
505 | } | 512 | } |
@@ -555,7 +562,7 @@ static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i) | |||
555 | 562 | ||
556 | t = arpt_get_target(e); | 563 | t = arpt_get_target(e); |
557 | if (t->u.kernel.target->destroy) | 564 | if (t->u.kernel.target->destroy) |
558 | t->u.kernel.target->destroy(t->data, | 565 | t->u.kernel.target->destroy(t->u.kernel.target, t->data, |
559 | t->u.target_size - sizeof(*t)); | 566 | t->u.target_size - sizeof(*t)); |
560 | module_put(t->u.kernel.target->me); | 567 | module_put(t->u.kernel.target->me); |
561 | return 0; | 568 | return 0; |
@@ -1138,11 +1145,15 @@ void arpt_unregister_table(struct arpt_table *table) | |||
1138 | /* The built-in targets: standard (NULL) and error. */ | 1145 | /* The built-in targets: standard (NULL) and error. */ |
1139 | static struct arpt_target arpt_standard_target = { | 1146 | static struct arpt_target arpt_standard_target = { |
1140 | .name = ARPT_STANDARD_TARGET, | 1147 | .name = ARPT_STANDARD_TARGET, |
1148 | .targetsize = sizeof(int), | ||
1149 | .family = NF_ARP, | ||
1141 | }; | 1150 | }; |
1142 | 1151 | ||
1143 | static struct arpt_target arpt_error_target = { | 1152 | static struct arpt_target arpt_error_target = { |
1144 | .name = ARPT_ERROR_TARGET, | 1153 | .name = ARPT_ERROR_TARGET, |
1145 | .target = arpt_error, | 1154 | .target = arpt_error, |
1155 | .targetsize = ARPT_FUNCTION_MAXNAMELEN, | ||
1156 | .family = NF_ARP, | ||
1146 | }; | 1157 | }; |
1147 | 1158 | ||
1148 | static struct nf_sockopt_ops arpt_sockopts = { | 1159 | static struct nf_sockopt_ops arpt_sockopts = { |
@@ -1162,8 +1173,8 @@ static int __init init(void) | |||
1162 | xt_proto_init(NF_ARP); | 1173 | xt_proto_init(NF_ARP); |
1163 | 1174 | ||
1164 | /* Noone else will be downing sem now, so we won't sleep */ | 1175 | /* Noone else will be downing sem now, so we won't sleep */ |
1165 | xt_register_target(NF_ARP, &arpt_standard_target); | 1176 | xt_register_target(&arpt_standard_target); |
1166 | xt_register_target(NF_ARP, &arpt_error_target); | 1177 | xt_register_target(&arpt_error_target); |
1167 | 1178 | ||
1168 | /* Register setsockopt */ | 1179 | /* Register setsockopt */ |
1169 | ret = nf_register_sockopt(&arpt_sockopts); | 1180 | ret = nf_register_sockopt(&arpt_sockopts); |
diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c index c97650a16a5b..0f2a95350e26 100644 --- a/net/ipv4/netfilter/arpt_mangle.c +++ b/net/ipv4/netfilter/arpt_mangle.c | |||
@@ -8,9 +8,10 @@ MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>"); | |||
8 | MODULE_DESCRIPTION("arptables arp payload mangle target"); | 8 | MODULE_DESCRIPTION("arptables arp payload mangle target"); |
9 | 9 | ||
10 | static unsigned int | 10 | static unsigned int |
11 | target(struct sk_buff **pskb, const struct net_device *in, | 11 | target(struct sk_buff **pskb, |
12 | const struct net_device *out, unsigned int hooknum, const void *targinfo, | 12 | const struct net_device *in, const struct net_device *out, |
13 | void *userinfo) | 13 | unsigned int hooknum, const struct xt_target *target, |
14 | const void *targinfo, void *userinfo) | ||
14 | { | 15 | { |
15 | const struct arpt_mangle *mangle = targinfo; | 16 | const struct arpt_mangle *mangle = targinfo; |
16 | struct arphdr *arp; | 17 | struct arphdr *arp; |
@@ -65,8 +66,8 @@ target(struct sk_buff **pskb, const struct net_device *in, | |||
65 | } | 66 | } |
66 | 67 | ||
67 | static int | 68 | static int |
68 | checkentry(const char *tablename, const void *e, void *targinfo, | 69 | checkentry(const char *tablename, const void *e, const struct xt_target *target, |
69 | unsigned int targinfosize, unsigned int hook_mask) | 70 | void *targinfo, unsigned int targinfosize, unsigned int hook_mask) |
70 | { | 71 | { |
71 | const struct arpt_mangle *mangle = targinfo; | 72 | const struct arpt_mangle *mangle = targinfo; |
72 | 73 | ||
@@ -80,12 +81,12 @@ checkentry(const char *tablename, const void *e, void *targinfo, | |||
80 | return 1; | 81 | return 1; |
81 | } | 82 | } |
82 | 83 | ||
83 | static struct arpt_target arpt_mangle_reg | 84 | static struct arpt_target arpt_mangle_reg = { |
84 | = { | 85 | .name = "mangle", |
85 | .name = "mangle", | 86 | .target = target, |
86 | .target = target, | 87 | .targetsize = sizeof(struct arpt_mangle), |
87 | .checkentry = checkentry, | 88 | .checkentry = checkentry, |
88 | .me = THIS_MODULE, | 89 | .me = THIS_MODULE, |
89 | }; | 90 | }; |
90 | 91 | ||
91 | static int __init init(void) | 92 | static int __init init(void) |
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 84c66dbfedaf..9e34034729a6 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c | |||
@@ -77,8 +77,8 @@ unsigned int ip_ct_log_invalid; | |||
77 | static LIST_HEAD(unconfirmed); | 77 | static LIST_HEAD(unconfirmed); |
78 | static int ip_conntrack_vmalloc; | 78 | static int ip_conntrack_vmalloc; |
79 | 79 | ||
80 | static unsigned int ip_conntrack_next_id = 1; | 80 | static unsigned int ip_conntrack_next_id; |
81 | static unsigned int ip_conntrack_expect_next_id = 1; | 81 | static unsigned int ip_conntrack_expect_next_id; |
82 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | 82 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS |
83 | struct notifier_block *ip_conntrack_chain; | 83 | struct notifier_block *ip_conntrack_chain; |
84 | struct notifier_block *ip_conntrack_expect_chain; | 84 | struct notifier_block *ip_conntrack_expect_chain; |
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c new file mode 100644 index 000000000000..daeb1395faa4 --- /dev/null +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c | |||
@@ -0,0 +1,1731 @@ | |||
1 | /* | ||
2 | * H.323 connection tracking helper | ||
3 | * | ||
4 | * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net> | ||
5 | * | ||
6 | * This source code is licensed under General Public License version 2. | ||
7 | * | ||
8 | * Based on the 'brute force' H.323 connection tracking module by | ||
9 | * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | ||
10 | * | ||
11 | * For more information, please see http://nath323.sourceforge.net/ | ||
12 | * | ||
13 | * Changes: | ||
14 | * 2006-02-01 - initial version 0.1 | ||
15 | * | ||
16 | * 2006-02-20 - version 0.2 | ||
17 | * 1. Changed source format to follow kernel conventions | ||
18 | * 2. Deleted some unnecessary structures | ||
19 | * 3. Minor fixes | ||
20 | * | ||
21 | * 2006-03-10 - version 0.3 | ||
22 | * 1. Added support for multiple TPKTs in one packet (suggested by | ||
23 | * Patrick McHardy) | ||
24 | * 2. Avoid excessive stack usage (based on Patrick McHardy's patch) | ||
25 | * 3. Added support for non-linear skb (based on Patrick McHardy's patch) | ||
26 | * 4. Fixed missing H.245 module owner (Patrick McHardy) | ||
27 | * 5. Avoid long RAS expectation chains (Patrick McHardy) | ||
28 | * 6. Fixed incorrect __exit attribute (Patrick McHardy) | ||
29 | * 7. Eliminated unnecessary return code | ||
30 | * 8. Fixed incorrect use of NAT data from conntrack code (suggested by | ||
31 | * Patrick McHardy) | ||
32 | * 9. Fixed TTL calculation error in RCF | ||
33 | * 10. Added TTL support in RRQ | ||
34 | * 11. Better support for separate TPKT header and data | ||
35 | * | ||
36 | * 2006-03-15 - version 0.4 | ||
37 | * 1. Added support for T.120 channels | ||
38 | * 2. Added parameter gkrouted_only (suggested by Patrick McHardy) | ||
39 | * 3. Splitted ASN.1 code and data (suggested by Patrick McHardy) | ||
40 | * 4. Sort ASN.1 data to avoid forwarding declarations (suggested by | ||
41 | * Patrick McHardy) | ||
42 | * 5. Reset next TPKT data length in get_tpkt_data() | ||
43 | */ | ||
44 | |||
45 | #include <linux/config.h> | ||
46 | #include <linux/module.h> | ||
47 | #include <linux/netfilter.h> | ||
48 | #include <linux/ip.h> | ||
49 | #include <net/tcp.h> | ||
50 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
51 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | ||
52 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
53 | #include <linux/netfilter_ipv4/ip_conntrack_tuple.h> | ||
54 | #include <linux/netfilter_ipv4/ip_conntrack_h323.h> | ||
55 | #include <linux/moduleparam.h> | ||
56 | |||
57 | #include "ip_conntrack_helper_h323_asn1.h" | ||
58 | |||
59 | #if 0 | ||
60 | #define DEBUGP printk | ||
61 | #else | ||
62 | #define DEBUGP(format, args...) | ||
63 | #endif | ||
64 | |||
65 | /* Parameters */ | ||
66 | static int gkrouted_only = 1; | ||
67 | module_param(gkrouted_only, int, 0600); | ||
68 | MODULE_PARM_DESC(gkrouted_only, "only accept calls from gatekeeper"); | ||
69 | |||
70 | /* Hooks for NAT */ | ||
71 | int (*set_h245_addr_hook) (struct sk_buff ** pskb, | ||
72 | unsigned char **data, int dataoff, | ||
73 | H245_TransportAddress * addr, | ||
74 | u_int32_t ip, u_int16_t port); | ||
75 | int (*set_h225_addr_hook) (struct sk_buff ** pskb, | ||
76 | unsigned char **data, int dataoff, | ||
77 | TransportAddress * addr, | ||
78 | u_int32_t ip, u_int16_t port); | ||
79 | int (*set_sig_addr_hook) (struct sk_buff ** pskb, | ||
80 | struct ip_conntrack * ct, | ||
81 | enum ip_conntrack_info ctinfo, | ||
82 | unsigned char **data, | ||
83 | TransportAddress * addr, int count); | ||
84 | int (*set_ras_addr_hook) (struct sk_buff ** pskb, | ||
85 | struct ip_conntrack * ct, | ||
86 | enum ip_conntrack_info ctinfo, | ||
87 | unsigned char **data, | ||
88 | TransportAddress * addr, int count); | ||
89 | int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb, | ||
90 | struct ip_conntrack * ct, | ||
91 | enum ip_conntrack_info ctinfo, | ||
92 | unsigned char **data, int dataoff, | ||
93 | H245_TransportAddress * addr, | ||
94 | u_int16_t port, u_int16_t rtp_port, | ||
95 | struct ip_conntrack_expect * rtp_exp, | ||
96 | struct ip_conntrack_expect * rtcp_exp); | ||
97 | int (*nat_t120_hook) (struct sk_buff ** pskb, | ||
98 | struct ip_conntrack * ct, | ||
99 | enum ip_conntrack_info ctinfo, | ||
100 | unsigned char **data, int dataoff, | ||
101 | H245_TransportAddress * addr, u_int16_t port, | ||
102 | struct ip_conntrack_expect * exp); | ||
103 | int (*nat_h245_hook) (struct sk_buff ** pskb, | ||
104 | struct ip_conntrack * ct, | ||
105 | enum ip_conntrack_info ctinfo, | ||
106 | unsigned char **data, int dataoff, | ||
107 | TransportAddress * addr, u_int16_t port, | ||
108 | struct ip_conntrack_expect * exp); | ||
109 | int (*nat_q931_hook) (struct sk_buff ** pskb, | ||
110 | struct ip_conntrack * ct, | ||
111 | enum ip_conntrack_info ctinfo, | ||
112 | unsigned char **data, TransportAddress * addr, int idx, | ||
113 | u_int16_t port, struct ip_conntrack_expect * exp); | ||
114 | |||
115 | |||
116 | static DEFINE_SPINLOCK(ip_h323_lock); | ||
117 | static char *h323_buffer; | ||
118 | |||
119 | /****************************************************************************/ | ||
120 | static int get_tpkt_data(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
121 | enum ip_conntrack_info ctinfo, | ||
122 | unsigned char **data, int *datalen, int *dataoff) | ||
123 | { | ||
124 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
125 | int dir = CTINFO2DIR(ctinfo); | ||
126 | struct tcphdr _tcph, *th; | ||
127 | int tcpdatalen; | ||
128 | int tcpdataoff; | ||
129 | unsigned char *tpkt; | ||
130 | int tpktlen; | ||
131 | int tpktoff; | ||
132 | |||
133 | /* Get TCP header */ | ||
134 | th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4, | ||
135 | sizeof(_tcph), &_tcph); | ||
136 | if (th == NULL) | ||
137 | return 0; | ||
138 | |||
139 | /* Get TCP data offset */ | ||
140 | tcpdataoff = (*pskb)->nh.iph->ihl * 4 + th->doff * 4; | ||
141 | |||
142 | /* Get TCP data length */ | ||
143 | tcpdatalen = (*pskb)->len - tcpdataoff; | ||
144 | if (tcpdatalen <= 0) /* No TCP data */ | ||
145 | goto clear_out; | ||
146 | |||
147 | if (*data == NULL) { /* first TPKT */ | ||
148 | /* Get first TPKT pointer */ | ||
149 | tpkt = skb_header_pointer(*pskb, tcpdataoff, tcpdatalen, | ||
150 | h323_buffer); | ||
151 | BUG_ON(tpkt == NULL); | ||
152 | |||
153 | /* Validate TPKT identifier */ | ||
154 | if (tcpdatalen < 4 || tpkt[0] != 0x03 || tpkt[1] != 0) { | ||
155 | /* Netmeeting sends TPKT header and data separately */ | ||
156 | if (info->tpkt_len[dir] > 0) { | ||
157 | DEBUGP("ip_ct_h323: previous packet " | ||
158 | "indicated separate TPKT data of %hu " | ||
159 | "bytes\n", info->tpkt_len[dir]); | ||
160 | if (info->tpkt_len[dir] <= tcpdatalen) { | ||
161 | /* Yes, there was a TPKT header | ||
162 | * received */ | ||
163 | *data = tpkt; | ||
164 | *datalen = info->tpkt_len[dir]; | ||
165 | *dataoff = 0; | ||
166 | goto out; | ||
167 | } | ||
168 | |||
169 | /* Fragmented TPKT */ | ||
170 | if (net_ratelimit()) | ||
171 | printk("ip_ct_h323: " | ||
172 | "fragmented TPKT\n"); | ||
173 | goto clear_out; | ||
174 | } | ||
175 | |||
176 | /* It is not even a TPKT */ | ||
177 | return 0; | ||
178 | } | ||
179 | tpktoff = 0; | ||
180 | } else { /* Next TPKT */ | ||
181 | tpktoff = *dataoff + *datalen; | ||
182 | tcpdatalen -= tpktoff; | ||
183 | if (tcpdatalen <= 4) /* No more TPKT */ | ||
184 | goto clear_out; | ||
185 | tpkt = *data + *datalen; | ||
186 | |||
187 | /* Validate TPKT identifier */ | ||
188 | if (tpkt[0] != 0x03 || tpkt[1] != 0) | ||
189 | goto clear_out; | ||
190 | } | ||
191 | |||
192 | /* Validate TPKT length */ | ||
193 | tpktlen = tpkt[2] * 256 + tpkt[3]; | ||
194 | if (tpktlen > tcpdatalen) { | ||
195 | if (tcpdatalen == 4) { /* Separate TPKT header */ | ||
196 | /* Netmeeting sends TPKT header and data separately */ | ||
197 | DEBUGP("ip_ct_h323: separate TPKT header indicates " | ||
198 | "there will be TPKT data of %hu bytes\n", | ||
199 | tpktlen - 4); | ||
200 | info->tpkt_len[dir] = tpktlen - 4; | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | if (net_ratelimit()) | ||
205 | printk("ip_ct_h323: incomplete TPKT (fragmented?)\n"); | ||
206 | goto clear_out; | ||
207 | } | ||
208 | |||
209 | /* This is the encapsulated data */ | ||
210 | *data = tpkt + 4; | ||
211 | *datalen = tpktlen - 4; | ||
212 | *dataoff = tpktoff + 4; | ||
213 | |||
214 | out: | ||
215 | /* Clear TPKT length */ | ||
216 | info->tpkt_len[dir] = 0; | ||
217 | return 1; | ||
218 | |||
219 | clear_out: | ||
220 | info->tpkt_len[dir] = 0; | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | /****************************************************************************/ | ||
225 | int get_h245_addr(unsigned char *data, H245_TransportAddress * addr, | ||
226 | u_int32_t * ip, u_int16_t * port) | ||
227 | { | ||
228 | unsigned char *p; | ||
229 | |||
230 | if (addr->choice != eH245_TransportAddress_unicastAddress || | ||
231 | addr->unicastAddress.choice != eUnicastAddress_iPAddress) | ||
232 | return 0; | ||
233 | |||
234 | p = data + addr->unicastAddress.iPAddress.network; | ||
235 | *ip = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3])); | ||
236 | *port = (p[4] << 8) | (p[5]); | ||
237 | |||
238 | return 1; | ||
239 | } | ||
240 | |||
241 | /****************************************************************************/ | ||
242 | static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
243 | enum ip_conntrack_info ctinfo, | ||
244 | unsigned char **data, int dataoff, | ||
245 | H245_TransportAddress * addr) | ||
246 | { | ||
247 | int dir = CTINFO2DIR(ctinfo); | ||
248 | int ret = 0; | ||
249 | u_int32_t ip; | ||
250 | u_int16_t port; | ||
251 | u_int16_t rtp_port; | ||
252 | struct ip_conntrack_expect *rtp_exp; | ||
253 | struct ip_conntrack_expect *rtcp_exp; | ||
254 | |||
255 | /* Read RTP or RTCP address */ | ||
256 | if (!get_h245_addr(*data, addr, &ip, &port) || | ||
257 | ip != ct->tuplehash[dir].tuple.src.ip || port == 0) | ||
258 | return 0; | ||
259 | |||
260 | /* RTP port is even */ | ||
261 | rtp_port = port & (~1); | ||
262 | |||
263 | /* Create expect for RTP */ | ||
264 | if ((rtp_exp = ip_conntrack_expect_alloc(ct)) == NULL) | ||
265 | return -1; | ||
266 | rtp_exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
267 | rtp_exp->tuple.src.u.udp.port = 0; | ||
268 | rtp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; | ||
269 | rtp_exp->tuple.dst.u.udp.port = htons(rtp_port); | ||
270 | rtp_exp->tuple.dst.protonum = IPPROTO_UDP; | ||
271 | rtp_exp->mask.src.ip = 0xFFFFFFFF; | ||
272 | rtp_exp->mask.src.u.udp.port = 0; | ||
273 | rtp_exp->mask.dst.ip = 0xFFFFFFFF; | ||
274 | rtp_exp->mask.dst.u.udp.port = 0xFFFF; | ||
275 | rtp_exp->mask.dst.protonum = 0xFF; | ||
276 | rtp_exp->flags = 0; | ||
277 | |||
278 | /* Create expect for RTCP */ | ||
279 | if ((rtcp_exp = ip_conntrack_expect_alloc(ct)) == NULL) { | ||
280 | ip_conntrack_expect_put(rtp_exp); | ||
281 | return -1; | ||
282 | } | ||
283 | rtcp_exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
284 | rtcp_exp->tuple.src.u.udp.port = 0; | ||
285 | rtcp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; | ||
286 | rtcp_exp->tuple.dst.u.udp.port = htons(rtp_port + 1); | ||
287 | rtcp_exp->tuple.dst.protonum = IPPROTO_UDP; | ||
288 | rtcp_exp->mask.src.ip = 0xFFFFFFFF; | ||
289 | rtcp_exp->mask.src.u.udp.port = 0; | ||
290 | rtcp_exp->mask.dst.ip = 0xFFFFFFFF; | ||
291 | rtcp_exp->mask.dst.u.udp.port = 0xFFFF; | ||
292 | rtcp_exp->mask.dst.protonum = 0xFF; | ||
293 | rtcp_exp->flags = 0; | ||
294 | |||
295 | if (ct->tuplehash[dir].tuple.src.ip != | ||
296 | ct->tuplehash[!dir].tuple.dst.ip && nat_rtp_rtcp_hook) { | ||
297 | /* NAT needed */ | ||
298 | ret = nat_rtp_rtcp_hook(pskb, ct, ctinfo, data, dataoff, | ||
299 | addr, port, rtp_port, rtp_exp, | ||
300 | rtcp_exp); | ||
301 | } else { /* Conntrack only */ | ||
302 | rtp_exp->expectfn = NULL; | ||
303 | rtcp_exp->expectfn = NULL; | ||
304 | |||
305 | if (ip_conntrack_expect_related(rtp_exp) == 0) { | ||
306 | if (ip_conntrack_expect_related(rtcp_exp) == 0) { | ||
307 | DEBUGP("ip_ct_h323: expect RTP " | ||
308 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
309 | NIPQUAD(rtp_exp->tuple.src.ip), | ||
310 | ntohs(rtp_exp->tuple.src.u.udp.port), | ||
311 | NIPQUAD(rtp_exp->tuple.dst.ip), | ||
312 | ntohs(rtp_exp->tuple.dst.u.udp.port)); | ||
313 | DEBUGP("ip_ct_h323: expect RTCP " | ||
314 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
315 | NIPQUAD(rtcp_exp->tuple.src.ip), | ||
316 | ntohs(rtcp_exp->tuple.src.u.udp.port), | ||
317 | NIPQUAD(rtcp_exp->tuple.dst.ip), | ||
318 | ntohs(rtcp_exp->tuple.dst.u.udp.port)); | ||
319 | } else { | ||
320 | ip_conntrack_unexpect_related(rtp_exp); | ||
321 | ret = -1; | ||
322 | } | ||
323 | } else | ||
324 | ret = -1; | ||
325 | } | ||
326 | |||
327 | ip_conntrack_expect_put(rtp_exp); | ||
328 | ip_conntrack_expect_put(rtcp_exp); | ||
329 | |||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | /****************************************************************************/ | ||
334 | static int expect_t120(struct sk_buff **pskb, | ||
335 | struct ip_conntrack *ct, | ||
336 | enum ip_conntrack_info ctinfo, | ||
337 | unsigned char **data, int dataoff, | ||
338 | H245_TransportAddress * addr) | ||
339 | { | ||
340 | int dir = CTINFO2DIR(ctinfo); | ||
341 | int ret = 0; | ||
342 | u_int32_t ip; | ||
343 | u_int16_t port; | ||
344 | struct ip_conntrack_expect *exp = NULL; | ||
345 | |||
346 | /* Read T.120 address */ | ||
347 | if (!get_h245_addr(*data, addr, &ip, &port) || | ||
348 | ip != ct->tuplehash[dir].tuple.src.ip || port == 0) | ||
349 | return 0; | ||
350 | |||
351 | /* Create expect for T.120 connections */ | ||
352 | if ((exp = ip_conntrack_expect_alloc(ct)) == NULL) | ||
353 | return -1; | ||
354 | exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
355 | exp->tuple.src.u.tcp.port = 0; | ||
356 | exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; | ||
357 | exp->tuple.dst.u.tcp.port = htons(port); | ||
358 | exp->tuple.dst.protonum = IPPROTO_TCP; | ||
359 | exp->mask.src.ip = 0xFFFFFFFF; | ||
360 | exp->mask.src.u.tcp.port = 0; | ||
361 | exp->mask.dst.ip = 0xFFFFFFFF; | ||
362 | exp->mask.dst.u.tcp.port = 0xFFFF; | ||
363 | exp->mask.dst.protonum = 0xFF; | ||
364 | exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple channels */ | ||
365 | |||
366 | if (ct->tuplehash[dir].tuple.src.ip != | ||
367 | ct->tuplehash[!dir].tuple.dst.ip && nat_t120_hook) { | ||
368 | /* NAT needed */ | ||
369 | ret = nat_t120_hook(pskb, ct, ctinfo, data, dataoff, addr, | ||
370 | port, exp); | ||
371 | } else { /* Conntrack only */ | ||
372 | exp->expectfn = NULL; | ||
373 | if (ip_conntrack_expect_related(exp) == 0) { | ||
374 | DEBUGP("ip_ct_h323: expect T.120 " | ||
375 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
376 | NIPQUAD(exp->tuple.src.ip), | ||
377 | ntohs(exp->tuple.src.u.tcp.port), | ||
378 | NIPQUAD(exp->tuple.dst.ip), | ||
379 | ntohs(exp->tuple.dst.u.tcp.port)); | ||
380 | } else | ||
381 | ret = -1; | ||
382 | } | ||
383 | |||
384 | ip_conntrack_expect_put(exp); | ||
385 | |||
386 | return ret; | ||
387 | } | ||
388 | |||
389 | /****************************************************************************/ | ||
390 | static int process_h245_channel(struct sk_buff **pskb, | ||
391 | struct ip_conntrack *ct, | ||
392 | enum ip_conntrack_info ctinfo, | ||
393 | unsigned char **data, int dataoff, | ||
394 | H2250LogicalChannelParameters * channel) | ||
395 | { | ||
396 | int ret; | ||
397 | |||
398 | if (channel->options & eH2250LogicalChannelParameters_mediaChannel) { | ||
399 | /* RTP */ | ||
400 | ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, | ||
401 | &channel->mediaChannel); | ||
402 | if (ret < 0) | ||
403 | return -1; | ||
404 | } | ||
405 | |||
406 | if (channel-> | ||
407 | options & eH2250LogicalChannelParameters_mediaControlChannel) { | ||
408 | /* RTCP */ | ||
409 | ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, | ||
410 | &channel->mediaControlChannel); | ||
411 | if (ret < 0) | ||
412 | return -1; | ||
413 | } | ||
414 | |||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | /****************************************************************************/ | ||
419 | static int process_olc(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
420 | enum ip_conntrack_info ctinfo, | ||
421 | unsigned char **data, int dataoff, | ||
422 | OpenLogicalChannel * olc) | ||
423 | { | ||
424 | int ret; | ||
425 | |||
426 | DEBUGP("ip_ct_h323: OpenLogicalChannel\n"); | ||
427 | |||
428 | if (olc->forwardLogicalChannelParameters.multiplexParameters.choice == | ||
429 | eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters) | ||
430 | { | ||
431 | ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff, | ||
432 | &olc-> | ||
433 | forwardLogicalChannelParameters. | ||
434 | multiplexParameters. | ||
435 | h2250LogicalChannelParameters); | ||
436 | if (ret < 0) | ||
437 | return -1; | ||
438 | } | ||
439 | |||
440 | if ((olc->options & | ||
441 | eOpenLogicalChannel_reverseLogicalChannelParameters) && | ||
442 | (olc->reverseLogicalChannelParameters.options & | ||
443 | eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters) | ||
444 | && (olc->reverseLogicalChannelParameters.multiplexParameters. | ||
445 | choice == | ||
446 | eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters)) | ||
447 | { | ||
448 | ret = | ||
449 | process_h245_channel(pskb, ct, ctinfo, data, dataoff, | ||
450 | &olc-> | ||
451 | reverseLogicalChannelParameters. | ||
452 | multiplexParameters. | ||
453 | h2250LogicalChannelParameters); | ||
454 | if (ret < 0) | ||
455 | return -1; | ||
456 | } | ||
457 | |||
458 | if ((olc->options & eOpenLogicalChannel_separateStack) && | ||
459 | olc->forwardLogicalChannelParameters.dataType.choice == | ||
460 | eDataType_data && | ||
461 | olc->forwardLogicalChannelParameters.dataType.data.application. | ||
462 | choice == eDataApplicationCapability_application_t120 && | ||
463 | olc->forwardLogicalChannelParameters.dataType.data.application. | ||
464 | t120.choice == eDataProtocolCapability_separateLANStack && | ||
465 | olc->separateStack.networkAddress.choice == | ||
466 | eNetworkAccessParameters_networkAddress_localAreaAddress) { | ||
467 | ret = expect_t120(pskb, ct, ctinfo, data, dataoff, | ||
468 | &olc->separateStack.networkAddress. | ||
469 | localAreaAddress); | ||
470 | if (ret < 0) | ||
471 | return -1; | ||
472 | } | ||
473 | |||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | /****************************************************************************/ | ||
478 | static int process_olca(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
479 | enum ip_conntrack_info ctinfo, | ||
480 | unsigned char **data, int dataoff, | ||
481 | OpenLogicalChannelAck * olca) | ||
482 | { | ||
483 | H2250LogicalChannelAckParameters *ack; | ||
484 | int ret; | ||
485 | |||
486 | DEBUGP("ip_ct_h323: OpenLogicalChannelAck\n"); | ||
487 | |||
488 | if ((olca->options & | ||
489 | eOpenLogicalChannelAck_reverseLogicalChannelParameters) && | ||
490 | (olca->reverseLogicalChannelParameters.options & | ||
491 | eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters) | ||
492 | && (olca->reverseLogicalChannelParameters.multiplexParameters. | ||
493 | choice == | ||
494 | eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters)) | ||
495 | { | ||
496 | ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff, | ||
497 | &olca-> | ||
498 | reverseLogicalChannelParameters. | ||
499 | multiplexParameters. | ||
500 | h2250LogicalChannelParameters); | ||
501 | if (ret < 0) | ||
502 | return -1; | ||
503 | } | ||
504 | |||
505 | if ((olca->options & | ||
506 | eOpenLogicalChannelAck_forwardMultiplexAckParameters) && | ||
507 | (olca->forwardMultiplexAckParameters.choice == | ||
508 | eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters)) | ||
509 | { | ||
510 | ack = &olca->forwardMultiplexAckParameters. | ||
511 | h2250LogicalChannelAckParameters; | ||
512 | if (ack->options & | ||
513 | eH2250LogicalChannelAckParameters_mediaChannel) { | ||
514 | /* RTP */ | ||
515 | ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, | ||
516 | &ack->mediaChannel); | ||
517 | if (ret < 0) | ||
518 | return -1; | ||
519 | } | ||
520 | |||
521 | if (ack->options & | ||
522 | eH2250LogicalChannelAckParameters_mediaControlChannel) { | ||
523 | /* RTCP */ | ||
524 | ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, | ||
525 | &ack->mediaControlChannel); | ||
526 | if (ret < 0) | ||
527 | return -1; | ||
528 | } | ||
529 | } | ||
530 | |||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | /****************************************************************************/ | ||
535 | static int process_h245(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
536 | enum ip_conntrack_info ctinfo, | ||
537 | unsigned char **data, int dataoff, | ||
538 | MultimediaSystemControlMessage * mscm) | ||
539 | { | ||
540 | switch (mscm->choice) { | ||
541 | case eMultimediaSystemControlMessage_request: | ||
542 | if (mscm->request.choice == | ||
543 | eRequestMessage_openLogicalChannel) { | ||
544 | return process_olc(pskb, ct, ctinfo, data, dataoff, | ||
545 | &mscm->request.openLogicalChannel); | ||
546 | } | ||
547 | DEBUGP("ip_ct_h323: H.245 Request %d\n", | ||
548 | mscm->request.choice); | ||
549 | break; | ||
550 | case eMultimediaSystemControlMessage_response: | ||
551 | if (mscm->response.choice == | ||
552 | eResponseMessage_openLogicalChannelAck) { | ||
553 | return process_olca(pskb, ct, ctinfo, data, dataoff, | ||
554 | &mscm->response. | ||
555 | openLogicalChannelAck); | ||
556 | } | ||
557 | DEBUGP("ip_ct_h323: H.245 Response %d\n", | ||
558 | mscm->response.choice); | ||
559 | break; | ||
560 | default: | ||
561 | DEBUGP("ip_ct_h323: H.245 signal %d\n", mscm->choice); | ||
562 | break; | ||
563 | } | ||
564 | |||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | /****************************************************************************/ | ||
569 | static int h245_help(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
570 | enum ip_conntrack_info ctinfo) | ||
571 | { | ||
572 | static MultimediaSystemControlMessage mscm; | ||
573 | unsigned char *data = NULL; | ||
574 | int datalen; | ||
575 | int dataoff; | ||
576 | int ret; | ||
577 | |||
578 | /* Until there's been traffic both ways, don't look in packets. */ | ||
579 | if (ctinfo != IP_CT_ESTABLISHED | ||
580 | && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { | ||
581 | return NF_ACCEPT; | ||
582 | } | ||
583 | DEBUGP("ip_ct_h245: skblen = %u\n", (*pskb)->len); | ||
584 | |||
585 | spin_lock_bh(&ip_h323_lock); | ||
586 | |||
587 | /* Process each TPKT */ | ||
588 | while (get_tpkt_data(pskb, ct, ctinfo, &data, &datalen, &dataoff)) { | ||
589 | DEBUGP("ip_ct_h245: TPKT %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n", | ||
590 | NIPQUAD((*pskb)->nh.iph->saddr), | ||
591 | NIPQUAD((*pskb)->nh.iph->daddr), datalen); | ||
592 | |||
593 | /* Decode H.245 signal */ | ||
594 | ret = DecodeMultimediaSystemControlMessage(data, datalen, | ||
595 | &mscm); | ||
596 | if (ret < 0) { | ||
597 | if (net_ratelimit()) | ||
598 | printk("ip_ct_h245: decoding error: %s\n", | ||
599 | ret == H323_ERROR_BOUND ? | ||
600 | "out of bound" : "out of range"); | ||
601 | /* We don't drop when decoding error */ | ||
602 | break; | ||
603 | } | ||
604 | |||
605 | /* Process H.245 signal */ | ||
606 | if (process_h245(pskb, ct, ctinfo, &data, dataoff, &mscm) < 0) | ||
607 | goto drop; | ||
608 | } | ||
609 | |||
610 | spin_unlock_bh(&ip_h323_lock); | ||
611 | return NF_ACCEPT; | ||
612 | |||
613 | drop: | ||
614 | spin_unlock_bh(&ip_h323_lock); | ||
615 | if (net_ratelimit()) | ||
616 | printk("ip_ct_h245: packet dropped\n"); | ||
617 | return NF_DROP; | ||
618 | } | ||
619 | |||
620 | /****************************************************************************/ | ||
621 | static struct ip_conntrack_helper ip_conntrack_helper_h245 = { | ||
622 | .name = "H.245", | ||
623 | .me = THIS_MODULE, | ||
624 | .max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */ , | ||
625 | .timeout = 240, | ||
626 | .tuple = {.dst = {.protonum = IPPROTO_TCP}}, | ||
627 | .mask = {.src = {.u = {0xFFFF}}, | ||
628 | .dst = {.protonum = 0xFF}}, | ||
629 | .help = h245_help | ||
630 | }; | ||
631 | |||
632 | /****************************************************************************/ | ||
633 | void ip_conntrack_h245_expect(struct ip_conntrack *new, | ||
634 | struct ip_conntrack_expect *this) | ||
635 | { | ||
636 | write_lock_bh(&ip_conntrack_lock); | ||
637 | new->helper = &ip_conntrack_helper_h245; | ||
638 | write_unlock_bh(&ip_conntrack_lock); | ||
639 | } | ||
640 | |||
641 | /****************************************************************************/ | ||
642 | int get_h225_addr(unsigned char *data, TransportAddress * addr, | ||
643 | u_int32_t * ip, u_int16_t * port) | ||
644 | { | ||
645 | unsigned char *p; | ||
646 | |||
647 | if (addr->choice != eTransportAddress_ipAddress) | ||
648 | return 0; | ||
649 | |||
650 | p = data + addr->ipAddress.ip; | ||
651 | *ip = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3])); | ||
652 | *port = (p[4] << 8) | (p[5]); | ||
653 | |||
654 | return 1; | ||
655 | } | ||
656 | |||
657 | /****************************************************************************/ | ||
658 | static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
659 | enum ip_conntrack_info ctinfo, | ||
660 | unsigned char **data, int dataoff, | ||
661 | TransportAddress * addr) | ||
662 | { | ||
663 | int dir = CTINFO2DIR(ctinfo); | ||
664 | int ret = 0; | ||
665 | u_int32_t ip; | ||
666 | u_int16_t port; | ||
667 | struct ip_conntrack_expect *exp = NULL; | ||
668 | |||
669 | /* Read h245Address */ | ||
670 | if (!get_h225_addr(*data, addr, &ip, &port) || | ||
671 | ip != ct->tuplehash[dir].tuple.src.ip || port == 0) | ||
672 | return 0; | ||
673 | |||
674 | /* Create expect for h245 connection */ | ||
675 | if ((exp = ip_conntrack_expect_alloc(ct)) == NULL) | ||
676 | return -1; | ||
677 | exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
678 | exp->tuple.src.u.tcp.port = 0; | ||
679 | exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; | ||
680 | exp->tuple.dst.u.tcp.port = htons(port); | ||
681 | exp->tuple.dst.protonum = IPPROTO_TCP; | ||
682 | exp->mask.src.ip = 0xFFFFFFFF; | ||
683 | exp->mask.src.u.tcp.port = 0; | ||
684 | exp->mask.dst.ip = 0xFFFFFFFF; | ||
685 | exp->mask.dst.u.tcp.port = 0xFFFF; | ||
686 | exp->mask.dst.protonum = 0xFF; | ||
687 | exp->flags = 0; | ||
688 | |||
689 | if (ct->tuplehash[dir].tuple.src.ip != | ||
690 | ct->tuplehash[!dir].tuple.dst.ip && nat_h245_hook) { | ||
691 | /* NAT needed */ | ||
692 | ret = nat_h245_hook(pskb, ct, ctinfo, data, dataoff, addr, | ||
693 | port, exp); | ||
694 | } else { /* Conntrack only */ | ||
695 | exp->expectfn = ip_conntrack_h245_expect; | ||
696 | |||
697 | if (ip_conntrack_expect_related(exp) == 0) { | ||
698 | DEBUGP("ip_ct_q931: expect H.245 " | ||
699 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
700 | NIPQUAD(exp->tuple.src.ip), | ||
701 | ntohs(exp->tuple.src.u.tcp.port), | ||
702 | NIPQUAD(exp->tuple.dst.ip), | ||
703 | ntohs(exp->tuple.dst.u.tcp.port)); | ||
704 | } else | ||
705 | ret = -1; | ||
706 | } | ||
707 | |||
708 | ip_conntrack_expect_put(exp); | ||
709 | |||
710 | return ret; | ||
711 | } | ||
712 | |||
713 | /****************************************************************************/ | ||
714 | static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
715 | enum ip_conntrack_info ctinfo, | ||
716 | unsigned char **data, int dataoff, | ||
717 | Setup_UUIE * setup) | ||
718 | { | ||
719 | int dir = CTINFO2DIR(ctinfo); | ||
720 | int ret; | ||
721 | int i; | ||
722 | u_int32_t ip; | ||
723 | u_int16_t port; | ||
724 | |||
725 | DEBUGP("ip_ct_q931: Setup\n"); | ||
726 | |||
727 | if (setup->options & eSetup_UUIE_h245Address) { | ||
728 | ret = expect_h245(pskb, ct, ctinfo, data, dataoff, | ||
729 | &setup->h245Address); | ||
730 | if (ret < 0) | ||
731 | return -1; | ||
732 | } | ||
733 | |||
734 | if ((setup->options & eSetup_UUIE_destCallSignalAddress) && | ||
735 | (set_h225_addr_hook) && | ||
736 | get_h225_addr(*data, &setup->destCallSignalAddress, &ip, &port) && | ||
737 | ip != ct->tuplehash[!dir].tuple.src.ip) { | ||
738 | DEBUGP("ip_ct_q931: set destCallSignalAddress " | ||
739 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
740 | NIPQUAD(ip), port, | ||
741 | NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), | ||
742 | ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port)); | ||
743 | ret = set_h225_addr_hook(pskb, data, dataoff, | ||
744 | &setup->destCallSignalAddress, | ||
745 | ct->tuplehash[!dir].tuple.src.ip, | ||
746 | ntohs(ct->tuplehash[!dir].tuple.src. | ||
747 | u.tcp.port)); | ||
748 | if (ret < 0) | ||
749 | return -1; | ||
750 | } | ||
751 | |||
752 | if ((setup->options & eSetup_UUIE_sourceCallSignalAddress) && | ||
753 | (set_h225_addr_hook) && | ||
754 | get_h225_addr(*data, &setup->sourceCallSignalAddress, &ip, &port) | ||
755 | && ip != ct->tuplehash[!dir].tuple.dst.ip) { | ||
756 | DEBUGP("ip_ct_q931: set sourceCallSignalAddress " | ||
757 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
758 | NIPQUAD(ip), port, | ||
759 | NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip), | ||
760 | ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port)); | ||
761 | ret = set_h225_addr_hook(pskb, data, dataoff, | ||
762 | &setup->sourceCallSignalAddress, | ||
763 | ct->tuplehash[!dir].tuple.dst.ip, | ||
764 | ntohs(ct->tuplehash[!dir].tuple.dst. | ||
765 | u.tcp.port)); | ||
766 | if (ret < 0) | ||
767 | return -1; | ||
768 | } | ||
769 | |||
770 | if (setup->options & eSetup_UUIE_fastStart) { | ||
771 | for (i = 0; i < setup->fastStart.count; i++) { | ||
772 | ret = process_olc(pskb, ct, ctinfo, data, dataoff, | ||
773 | &setup->fastStart.item[i]); | ||
774 | if (ret < 0) | ||
775 | return -1; | ||
776 | } | ||
777 | } | ||
778 | |||
779 | return 0; | ||
780 | } | ||
781 | |||
782 | /****************************************************************************/ | ||
783 | static int process_callproceeding(struct sk_buff **pskb, | ||
784 | struct ip_conntrack *ct, | ||
785 | enum ip_conntrack_info ctinfo, | ||
786 | unsigned char **data, int dataoff, | ||
787 | CallProceeding_UUIE * callproc) | ||
788 | { | ||
789 | int ret; | ||
790 | int i; | ||
791 | |||
792 | DEBUGP("ip_ct_q931: CallProceeding\n"); | ||
793 | |||
794 | if (callproc->options & eCallProceeding_UUIE_h245Address) { | ||
795 | ret = expect_h245(pskb, ct, ctinfo, data, dataoff, | ||
796 | &callproc->h245Address); | ||
797 | if (ret < 0) | ||
798 | return -1; | ||
799 | } | ||
800 | |||
801 | if (callproc->options & eCallProceeding_UUIE_fastStart) { | ||
802 | for (i = 0; i < callproc->fastStart.count; i++) { | ||
803 | ret = process_olc(pskb, ct, ctinfo, data, dataoff, | ||
804 | &callproc->fastStart.item[i]); | ||
805 | if (ret < 0) | ||
806 | return -1; | ||
807 | } | ||
808 | } | ||
809 | |||
810 | return 0; | ||
811 | } | ||
812 | |||
813 | /****************************************************************************/ | ||
814 | static int process_connect(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
815 | enum ip_conntrack_info ctinfo, | ||
816 | unsigned char **data, int dataoff, | ||
817 | Connect_UUIE * connect) | ||
818 | { | ||
819 | int ret; | ||
820 | int i; | ||
821 | |||
822 | DEBUGP("ip_ct_q931: Connect\n"); | ||
823 | |||
824 | if (connect->options & eConnect_UUIE_h245Address) { | ||
825 | ret = expect_h245(pskb, ct, ctinfo, data, dataoff, | ||
826 | &connect->h245Address); | ||
827 | if (ret < 0) | ||
828 | return -1; | ||
829 | } | ||
830 | |||
831 | if (connect->options & eConnect_UUIE_fastStart) { | ||
832 | for (i = 0; i < connect->fastStart.count; i++) { | ||
833 | ret = process_olc(pskb, ct, ctinfo, data, dataoff, | ||
834 | &connect->fastStart.item[i]); | ||
835 | if (ret < 0) | ||
836 | return -1; | ||
837 | } | ||
838 | } | ||
839 | |||
840 | return 0; | ||
841 | } | ||
842 | |||
843 | /****************************************************************************/ | ||
844 | static int process_alerting(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
845 | enum ip_conntrack_info ctinfo, | ||
846 | unsigned char **data, int dataoff, | ||
847 | Alerting_UUIE * alert) | ||
848 | { | ||
849 | int ret; | ||
850 | int i; | ||
851 | |||
852 | DEBUGP("ip_ct_q931: Alerting\n"); | ||
853 | |||
854 | if (alert->options & eAlerting_UUIE_h245Address) { | ||
855 | ret = expect_h245(pskb, ct, ctinfo, data, dataoff, | ||
856 | &alert->h245Address); | ||
857 | if (ret < 0) | ||
858 | return -1; | ||
859 | } | ||
860 | |||
861 | if (alert->options & eAlerting_UUIE_fastStart) { | ||
862 | for (i = 0; i < alert->fastStart.count; i++) { | ||
863 | ret = process_olc(pskb, ct, ctinfo, data, dataoff, | ||
864 | &alert->fastStart.item[i]); | ||
865 | if (ret < 0) | ||
866 | return -1; | ||
867 | } | ||
868 | } | ||
869 | |||
870 | return 0; | ||
871 | } | ||
872 | |||
873 | /****************************************************************************/ | ||
874 | static int process_information(struct sk_buff **pskb, | ||
875 | struct ip_conntrack *ct, | ||
876 | enum ip_conntrack_info ctinfo, | ||
877 | unsigned char **data, int dataoff, | ||
878 | Information_UUIE * info) | ||
879 | { | ||
880 | int ret; | ||
881 | int i; | ||
882 | |||
883 | DEBUGP("ip_ct_q931: Information\n"); | ||
884 | |||
885 | if (info->options & eInformation_UUIE_fastStart) { | ||
886 | for (i = 0; i < info->fastStart.count; i++) { | ||
887 | ret = process_olc(pskb, ct, ctinfo, data, dataoff, | ||
888 | &info->fastStart.item[i]); | ||
889 | if (ret < 0) | ||
890 | return -1; | ||
891 | } | ||
892 | } | ||
893 | |||
894 | return 0; | ||
895 | } | ||
896 | |||
897 | /****************************************************************************/ | ||
898 | static int process_facility(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
899 | enum ip_conntrack_info ctinfo, | ||
900 | unsigned char **data, int dataoff, | ||
901 | Facility_UUIE * facility) | ||
902 | { | ||
903 | int ret; | ||
904 | int i; | ||
905 | |||
906 | DEBUGP("ip_ct_q931: Facility\n"); | ||
907 | |||
908 | if (facility->options & eFacility_UUIE_h245Address) { | ||
909 | ret = expect_h245(pskb, ct, ctinfo, data, dataoff, | ||
910 | &facility->h245Address); | ||
911 | if (ret < 0) | ||
912 | return -1; | ||
913 | } | ||
914 | |||
915 | if (facility->options & eFacility_UUIE_fastStart) { | ||
916 | for (i = 0; i < facility->fastStart.count; i++) { | ||
917 | ret = process_olc(pskb, ct, ctinfo, data, dataoff, | ||
918 | &facility->fastStart.item[i]); | ||
919 | if (ret < 0) | ||
920 | return -1; | ||
921 | } | ||
922 | } | ||
923 | |||
924 | return 0; | ||
925 | } | ||
926 | |||
927 | /****************************************************************************/ | ||
928 | static int process_progress(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
929 | enum ip_conntrack_info ctinfo, | ||
930 | unsigned char **data, int dataoff, | ||
931 | Progress_UUIE * progress) | ||
932 | { | ||
933 | int ret; | ||
934 | int i; | ||
935 | |||
936 | DEBUGP("ip_ct_q931: Progress\n"); | ||
937 | |||
938 | if (progress->options & eProgress_UUIE_h245Address) { | ||
939 | ret = expect_h245(pskb, ct, ctinfo, data, dataoff, | ||
940 | &progress->h245Address); | ||
941 | if (ret < 0) | ||
942 | return -1; | ||
943 | } | ||
944 | |||
945 | if (progress->options & eProgress_UUIE_fastStart) { | ||
946 | for (i = 0; i < progress->fastStart.count; i++) { | ||
947 | ret = process_olc(pskb, ct, ctinfo, data, dataoff, | ||
948 | &progress->fastStart.item[i]); | ||
949 | if (ret < 0) | ||
950 | return -1; | ||
951 | } | ||
952 | } | ||
953 | |||
954 | return 0; | ||
955 | } | ||
956 | |||
957 | /****************************************************************************/ | ||
958 | static int process_q931(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
959 | enum ip_conntrack_info ctinfo, | ||
960 | unsigned char **data, int dataoff, Q931 * q931) | ||
961 | { | ||
962 | H323_UU_PDU *pdu = &q931->UUIE.h323_uu_pdu; | ||
963 | int i; | ||
964 | int ret = 0; | ||
965 | |||
966 | switch (pdu->h323_message_body.choice) { | ||
967 | case eH323_UU_PDU_h323_message_body_setup: | ||
968 | ret = process_setup(pskb, ct, ctinfo, data, dataoff, | ||
969 | &pdu->h323_message_body.setup); | ||
970 | break; | ||
971 | case eH323_UU_PDU_h323_message_body_callProceeding: | ||
972 | ret = process_callproceeding(pskb, ct, ctinfo, data, dataoff, | ||
973 | &pdu->h323_message_body. | ||
974 | callProceeding); | ||
975 | break; | ||
976 | case eH323_UU_PDU_h323_message_body_connect: | ||
977 | ret = process_connect(pskb, ct, ctinfo, data, dataoff, | ||
978 | &pdu->h323_message_body.connect); | ||
979 | break; | ||
980 | case eH323_UU_PDU_h323_message_body_alerting: | ||
981 | ret = process_alerting(pskb, ct, ctinfo, data, dataoff, | ||
982 | &pdu->h323_message_body.alerting); | ||
983 | break; | ||
984 | case eH323_UU_PDU_h323_message_body_information: | ||
985 | ret = process_information(pskb, ct, ctinfo, data, dataoff, | ||
986 | &pdu->h323_message_body. | ||
987 | information); | ||
988 | break; | ||
989 | case eH323_UU_PDU_h323_message_body_facility: | ||
990 | ret = process_facility(pskb, ct, ctinfo, data, dataoff, | ||
991 | &pdu->h323_message_body.facility); | ||
992 | break; | ||
993 | case eH323_UU_PDU_h323_message_body_progress: | ||
994 | ret = process_progress(pskb, ct, ctinfo, data, dataoff, | ||
995 | &pdu->h323_message_body.progress); | ||
996 | break; | ||
997 | default: | ||
998 | DEBUGP("ip_ct_q931: Q.931 signal %d\n", | ||
999 | pdu->h323_message_body.choice); | ||
1000 | break; | ||
1001 | } | ||
1002 | |||
1003 | if (ret < 0) | ||
1004 | return -1; | ||
1005 | |||
1006 | if (pdu->options & eH323_UU_PDU_h245Control) { | ||
1007 | for (i = 0; i < pdu->h245Control.count; i++) { | ||
1008 | ret = process_h245(pskb, ct, ctinfo, data, dataoff, | ||
1009 | &pdu->h245Control.item[i]); | ||
1010 | if (ret < 0) | ||
1011 | return -1; | ||
1012 | } | ||
1013 | } | ||
1014 | |||
1015 | return 0; | ||
1016 | } | ||
1017 | |||
1018 | /****************************************************************************/ | ||
1019 | static int q931_help(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1020 | enum ip_conntrack_info ctinfo) | ||
1021 | { | ||
1022 | static Q931 q931; | ||
1023 | unsigned char *data = NULL; | ||
1024 | int datalen; | ||
1025 | int dataoff; | ||
1026 | int ret; | ||
1027 | |||
1028 | /* Until there's been traffic both ways, don't look in packets. */ | ||
1029 | if (ctinfo != IP_CT_ESTABLISHED | ||
1030 | && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { | ||
1031 | return NF_ACCEPT; | ||
1032 | } | ||
1033 | DEBUGP("ip_ct_q931: skblen = %u\n", (*pskb)->len); | ||
1034 | |||
1035 | spin_lock_bh(&ip_h323_lock); | ||
1036 | |||
1037 | /* Process each TPKT */ | ||
1038 | while (get_tpkt_data(pskb, ct, ctinfo, &data, &datalen, &dataoff)) { | ||
1039 | DEBUGP("ip_ct_q931: TPKT %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n", | ||
1040 | NIPQUAD((*pskb)->nh.iph->saddr), | ||
1041 | NIPQUAD((*pskb)->nh.iph->daddr), datalen); | ||
1042 | |||
1043 | /* Decode Q.931 signal */ | ||
1044 | ret = DecodeQ931(data, datalen, &q931); | ||
1045 | if (ret < 0) { | ||
1046 | if (net_ratelimit()) | ||
1047 | printk("ip_ct_q931: decoding error: %s\n", | ||
1048 | ret == H323_ERROR_BOUND ? | ||
1049 | "out of bound" : "out of range"); | ||
1050 | /* We don't drop when decoding error */ | ||
1051 | break; | ||
1052 | } | ||
1053 | |||
1054 | /* Process Q.931 signal */ | ||
1055 | if (process_q931(pskb, ct, ctinfo, &data, dataoff, &q931) < 0) | ||
1056 | goto drop; | ||
1057 | } | ||
1058 | |||
1059 | spin_unlock_bh(&ip_h323_lock); | ||
1060 | return NF_ACCEPT; | ||
1061 | |||
1062 | drop: | ||
1063 | spin_unlock_bh(&ip_h323_lock); | ||
1064 | if (net_ratelimit()) | ||
1065 | printk("ip_ct_q931: packet dropped\n"); | ||
1066 | return NF_DROP; | ||
1067 | } | ||
1068 | |||
1069 | /****************************************************************************/ | ||
1070 | static struct ip_conntrack_helper ip_conntrack_helper_q931 = { | ||
1071 | .name = "Q.931", | ||
1072 | .me = THIS_MODULE, | ||
1073 | .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4 /* T.120 and H.245 */ , | ||
1074 | .timeout = 240, | ||
1075 | .tuple = {.src = {.u = {__constant_htons(Q931_PORT)}}, | ||
1076 | .dst = {.protonum = IPPROTO_TCP}}, | ||
1077 | .mask = {.src = {.u = {0xFFFF}}, | ||
1078 | .dst = {.protonum = 0xFF}}, | ||
1079 | .help = q931_help | ||
1080 | }; | ||
1081 | |||
1082 | /****************************************************************************/ | ||
1083 | void ip_conntrack_q931_expect(struct ip_conntrack *new, | ||
1084 | struct ip_conntrack_expect *this) | ||
1085 | { | ||
1086 | write_lock_bh(&ip_conntrack_lock); | ||
1087 | new->helper = &ip_conntrack_helper_q931; | ||
1088 | write_unlock_bh(&ip_conntrack_lock); | ||
1089 | } | ||
1090 | |||
1091 | /****************************************************************************/ | ||
1092 | static unsigned char *get_udp_data(struct sk_buff **pskb, int *datalen) | ||
1093 | { | ||
1094 | struct udphdr _uh, *uh; | ||
1095 | int dataoff; | ||
1096 | |||
1097 | uh = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4, sizeof(_uh), | ||
1098 | &_uh); | ||
1099 | if (uh == NULL) | ||
1100 | return NULL; | ||
1101 | dataoff = (*pskb)->nh.iph->ihl * 4 + sizeof(_uh); | ||
1102 | if (dataoff >= (*pskb)->len) | ||
1103 | return NULL; | ||
1104 | *datalen = (*pskb)->len - dataoff; | ||
1105 | return skb_header_pointer(*pskb, dataoff, *datalen, h323_buffer); | ||
1106 | } | ||
1107 | |||
1108 | /****************************************************************************/ | ||
1109 | static struct ip_conntrack_expect *find_expect(struct ip_conntrack *ct, | ||
1110 | u_int32_t ip, u_int16_t port) | ||
1111 | { | ||
1112 | struct ip_conntrack_expect *exp; | ||
1113 | struct ip_conntrack_tuple tuple; | ||
1114 | |||
1115 | tuple.src.ip = 0; | ||
1116 | tuple.src.u.tcp.port = 0; | ||
1117 | tuple.dst.ip = ip; | ||
1118 | tuple.dst.u.tcp.port = htons(port); | ||
1119 | tuple.dst.protonum = IPPROTO_TCP; | ||
1120 | |||
1121 | exp = __ip_conntrack_expect_find(&tuple); | ||
1122 | if (exp->master == ct) | ||
1123 | return exp; | ||
1124 | return NULL; | ||
1125 | } | ||
1126 | |||
1127 | /****************************************************************************/ | ||
1128 | static int set_expect_timeout(struct ip_conntrack_expect *exp, | ||
1129 | unsigned timeout) | ||
1130 | { | ||
1131 | if (!exp || !del_timer(&exp->timeout)) | ||
1132 | return 0; | ||
1133 | |||
1134 | exp->timeout.expires = jiffies + timeout * HZ; | ||
1135 | add_timer(&exp->timeout); | ||
1136 | |||
1137 | return 1; | ||
1138 | } | ||
1139 | |||
1140 | /****************************************************************************/ | ||
1141 | static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1142 | enum ip_conntrack_info ctinfo, | ||
1143 | unsigned char **data, | ||
1144 | TransportAddress * addr, int count) | ||
1145 | { | ||
1146 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
1147 | int dir = CTINFO2DIR(ctinfo); | ||
1148 | int ret = 0; | ||
1149 | int i; | ||
1150 | u_int32_t ip; | ||
1151 | u_int16_t port; | ||
1152 | struct ip_conntrack_expect *exp; | ||
1153 | |||
1154 | /* Look for the first related address */ | ||
1155 | for (i = 0; i < count; i++) { | ||
1156 | if (get_h225_addr(*data, &addr[i], &ip, &port) && | ||
1157 | ip == ct->tuplehash[dir].tuple.src.ip && port != 0) | ||
1158 | break; | ||
1159 | } | ||
1160 | |||
1161 | if (i >= count) /* Not found */ | ||
1162 | return 0; | ||
1163 | |||
1164 | /* Create expect for Q.931 */ | ||
1165 | if ((exp = ip_conntrack_expect_alloc(ct)) == NULL) | ||
1166 | return -1; | ||
1167 | exp->tuple.src.ip = gkrouted_only ? /* only accept calls from GK? */ | ||
1168 | ct->tuplehash[!dir].tuple.src.ip : 0; | ||
1169 | exp->tuple.src.u.tcp.port = 0; | ||
1170 | exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; | ||
1171 | exp->tuple.dst.u.tcp.port = htons(port); | ||
1172 | exp->tuple.dst.protonum = IPPROTO_TCP; | ||
1173 | exp->mask.src.ip = gkrouted_only ? 0xFFFFFFFF : 0; | ||
1174 | exp->mask.src.u.tcp.port = 0; | ||
1175 | exp->mask.dst.ip = 0xFFFFFFFF; | ||
1176 | exp->mask.dst.u.tcp.port = 0xFFFF; | ||
1177 | exp->mask.dst.protonum = 0xFF; | ||
1178 | exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple calls */ | ||
1179 | |||
1180 | if (nat_q931_hook) { /* Need NAT */ | ||
1181 | ret = nat_q931_hook(pskb, ct, ctinfo, data, addr, i, | ||
1182 | port, exp); | ||
1183 | } else { /* Conntrack only */ | ||
1184 | exp->expectfn = ip_conntrack_q931_expect; | ||
1185 | |||
1186 | if (ip_conntrack_expect_related(exp) == 0) { | ||
1187 | DEBUGP("ip_ct_ras: expect Q.931 " | ||
1188 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
1189 | NIPQUAD(exp->tuple.src.ip), | ||
1190 | ntohs(exp->tuple.src.u.tcp.port), | ||
1191 | NIPQUAD(exp->tuple.dst.ip), | ||
1192 | ntohs(exp->tuple.dst.u.tcp.port)); | ||
1193 | |||
1194 | /* Save port for looking up expect in processing RCF */ | ||
1195 | info->sig_port[dir] = port; | ||
1196 | } else | ||
1197 | ret = -1; | ||
1198 | } | ||
1199 | |||
1200 | ip_conntrack_expect_put(exp); | ||
1201 | |||
1202 | return ret; | ||
1203 | } | ||
1204 | |||
1205 | /****************************************************************************/ | ||
1206 | static int process_grq(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1207 | enum ip_conntrack_info ctinfo, | ||
1208 | unsigned char **data, GatekeeperRequest * grq) | ||
1209 | { | ||
1210 | DEBUGP("ip_ct_ras: GRQ\n"); | ||
1211 | |||
1212 | if (set_ras_addr_hook) /* NATed */ | ||
1213 | return set_ras_addr_hook(pskb, ct, ctinfo, data, | ||
1214 | &grq->rasAddress, 1); | ||
1215 | return 0; | ||
1216 | } | ||
1217 | |||
1218 | /* Declare before using */ | ||
1219 | static void ip_conntrack_ras_expect(struct ip_conntrack *new, | ||
1220 | struct ip_conntrack_expect *this); | ||
1221 | |||
1222 | /****************************************************************************/ | ||
1223 | static int process_gcf(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1224 | enum ip_conntrack_info ctinfo, | ||
1225 | unsigned char **data, GatekeeperConfirm * gcf) | ||
1226 | { | ||
1227 | int dir = CTINFO2DIR(ctinfo); | ||
1228 | int ret = 0; | ||
1229 | u_int32_t ip; | ||
1230 | u_int16_t port; | ||
1231 | struct ip_conntrack_expect *exp; | ||
1232 | |||
1233 | DEBUGP("ip_ct_ras: GCF\n"); | ||
1234 | |||
1235 | if (!get_h225_addr(*data, &gcf->rasAddress, &ip, &port)) | ||
1236 | return 0; | ||
1237 | |||
1238 | /* Registration port is the same as discovery port */ | ||
1239 | if (ip == ct->tuplehash[dir].tuple.src.ip && | ||
1240 | port == ntohs(ct->tuplehash[dir].tuple.src.u.udp.port)) | ||
1241 | return 0; | ||
1242 | |||
1243 | /* Avoid RAS expectation loops. A GCF is never expected. */ | ||
1244 | if (test_bit(IPS_EXPECTED_BIT, &ct->status)) | ||
1245 | return 0; | ||
1246 | |||
1247 | /* Need new expect */ | ||
1248 | if ((exp = ip_conntrack_expect_alloc(ct)) == NULL) | ||
1249 | return -1; | ||
1250 | exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
1251 | exp->tuple.src.u.tcp.port = 0; | ||
1252 | exp->tuple.dst.ip = ip; | ||
1253 | exp->tuple.dst.u.tcp.port = htons(port); | ||
1254 | exp->tuple.dst.protonum = IPPROTO_UDP; | ||
1255 | exp->mask.src.ip = 0xFFFFFFFF; | ||
1256 | exp->mask.src.u.tcp.port = 0; | ||
1257 | exp->mask.dst.ip = 0xFFFFFFFF; | ||
1258 | exp->mask.dst.u.tcp.port = 0xFFFF; | ||
1259 | exp->mask.dst.protonum = 0xFF; | ||
1260 | exp->flags = 0; | ||
1261 | exp->expectfn = ip_conntrack_ras_expect; | ||
1262 | if (ip_conntrack_expect_related(exp) == 0) { | ||
1263 | DEBUGP("ip_ct_ras: expect RAS " | ||
1264 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
1265 | NIPQUAD(exp->tuple.src.ip), | ||
1266 | ntohs(exp->tuple.src.u.tcp.port), | ||
1267 | NIPQUAD(exp->tuple.dst.ip), | ||
1268 | ntohs(exp->tuple.dst.u.tcp.port)); | ||
1269 | } else | ||
1270 | ret = -1; | ||
1271 | |||
1272 | ip_conntrack_expect_put(exp); | ||
1273 | |||
1274 | return ret; | ||
1275 | } | ||
1276 | |||
1277 | /****************************************************************************/ | ||
1278 | static int process_rrq(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1279 | enum ip_conntrack_info ctinfo, | ||
1280 | unsigned char **data, RegistrationRequest * rrq) | ||
1281 | { | ||
1282 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
1283 | int ret; | ||
1284 | |||
1285 | DEBUGP("ip_ct_ras: RRQ\n"); | ||
1286 | |||
1287 | ret = expect_q931(pskb, ct, ctinfo, data, | ||
1288 | rrq->callSignalAddress.item, | ||
1289 | rrq->callSignalAddress.count); | ||
1290 | if (ret < 0) | ||
1291 | return -1; | ||
1292 | |||
1293 | if (set_ras_addr_hook) { | ||
1294 | ret = set_ras_addr_hook(pskb, ct, ctinfo, data, | ||
1295 | rrq->rasAddress.item, | ||
1296 | rrq->rasAddress.count); | ||
1297 | if (ret < 0) | ||
1298 | return -1; | ||
1299 | } | ||
1300 | |||
1301 | if (rrq->options & eRegistrationRequest_timeToLive) { | ||
1302 | DEBUGP("ip_ct_ras: RRQ TTL = %u seconds\n", rrq->timeToLive); | ||
1303 | info->timeout = rrq->timeToLive; | ||
1304 | } else | ||
1305 | info->timeout = 0; | ||
1306 | |||
1307 | return 0; | ||
1308 | } | ||
1309 | |||
1310 | /****************************************************************************/ | ||
1311 | static int process_rcf(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1312 | enum ip_conntrack_info ctinfo, | ||
1313 | unsigned char **data, RegistrationConfirm * rcf) | ||
1314 | { | ||
1315 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
1316 | int dir = CTINFO2DIR(ctinfo); | ||
1317 | int ret; | ||
1318 | struct ip_conntrack_expect *exp; | ||
1319 | |||
1320 | DEBUGP("ip_ct_ras: RCF\n"); | ||
1321 | |||
1322 | if (set_sig_addr_hook) { | ||
1323 | ret = set_sig_addr_hook(pskb, ct, ctinfo, data, | ||
1324 | rcf->callSignalAddress.item, | ||
1325 | rcf->callSignalAddress.count); | ||
1326 | if (ret < 0) | ||
1327 | return -1; | ||
1328 | } | ||
1329 | |||
1330 | if (rcf->options & eRegistrationConfirm_timeToLive) { | ||
1331 | DEBUGP("ip_ct_ras: RCF TTL = %u seconds\n", rcf->timeToLive); | ||
1332 | info->timeout = rcf->timeToLive; | ||
1333 | } | ||
1334 | |||
1335 | if (info->timeout > 0) { | ||
1336 | DEBUGP | ||
1337 | ("ip_ct_ras: set RAS connection timeout to %u seconds\n", | ||
1338 | info->timeout); | ||
1339 | ip_ct_refresh_acct(ct, ctinfo, NULL, info->timeout * HZ); | ||
1340 | |||
1341 | /* Set expect timeout */ | ||
1342 | read_lock_bh(&ip_conntrack_lock); | ||
1343 | exp = find_expect(ct, ct->tuplehash[dir].tuple.dst.ip, | ||
1344 | info->sig_port[!dir]); | ||
1345 | if (exp) { | ||
1346 | DEBUGP("ip_ct_ras: set Q.931 expect " | ||
1347 | "(%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu) " | ||
1348 | "timeout to %u seconds\n", | ||
1349 | NIPQUAD(exp->tuple.src.ip), | ||
1350 | ntohs(exp->tuple.src.u.tcp.port), | ||
1351 | NIPQUAD(exp->tuple.dst.ip), | ||
1352 | ntohs(exp->tuple.dst.u.tcp.port), | ||
1353 | info->timeout); | ||
1354 | set_expect_timeout(exp, info->timeout); | ||
1355 | } | ||
1356 | read_unlock_bh(&ip_conntrack_lock); | ||
1357 | } | ||
1358 | |||
1359 | return 0; | ||
1360 | } | ||
1361 | |||
1362 | /****************************************************************************/ | ||
1363 | static int process_urq(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1364 | enum ip_conntrack_info ctinfo, | ||
1365 | unsigned char **data, UnregistrationRequest * urq) | ||
1366 | { | ||
1367 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
1368 | int dir = CTINFO2DIR(ctinfo); | ||
1369 | int ret; | ||
1370 | |||
1371 | DEBUGP("ip_ct_ras: URQ\n"); | ||
1372 | |||
1373 | if (set_sig_addr_hook) { | ||
1374 | ret = set_sig_addr_hook(pskb, ct, ctinfo, data, | ||
1375 | urq->callSignalAddress.item, | ||
1376 | urq->callSignalAddress.count); | ||
1377 | if (ret < 0) | ||
1378 | return -1; | ||
1379 | } | ||
1380 | |||
1381 | /* Clear old expect */ | ||
1382 | ip_ct_remove_expectations(ct); | ||
1383 | info->sig_port[dir] = 0; | ||
1384 | info->sig_port[!dir] = 0; | ||
1385 | |||
1386 | /* Give it 30 seconds for UCF or URJ */ | ||
1387 | ip_ct_refresh_acct(ct, ctinfo, NULL, 30 * HZ); | ||
1388 | |||
1389 | return 0; | ||
1390 | } | ||
1391 | |||
1392 | /****************************************************************************/ | ||
1393 | static int process_arq(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1394 | enum ip_conntrack_info ctinfo, | ||
1395 | unsigned char **data, AdmissionRequest * arq) | ||
1396 | { | ||
1397 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
1398 | int dir = CTINFO2DIR(ctinfo); | ||
1399 | u_int32_t ip; | ||
1400 | u_int16_t port; | ||
1401 | |||
1402 | DEBUGP("ip_ct_ras: ARQ\n"); | ||
1403 | |||
1404 | if ((arq->options & eAdmissionRequest_destCallSignalAddress) && | ||
1405 | get_h225_addr(*data, &arq->destCallSignalAddress, &ip, &port) && | ||
1406 | ip == ct->tuplehash[dir].tuple.src.ip && | ||
1407 | port == info->sig_port[dir] && set_h225_addr_hook) { | ||
1408 | /* Answering ARQ */ | ||
1409 | return set_h225_addr_hook(pskb, data, 0, | ||
1410 | &arq->destCallSignalAddress, | ||
1411 | ct->tuplehash[!dir].tuple.dst.ip, | ||
1412 | info->sig_port[!dir]); | ||
1413 | } | ||
1414 | |||
1415 | if ((arq->options & eAdmissionRequest_srcCallSignalAddress) && | ||
1416 | get_h225_addr(*data, &arq->srcCallSignalAddress, &ip, &port) && | ||
1417 | ip == ct->tuplehash[dir].tuple.src.ip && set_h225_addr_hook) { | ||
1418 | /* Calling ARQ */ | ||
1419 | return set_h225_addr_hook(pskb, data, 0, | ||
1420 | &arq->srcCallSignalAddress, | ||
1421 | ct->tuplehash[!dir].tuple.dst.ip, | ||
1422 | port); | ||
1423 | } | ||
1424 | |||
1425 | return 0; | ||
1426 | } | ||
1427 | |||
1428 | /****************************************************************************/ | ||
1429 | static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1430 | enum ip_conntrack_info ctinfo, | ||
1431 | unsigned char **data, AdmissionConfirm * acf) | ||
1432 | { | ||
1433 | int dir = CTINFO2DIR(ctinfo); | ||
1434 | int ret = 0; | ||
1435 | u_int32_t ip; | ||
1436 | u_int16_t port; | ||
1437 | struct ip_conntrack_expect *exp; | ||
1438 | |||
1439 | DEBUGP("ip_ct_ras: ACF\n"); | ||
1440 | |||
1441 | if (!get_h225_addr(*data, &acf->destCallSignalAddress, &ip, &port)) | ||
1442 | return 0; | ||
1443 | |||
1444 | if (ip == ct->tuplehash[dir].tuple.dst.ip) { /* Answering ACF */ | ||
1445 | if (set_sig_addr_hook) | ||
1446 | return set_sig_addr_hook(pskb, ct, ctinfo, data, | ||
1447 | &acf->destCallSignalAddress, | ||
1448 | 1); | ||
1449 | return 0; | ||
1450 | } | ||
1451 | |||
1452 | /* Need new expect */ | ||
1453 | if ((exp = ip_conntrack_expect_alloc(ct)) == NULL) | ||
1454 | return -1; | ||
1455 | exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
1456 | exp->tuple.src.u.tcp.port = 0; | ||
1457 | exp->tuple.dst.ip = ip; | ||
1458 | exp->tuple.dst.u.tcp.port = htons(port); | ||
1459 | exp->tuple.dst.protonum = IPPROTO_TCP; | ||
1460 | exp->mask.src.ip = 0xFFFFFFFF; | ||
1461 | exp->mask.src.u.tcp.port = 0; | ||
1462 | exp->mask.dst.ip = 0xFFFFFFFF; | ||
1463 | exp->mask.dst.u.tcp.port = 0xFFFF; | ||
1464 | exp->mask.dst.protonum = 0xFF; | ||
1465 | exp->flags = IP_CT_EXPECT_PERMANENT; | ||
1466 | exp->expectfn = ip_conntrack_q931_expect; | ||
1467 | |||
1468 | if (ip_conntrack_expect_related(exp) == 0) { | ||
1469 | DEBUGP("ip_ct_ras: expect Q.931 " | ||
1470 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
1471 | NIPQUAD(exp->tuple.src.ip), | ||
1472 | ntohs(exp->tuple.src.u.tcp.port), | ||
1473 | NIPQUAD(exp->tuple.dst.ip), | ||
1474 | ntohs(exp->tuple.dst.u.tcp.port)); | ||
1475 | } else | ||
1476 | ret = -1; | ||
1477 | |||
1478 | ip_conntrack_expect_put(exp); | ||
1479 | |||
1480 | return ret; | ||
1481 | } | ||
1482 | |||
1483 | /****************************************************************************/ | ||
1484 | static int process_lrq(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1485 | enum ip_conntrack_info ctinfo, | ||
1486 | unsigned char **data, LocationRequest * lrq) | ||
1487 | { | ||
1488 | DEBUGP("ip_ct_ras: LRQ\n"); | ||
1489 | |||
1490 | if (set_ras_addr_hook) | ||
1491 | return set_ras_addr_hook(pskb, ct, ctinfo, data, | ||
1492 | &lrq->replyAddress, 1); | ||
1493 | return 0; | ||
1494 | } | ||
1495 | |||
1496 | /****************************************************************************/ | ||
1497 | static int process_lcf(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1498 | enum ip_conntrack_info ctinfo, | ||
1499 | unsigned char **data, LocationConfirm * lcf) | ||
1500 | { | ||
1501 | int dir = CTINFO2DIR(ctinfo); | ||
1502 | int ret = 0; | ||
1503 | u_int32_t ip; | ||
1504 | u_int16_t port; | ||
1505 | struct ip_conntrack_expect *exp = NULL; | ||
1506 | |||
1507 | DEBUGP("ip_ct_ras: LCF\n"); | ||
1508 | |||
1509 | if (!get_h225_addr(*data, &lcf->callSignalAddress, &ip, &port)) | ||
1510 | return 0; | ||
1511 | |||
1512 | /* Need new expect for call signal */ | ||
1513 | if ((exp = ip_conntrack_expect_alloc(ct)) == NULL) | ||
1514 | return -1; | ||
1515 | exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
1516 | exp->tuple.src.u.tcp.port = 0; | ||
1517 | exp->tuple.dst.ip = ip; | ||
1518 | exp->tuple.dst.u.tcp.port = htons(port); | ||
1519 | exp->tuple.dst.protonum = IPPROTO_TCP; | ||
1520 | exp->mask.src.ip = 0xFFFFFFFF; | ||
1521 | exp->mask.src.u.tcp.port = 0; | ||
1522 | exp->mask.dst.ip = 0xFFFFFFFF; | ||
1523 | exp->mask.dst.u.tcp.port = 0xFFFF; | ||
1524 | exp->mask.dst.protonum = 0xFF; | ||
1525 | exp->flags = IP_CT_EXPECT_PERMANENT; | ||
1526 | exp->expectfn = ip_conntrack_q931_expect; | ||
1527 | |||
1528 | if (ip_conntrack_expect_related(exp) == 0) { | ||
1529 | DEBUGP("ip_ct_ras: expect Q.931 " | ||
1530 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
1531 | NIPQUAD(exp->tuple.src.ip), | ||
1532 | ntohs(exp->tuple.src.u.tcp.port), | ||
1533 | NIPQUAD(exp->tuple.dst.ip), | ||
1534 | ntohs(exp->tuple.dst.u.tcp.port)); | ||
1535 | } else | ||
1536 | ret = -1; | ||
1537 | |||
1538 | ip_conntrack_expect_put(exp); | ||
1539 | |||
1540 | /* Ignore rasAddress */ | ||
1541 | |||
1542 | return ret; | ||
1543 | } | ||
1544 | |||
1545 | /****************************************************************************/ | ||
1546 | static int process_irr(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1547 | enum ip_conntrack_info ctinfo, | ||
1548 | unsigned char **data, InfoRequestResponse * irr) | ||
1549 | { | ||
1550 | int ret; | ||
1551 | |||
1552 | DEBUGP("ip_ct_ras: IRR\n"); | ||
1553 | |||
1554 | if (set_ras_addr_hook) { | ||
1555 | ret = set_ras_addr_hook(pskb, ct, ctinfo, data, | ||
1556 | &irr->rasAddress, 1); | ||
1557 | if (ret < 0) | ||
1558 | return -1; | ||
1559 | } | ||
1560 | |||
1561 | if (set_sig_addr_hook) { | ||
1562 | ret = set_sig_addr_hook(pskb, ct, ctinfo, data, | ||
1563 | irr->callSignalAddress.item, | ||
1564 | irr->callSignalAddress.count); | ||
1565 | if (ret < 0) | ||
1566 | return -1; | ||
1567 | } | ||
1568 | |||
1569 | return 0; | ||
1570 | } | ||
1571 | |||
1572 | /****************************************************************************/ | ||
1573 | static int process_ras(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1574 | enum ip_conntrack_info ctinfo, | ||
1575 | unsigned char **data, RasMessage * ras) | ||
1576 | { | ||
1577 | switch (ras->choice) { | ||
1578 | case eRasMessage_gatekeeperRequest: | ||
1579 | return process_grq(pskb, ct, ctinfo, data, | ||
1580 | &ras->gatekeeperRequest); | ||
1581 | case eRasMessage_gatekeeperConfirm: | ||
1582 | return process_gcf(pskb, ct, ctinfo, data, | ||
1583 | &ras->gatekeeperConfirm); | ||
1584 | case eRasMessage_registrationRequest: | ||
1585 | return process_rrq(pskb, ct, ctinfo, data, | ||
1586 | &ras->registrationRequest); | ||
1587 | case eRasMessage_registrationConfirm: | ||
1588 | return process_rcf(pskb, ct, ctinfo, data, | ||
1589 | &ras->registrationConfirm); | ||
1590 | case eRasMessage_unregistrationRequest: | ||
1591 | return process_urq(pskb, ct, ctinfo, data, | ||
1592 | &ras->unregistrationRequest); | ||
1593 | case eRasMessage_admissionRequest: | ||
1594 | return process_arq(pskb, ct, ctinfo, data, | ||
1595 | &ras->admissionRequest); | ||
1596 | case eRasMessage_admissionConfirm: | ||
1597 | return process_acf(pskb, ct, ctinfo, data, | ||
1598 | &ras->admissionConfirm); | ||
1599 | case eRasMessage_locationRequest: | ||
1600 | return process_lrq(pskb, ct, ctinfo, data, | ||
1601 | &ras->locationRequest); | ||
1602 | case eRasMessage_locationConfirm: | ||
1603 | return process_lcf(pskb, ct, ctinfo, data, | ||
1604 | &ras->locationConfirm); | ||
1605 | case eRasMessage_infoRequestResponse: | ||
1606 | return process_irr(pskb, ct, ctinfo, data, | ||
1607 | &ras->infoRequestResponse); | ||
1608 | default: | ||
1609 | DEBUGP("ip_ct_ras: RAS message %d\n", ras->choice); | ||
1610 | break; | ||
1611 | } | ||
1612 | |||
1613 | return 0; | ||
1614 | } | ||
1615 | |||
1616 | /****************************************************************************/ | ||
1617 | static int ras_help(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1618 | enum ip_conntrack_info ctinfo) | ||
1619 | { | ||
1620 | static RasMessage ras; | ||
1621 | unsigned char *data; | ||
1622 | int datalen = 0; | ||
1623 | int ret; | ||
1624 | |||
1625 | DEBUGP("ip_ct_ras: skblen = %u\n", (*pskb)->len); | ||
1626 | |||
1627 | spin_lock_bh(&ip_h323_lock); | ||
1628 | |||
1629 | /* Get UDP data */ | ||
1630 | data = get_udp_data(pskb, &datalen); | ||
1631 | if (data == NULL) | ||
1632 | goto accept; | ||
1633 | DEBUGP("ip_ct_ras: RAS message %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n", | ||
1634 | NIPQUAD((*pskb)->nh.iph->saddr), | ||
1635 | NIPQUAD((*pskb)->nh.iph->daddr), datalen); | ||
1636 | |||
1637 | /* Decode RAS message */ | ||
1638 | ret = DecodeRasMessage(data, datalen, &ras); | ||
1639 | if (ret < 0) { | ||
1640 | if (net_ratelimit()) | ||
1641 | printk("ip_ct_ras: decoding error: %s\n", | ||
1642 | ret == H323_ERROR_BOUND ? | ||
1643 | "out of bound" : "out of range"); | ||
1644 | goto accept; | ||
1645 | } | ||
1646 | |||
1647 | /* Process RAS message */ | ||
1648 | if (process_ras(pskb, ct, ctinfo, &data, &ras) < 0) | ||
1649 | goto drop; | ||
1650 | |||
1651 | accept: | ||
1652 | spin_unlock_bh(&ip_h323_lock); | ||
1653 | return NF_ACCEPT; | ||
1654 | |||
1655 | drop: | ||
1656 | spin_unlock_bh(&ip_h323_lock); | ||
1657 | if (net_ratelimit()) | ||
1658 | printk("ip_ct_ras: packet dropped\n"); | ||
1659 | return NF_DROP; | ||
1660 | } | ||
1661 | |||
1662 | /****************************************************************************/ | ||
1663 | static struct ip_conntrack_helper ip_conntrack_helper_ras = { | ||
1664 | .name = "RAS", | ||
1665 | .me = THIS_MODULE, | ||
1666 | .max_expected = 32, | ||
1667 | .timeout = 240, | ||
1668 | .tuple = {.src = {.u = {__constant_htons(RAS_PORT)}}, | ||
1669 | .dst = {.protonum = IPPROTO_UDP}}, | ||
1670 | .mask = {.src = {.u = {0xFFFE}}, | ||
1671 | .dst = {.protonum = 0xFF}}, | ||
1672 | .help = ras_help, | ||
1673 | }; | ||
1674 | |||
1675 | /****************************************************************************/ | ||
1676 | static void ip_conntrack_ras_expect(struct ip_conntrack *new, | ||
1677 | struct ip_conntrack_expect *this) | ||
1678 | { | ||
1679 | write_lock_bh(&ip_conntrack_lock); | ||
1680 | new->helper = &ip_conntrack_helper_ras; | ||
1681 | write_unlock_bh(&ip_conntrack_lock); | ||
1682 | } | ||
1683 | |||
1684 | /****************************************************************************/ | ||
1685 | /* Not __exit - called from init() */ | ||
1686 | static void fini(void) | ||
1687 | { | ||
1688 | ip_conntrack_helper_unregister(&ip_conntrack_helper_ras); | ||
1689 | ip_conntrack_helper_unregister(&ip_conntrack_helper_q931); | ||
1690 | kfree(h323_buffer); | ||
1691 | DEBUGP("ip_ct_h323: fini\n"); | ||
1692 | } | ||
1693 | |||
1694 | /****************************************************************************/ | ||
1695 | static int __init init(void) | ||
1696 | { | ||
1697 | int ret; | ||
1698 | |||
1699 | h323_buffer = kmalloc(65536, GFP_KERNEL); | ||
1700 | if (!h323_buffer) | ||
1701 | return -ENOMEM; | ||
1702 | if ((ret = ip_conntrack_helper_register(&ip_conntrack_helper_q931)) || | ||
1703 | (ret = ip_conntrack_helper_register(&ip_conntrack_helper_ras))) { | ||
1704 | fini(); | ||
1705 | return ret; | ||
1706 | } | ||
1707 | |||
1708 | DEBUGP("ip_ct_h323: init success\n"); | ||
1709 | return 0; | ||
1710 | } | ||
1711 | |||
1712 | /****************************************************************************/ | ||
1713 | module_init(init); | ||
1714 | module_exit(fini); | ||
1715 | |||
1716 | EXPORT_SYMBOL(get_h245_addr); | ||
1717 | EXPORT_SYMBOL(get_h225_addr); | ||
1718 | EXPORT_SYMBOL(ip_conntrack_h245_expect); | ||
1719 | EXPORT_SYMBOL(ip_conntrack_q931_expect); | ||
1720 | EXPORT_SYMBOL(set_h245_addr_hook); | ||
1721 | EXPORT_SYMBOL(set_h225_addr_hook); | ||
1722 | EXPORT_SYMBOL(set_sig_addr_hook); | ||
1723 | EXPORT_SYMBOL(set_ras_addr_hook); | ||
1724 | EXPORT_SYMBOL(nat_rtp_rtcp_hook); | ||
1725 | EXPORT_SYMBOL(nat_t120_hook); | ||
1726 | EXPORT_SYMBOL(nat_h245_hook); | ||
1727 | EXPORT_SYMBOL(nat_q931_hook); | ||
1728 | |||
1729 | MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>"); | ||
1730 | MODULE_DESCRIPTION("H.323 connection tracking helper"); | ||
1731 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c new file mode 100644 index 000000000000..afa525129b51 --- /dev/null +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c | |||
@@ -0,0 +1,870 @@ | |||
1 | /**************************************************************************** | ||
2 | * ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323 | ||
3 | * conntrack/NAT module. | ||
4 | * | ||
5 | * Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@hotmail.com> | ||
6 | * | ||
7 | * This source code is licensed under General Public License version 2. | ||
8 | * | ||
9 | * See ip_conntrack_helper_h323_asn1.h for details. | ||
10 | * | ||
11 | ****************************************************************************/ | ||
12 | |||
13 | #ifdef __KERNEL__ | ||
14 | #include <linux/kernel.h> | ||
15 | #else | ||
16 | #include <stdio.h> | ||
17 | #endif | ||
18 | #include "ip_conntrack_helper_h323_asn1.h" | ||
19 | |||
20 | /* Trace Flag */ | ||
21 | #ifndef H323_TRACE | ||
22 | #define H323_TRACE 0 | ||
23 | #endif | ||
24 | |||
25 | #if H323_TRACE | ||
26 | #define TAB_SIZE 4 | ||
27 | #define IFTHEN(cond, act) if(cond){act;} | ||
28 | #ifdef __KERNEL__ | ||
29 | #define PRINT printk | ||
30 | #else | ||
31 | #define PRINT printf | ||
32 | #endif | ||
33 | #define FNAME(name) name, | ||
34 | #else | ||
35 | #define IFTHEN(cond, act) | ||
36 | #define PRINT(fmt, args...) | ||
37 | #define FNAME(name) | ||
38 | #endif | ||
39 | |||
40 | /* ASN.1 Types */ | ||
41 | #define NUL 0 | ||
42 | #define BOOL 1 | ||
43 | #define OID 2 | ||
44 | #define INT 3 | ||
45 | #define ENUM 4 | ||
46 | #define BITSTR 5 | ||
47 | #define NUMSTR 6 | ||
48 | #define NUMDGT 6 | ||
49 | #define TBCDSTR 6 | ||
50 | #define OCTSTR 7 | ||
51 | #define PRTSTR 7 | ||
52 | #define IA5STR 7 | ||
53 | #define GENSTR 7 | ||
54 | #define BMPSTR 8 | ||
55 | #define SEQ 9 | ||
56 | #define SET 9 | ||
57 | #define SEQOF 10 | ||
58 | #define SETOF 10 | ||
59 | #define CHOICE 11 | ||
60 | |||
61 | /* Constraint Types */ | ||
62 | #define FIXD 0 | ||
63 | /* #define BITS 1-8 */ | ||
64 | #define BYTE 9 | ||
65 | #define WORD 10 | ||
66 | #define CONS 11 | ||
67 | #define SEMI 12 | ||
68 | #define UNCO 13 | ||
69 | |||
70 | /* ASN.1 Type Attributes */ | ||
71 | #define SKIP 0 | ||
72 | #define STOP 1 | ||
73 | #define DECODE 2 | ||
74 | #define EXT 4 | ||
75 | #define OPEN 8 | ||
76 | #define OPT 16 | ||
77 | |||
78 | |||
79 | /* ASN.1 Field Structure */ | ||
80 | typedef struct field_t { | ||
81 | #if H323_TRACE | ||
82 | char *name; | ||
83 | #endif | ||
84 | unsigned char type; | ||
85 | unsigned char sz; | ||
86 | unsigned char lb; | ||
87 | unsigned char ub; | ||
88 | unsigned short attr; | ||
89 | unsigned short offset; | ||
90 | struct field_t *fields; | ||
91 | } field_t; | ||
92 | |||
93 | /* Bit Stream */ | ||
94 | typedef struct { | ||
95 | unsigned char *buf; | ||
96 | unsigned char *beg; | ||
97 | unsigned char *end; | ||
98 | unsigned char *cur; | ||
99 | unsigned bit; | ||
100 | } bitstr_t; | ||
101 | |||
102 | /* Tool Functions */ | ||
103 | #define INC_BIT(bs) if((++bs->bit)>7){bs->cur++;bs->bit=0;} | ||
104 | #define INC_BITS(bs,b) if((bs->bit+=b)>7){bs->cur+=bs->bit>>3;bs->bit&=7;} | ||
105 | #define BYTE_ALIGN(bs) if(bs->bit){bs->cur++;bs->bit=0;} | ||
106 | #define CHECK_BOUND(bs,n) if(bs->cur+(n)>bs->end)return(H323_ERROR_BOUND) | ||
107 | static unsigned get_len(bitstr_t * bs); | ||
108 | static unsigned get_bit(bitstr_t * bs); | ||
109 | static unsigned get_bits(bitstr_t * bs, unsigned b); | ||
110 | static unsigned get_bitmap(bitstr_t * bs, unsigned b); | ||
111 | static unsigned get_uint(bitstr_t * bs, int b); | ||
112 | |||
113 | /* Decoder Functions */ | ||
114 | static int decode_nul(bitstr_t * bs, field_t * f, char *base, int level); | ||
115 | static int decode_bool(bitstr_t * bs, field_t * f, char *base, int level); | ||
116 | static int decode_oid(bitstr_t * bs, field_t * f, char *base, int level); | ||
117 | static int decode_int(bitstr_t * bs, field_t * f, char *base, int level); | ||
118 | static int decode_enum(bitstr_t * bs, field_t * f, char *base, int level); | ||
119 | static int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level); | ||
120 | static int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level); | ||
121 | static int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level); | ||
122 | static int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level); | ||
123 | static int decode_seq(bitstr_t * bs, field_t * f, char *base, int level); | ||
124 | static int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level); | ||
125 | static int decode_choice(bitstr_t * bs, field_t * f, char *base, int level); | ||
126 | |||
127 | /* Decoder Functions Vector */ | ||
128 | typedef int (*decoder_t) (bitstr_t *, field_t *, char *, int); | ||
129 | static decoder_t Decoders[] = { | ||
130 | decode_nul, | ||
131 | decode_bool, | ||
132 | decode_oid, | ||
133 | decode_int, | ||
134 | decode_enum, | ||
135 | decode_bitstr, | ||
136 | decode_numstr, | ||
137 | decode_octstr, | ||
138 | decode_bmpstr, | ||
139 | decode_seq, | ||
140 | decode_seqof, | ||
141 | decode_choice, | ||
142 | }; | ||
143 | |||
144 | /**************************************************************************** | ||
145 | * H.323 Types | ||
146 | ****************************************************************************/ | ||
147 | #include "ip_conntrack_helper_h323_types.c" | ||
148 | |||
149 | /**************************************************************************** | ||
150 | * Functions | ||
151 | ****************************************************************************/ | ||
152 | /* Assume bs is aligned && v < 16384 */ | ||
153 | unsigned get_len(bitstr_t * bs) | ||
154 | { | ||
155 | unsigned v; | ||
156 | |||
157 | v = *bs->cur++; | ||
158 | |||
159 | if (v & 0x80) { | ||
160 | v &= 0x3f; | ||
161 | v <<= 8; | ||
162 | v += *bs->cur++; | ||
163 | } | ||
164 | |||
165 | return v; | ||
166 | } | ||
167 | |||
168 | /****************************************************************************/ | ||
169 | unsigned get_bit(bitstr_t * bs) | ||
170 | { | ||
171 | unsigned b = (*bs->cur) & (0x80 >> bs->bit); | ||
172 | |||
173 | INC_BIT(bs); | ||
174 | |||
175 | return b; | ||
176 | } | ||
177 | |||
178 | /****************************************************************************/ | ||
179 | /* Assume b <= 8 */ | ||
180 | unsigned get_bits(bitstr_t * bs, unsigned b) | ||
181 | { | ||
182 | unsigned v, l; | ||
183 | |||
184 | v = (*bs->cur) & (0xffU >> bs->bit); | ||
185 | l = b + bs->bit; | ||
186 | |||
187 | if (l < 8) { | ||
188 | v >>= 8 - l; | ||
189 | bs->bit = l; | ||
190 | } else if (l == 8) { | ||
191 | bs->cur++; | ||
192 | bs->bit = 0; | ||
193 | } else { /* l > 8 */ | ||
194 | |||
195 | v <<= 8; | ||
196 | v += *(++bs->cur); | ||
197 | v >>= 16 - l; | ||
198 | bs->bit = l - 8; | ||
199 | } | ||
200 | |||
201 | return v; | ||
202 | } | ||
203 | |||
204 | /****************************************************************************/ | ||
205 | /* Assume b <= 32 */ | ||
206 | unsigned get_bitmap(bitstr_t * bs, unsigned b) | ||
207 | { | ||
208 | unsigned v, l, shift, bytes; | ||
209 | |||
210 | if (!b) | ||
211 | return 0; | ||
212 | |||
213 | l = bs->bit + b; | ||
214 | |||
215 | if (l < 8) { | ||
216 | v = (unsigned) (*bs->cur) << (bs->bit + 24); | ||
217 | bs->bit = l; | ||
218 | } else if (l == 8) { | ||
219 | v = (unsigned) (*bs->cur++) << (bs->bit + 24); | ||
220 | bs->bit = 0; | ||
221 | } else { | ||
222 | for (bytes = l >> 3, shift = 24, v = 0; bytes; | ||
223 | bytes--, shift -= 8) | ||
224 | v |= (unsigned) (*bs->cur++) << shift; | ||
225 | |||
226 | if (l < 32) { | ||
227 | v |= (unsigned) (*bs->cur) << shift; | ||
228 | v <<= bs->bit; | ||
229 | } else if (l > 32) { | ||
230 | v <<= bs->bit; | ||
231 | v |= (*bs->cur) >> (8 - bs->bit); | ||
232 | } | ||
233 | |||
234 | bs->bit = l & 0x7; | ||
235 | } | ||
236 | |||
237 | v &= 0xffffffff << (32 - b); | ||
238 | |||
239 | return v; | ||
240 | } | ||
241 | |||
242 | /**************************************************************************** | ||
243 | * Assume bs is aligned and sizeof(unsigned int) == 4 | ||
244 | ****************************************************************************/ | ||
245 | unsigned get_uint(bitstr_t * bs, int b) | ||
246 | { | ||
247 | unsigned v = 0; | ||
248 | |||
249 | switch (b) { | ||
250 | case 4: | ||
251 | v |= *bs->cur++; | ||
252 | v <<= 8; | ||
253 | case 3: | ||
254 | v |= *bs->cur++; | ||
255 | v <<= 8; | ||
256 | case 2: | ||
257 | v |= *bs->cur++; | ||
258 | v <<= 8; | ||
259 | case 1: | ||
260 | v |= *bs->cur++; | ||
261 | break; | ||
262 | } | ||
263 | return v; | ||
264 | } | ||
265 | |||
266 | /****************************************************************************/ | ||
267 | int decode_nul(bitstr_t * bs, field_t * f, char *base, int level) | ||
268 | { | ||
269 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
270 | |||
271 | return H323_ERROR_NONE; | ||
272 | } | ||
273 | |||
274 | /****************************************************************************/ | ||
275 | int decode_bool(bitstr_t * bs, field_t * f, char *base, int level) | ||
276 | { | ||
277 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
278 | |||
279 | INC_BIT(bs); | ||
280 | |||
281 | CHECK_BOUND(bs, 0); | ||
282 | return H323_ERROR_NONE; | ||
283 | } | ||
284 | |||
285 | /****************************************************************************/ | ||
286 | int decode_oid(bitstr_t * bs, field_t * f, char *base, int level) | ||
287 | { | ||
288 | int len; | ||
289 | |||
290 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
291 | |||
292 | BYTE_ALIGN(bs); | ||
293 | CHECK_BOUND(bs, 1); | ||
294 | len = *bs->cur++; | ||
295 | bs->cur += len; | ||
296 | |||
297 | CHECK_BOUND(bs, 0); | ||
298 | return H323_ERROR_NONE; | ||
299 | } | ||
300 | |||
301 | /****************************************************************************/ | ||
302 | int decode_int(bitstr_t * bs, field_t * f, char *base, int level) | ||
303 | { | ||
304 | unsigned len; | ||
305 | |||
306 | PRINT("%*.s%s", level * TAB_SIZE, " ", f->name); | ||
307 | |||
308 | switch (f->sz) { | ||
309 | case BYTE: /* Range == 256 */ | ||
310 | BYTE_ALIGN(bs); | ||
311 | bs->cur++; | ||
312 | break; | ||
313 | case WORD: /* 257 <= Range <= 64K */ | ||
314 | BYTE_ALIGN(bs); | ||
315 | bs->cur += 2; | ||
316 | break; | ||
317 | case CONS: /* 64K < Range < 4G */ | ||
318 | len = get_bits(bs, 2) + 1; | ||
319 | BYTE_ALIGN(bs); | ||
320 | if (base && (f->attr & DECODE)) { /* timeToLive */ | ||
321 | unsigned v = get_uint(bs, len) + f->lb; | ||
322 | PRINT(" = %u", v); | ||
323 | *((unsigned *) (base + f->offset)) = v; | ||
324 | } | ||
325 | bs->cur += len; | ||
326 | break; | ||
327 | case UNCO: | ||
328 | BYTE_ALIGN(bs); | ||
329 | CHECK_BOUND(bs, 2); | ||
330 | len = get_len(bs); | ||
331 | bs->cur += len; | ||
332 | break; | ||
333 | default: /* 2 <= Range <= 255 */ | ||
334 | INC_BITS(bs, f->sz); | ||
335 | break; | ||
336 | } | ||
337 | |||
338 | PRINT("\n"); | ||
339 | |||
340 | CHECK_BOUND(bs, 0); | ||
341 | return H323_ERROR_NONE; | ||
342 | } | ||
343 | |||
344 | /****************************************************************************/ | ||
345 | int decode_enum(bitstr_t * bs, field_t * f, char *base, int level) | ||
346 | { | ||
347 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
348 | |||
349 | if ((f->attr & EXT) && get_bit(bs)) { | ||
350 | INC_BITS(bs, 7); | ||
351 | } else { | ||
352 | INC_BITS(bs, f->sz); | ||
353 | } | ||
354 | |||
355 | CHECK_BOUND(bs, 0); | ||
356 | return H323_ERROR_NONE; | ||
357 | } | ||
358 | |||
359 | /****************************************************************************/ | ||
360 | int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level) | ||
361 | { | ||
362 | unsigned len; | ||
363 | |||
364 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
365 | |||
366 | BYTE_ALIGN(bs); | ||
367 | switch (f->sz) { | ||
368 | case FIXD: /* fixed length > 16 */ | ||
369 | len = f->lb; | ||
370 | break; | ||
371 | case WORD: /* 2-byte length */ | ||
372 | CHECK_BOUND(bs, 2); | ||
373 | len = (*bs->cur++) << 8; | ||
374 | len += (*bs->cur++) + f->lb; | ||
375 | break; | ||
376 | case SEMI: | ||
377 | CHECK_BOUND(bs, 2); | ||
378 | len = get_len(bs); | ||
379 | break; | ||
380 | default: | ||
381 | len = 0; | ||
382 | break; | ||
383 | } | ||
384 | |||
385 | bs->cur += len >> 3; | ||
386 | bs->bit = len & 7; | ||
387 | |||
388 | CHECK_BOUND(bs, 0); | ||
389 | return H323_ERROR_NONE; | ||
390 | } | ||
391 | |||
392 | /****************************************************************************/ | ||
393 | int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level) | ||
394 | { | ||
395 | unsigned len; | ||
396 | |||
397 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
398 | |||
399 | /* 2 <= Range <= 255 */ | ||
400 | len = get_bits(bs, f->sz) + f->lb; | ||
401 | |||
402 | BYTE_ALIGN(bs); | ||
403 | INC_BITS(bs, (len << 2)); | ||
404 | |||
405 | CHECK_BOUND(bs, 0); | ||
406 | return H323_ERROR_NONE; | ||
407 | } | ||
408 | |||
409 | /****************************************************************************/ | ||
410 | int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level) | ||
411 | { | ||
412 | unsigned len; | ||
413 | |||
414 | PRINT("%*.s%s", level * TAB_SIZE, " ", f->name); | ||
415 | |||
416 | switch (f->sz) { | ||
417 | case FIXD: /* Range == 1 */ | ||
418 | if (f->lb > 2) { | ||
419 | BYTE_ALIGN(bs); | ||
420 | if (base && (f->attr & DECODE)) { | ||
421 | /* The IP Address */ | ||
422 | IFTHEN(f->lb == 4, | ||
423 | PRINT(" = %d.%d.%d.%d:%d", | ||
424 | bs->cur[0], bs->cur[1], | ||
425 | bs->cur[2], bs->cur[3], | ||
426 | bs->cur[4] * 256 + bs->cur[5])); | ||
427 | *((unsigned *) (base + f->offset)) = | ||
428 | bs->cur - bs->buf; | ||
429 | } | ||
430 | } | ||
431 | len = f->lb; | ||
432 | break; | ||
433 | case BYTE: /* Range == 256 */ | ||
434 | BYTE_ALIGN(bs); | ||
435 | CHECK_BOUND(bs, 1); | ||
436 | len = (*bs->cur++) + f->lb; | ||
437 | break; | ||
438 | case SEMI: | ||
439 | BYTE_ALIGN(bs); | ||
440 | CHECK_BOUND(bs, 2); | ||
441 | len = get_len(bs) + f->lb; | ||
442 | break; | ||
443 | default: /* 2 <= Range <= 255 */ | ||
444 | len = get_bits(bs, f->sz) + f->lb; | ||
445 | BYTE_ALIGN(bs); | ||
446 | break; | ||
447 | } | ||
448 | |||
449 | bs->cur += len; | ||
450 | |||
451 | PRINT("\n"); | ||
452 | |||
453 | CHECK_BOUND(bs, 0); | ||
454 | return H323_ERROR_NONE; | ||
455 | } | ||
456 | |||
457 | /****************************************************************************/ | ||
458 | int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level) | ||
459 | { | ||
460 | unsigned len; | ||
461 | |||
462 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
463 | |||
464 | switch (f->sz) { | ||
465 | case BYTE: /* Range == 256 */ | ||
466 | BYTE_ALIGN(bs); | ||
467 | CHECK_BOUND(bs, 1); | ||
468 | len = (*bs->cur++) + f->lb; | ||
469 | break; | ||
470 | default: /* 2 <= Range <= 255 */ | ||
471 | len = get_bits(bs, f->sz) + f->lb; | ||
472 | BYTE_ALIGN(bs); | ||
473 | break; | ||
474 | } | ||
475 | |||
476 | bs->cur += len << 1; | ||
477 | |||
478 | CHECK_BOUND(bs, 0); | ||
479 | return H323_ERROR_NONE; | ||
480 | } | ||
481 | |||
482 | /****************************************************************************/ | ||
483 | int decode_seq(bitstr_t * bs, field_t * f, char *base, int level) | ||
484 | { | ||
485 | unsigned ext, bmp, i, opt, len = 0, bmp2, bmp2_len; | ||
486 | int err; | ||
487 | field_t *son; | ||
488 | unsigned char *beg = NULL; | ||
489 | |||
490 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
491 | |||
492 | /* Decode? */ | ||
493 | base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; | ||
494 | |||
495 | /* Extensible? */ | ||
496 | ext = (f->attr & EXT) ? get_bit(bs) : 0; | ||
497 | |||
498 | /* Get fields bitmap */ | ||
499 | bmp = get_bitmap(bs, f->sz); | ||
500 | if (base) | ||
501 | *(unsigned *) base = bmp; | ||
502 | |||
503 | /* Decode the root components */ | ||
504 | for (i = opt = 0, son = f->fields; i < f->lb; i++, son++) { | ||
505 | if (son->attr & STOP) { | ||
506 | PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", | ||
507 | son->name); | ||
508 | return H323_ERROR_STOP; | ||
509 | } | ||
510 | |||
511 | if (son->attr & OPT) { /* Optional component */ | ||
512 | if (!((0x80000000U >> (opt++)) & bmp)) /* Not exist */ | ||
513 | continue; | ||
514 | } | ||
515 | |||
516 | /* Decode */ | ||
517 | if (son->attr & OPEN) { /* Open field */ | ||
518 | CHECK_BOUND(bs, 2); | ||
519 | len = get_len(bs); | ||
520 | CHECK_BOUND(bs, len); | ||
521 | if (!base) { | ||
522 | PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, | ||
523 | " ", son->name); | ||
524 | bs->cur += len; | ||
525 | continue; | ||
526 | } | ||
527 | beg = bs->cur; | ||
528 | |||
529 | /* Decode */ | ||
530 | if ((err = (Decoders[son->type]) (bs, son, base, | ||
531 | level + 1)) > | ||
532 | H323_ERROR_STOP) | ||
533 | return err; | ||
534 | |||
535 | bs->cur = beg + len; | ||
536 | bs->bit = 0; | ||
537 | } else if ((err = (Decoders[son->type]) (bs, son, base, | ||
538 | level + 1))) | ||
539 | return err; | ||
540 | } | ||
541 | |||
542 | /* No extension? */ | ||
543 | if (!ext) | ||
544 | return H323_ERROR_NONE; | ||
545 | |||
546 | /* Get the extension bitmap */ | ||
547 | bmp2_len = get_bits(bs, 7) + 1; | ||
548 | CHECK_BOUND(bs, (bmp2_len + 7) >> 3); | ||
549 | bmp2 = get_bitmap(bs, bmp2_len); | ||
550 | bmp |= bmp2 >> f->sz; | ||
551 | if (base) | ||
552 | *(unsigned *) base = bmp; | ||
553 | BYTE_ALIGN(bs); | ||
554 | |||
555 | /* Decode the extension components */ | ||
556 | for (opt = 0; opt < bmp2_len; opt++, i++, son++) { | ||
557 | if (son->attr & STOP) { | ||
558 | PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", | ||
559 | son->name); | ||
560 | return H323_ERROR_STOP; | ||
561 | } | ||
562 | |||
563 | if (!((0x80000000 >> opt) & bmp2)) /* Not present */ | ||
564 | continue; | ||
565 | |||
566 | /* Check Range */ | ||
567 | if (i >= f->ub) { /* Newer Version? */ | ||
568 | CHECK_BOUND(bs, 2); | ||
569 | len = get_len(bs); | ||
570 | CHECK_BOUND(bs, len); | ||
571 | bs->cur += len; | ||
572 | continue; | ||
573 | } | ||
574 | |||
575 | CHECK_BOUND(bs, 2); | ||
576 | len = get_len(bs); | ||
577 | CHECK_BOUND(bs, len); | ||
578 | if (!base || !(son->attr & DECODE)) { | ||
579 | PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", | ||
580 | son->name); | ||
581 | bs->cur += len; | ||
582 | continue; | ||
583 | } | ||
584 | beg = bs->cur; | ||
585 | |||
586 | if ((err = (Decoders[son->type]) (bs, son, base, | ||
587 | level + 1)) > | ||
588 | H323_ERROR_STOP) | ||
589 | return err; | ||
590 | |||
591 | bs->cur = beg + len; | ||
592 | bs->bit = 0; | ||
593 | } | ||
594 | return H323_ERROR_NONE; | ||
595 | } | ||
596 | |||
597 | /****************************************************************************/ | ||
598 | int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level) | ||
599 | { | ||
600 | unsigned count, effective_count = 0, i, len = 0; | ||
601 | int err; | ||
602 | field_t *son; | ||
603 | unsigned char *beg = NULL; | ||
604 | |||
605 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
606 | |||
607 | /* Decode? */ | ||
608 | base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; | ||
609 | |||
610 | /* Decode item count */ | ||
611 | switch (f->sz) { | ||
612 | case BYTE: | ||
613 | BYTE_ALIGN(bs); | ||
614 | CHECK_BOUND(bs, 1); | ||
615 | count = *bs->cur++; | ||
616 | break; | ||
617 | case WORD: | ||
618 | BYTE_ALIGN(bs); | ||
619 | CHECK_BOUND(bs, 2); | ||
620 | count = *bs->cur++; | ||
621 | count <<= 8; | ||
622 | count = *bs->cur++; | ||
623 | break; | ||
624 | case SEMI: | ||
625 | BYTE_ALIGN(bs); | ||
626 | CHECK_BOUND(bs, 2); | ||
627 | count = get_len(bs); | ||
628 | break; | ||
629 | default: | ||
630 | count = get_bits(bs, f->sz); | ||
631 | break; | ||
632 | } | ||
633 | count += f->lb; | ||
634 | |||
635 | /* Write Count */ | ||
636 | if (base) { | ||
637 | effective_count = count > f->ub ? f->ub : count; | ||
638 | *(unsigned *) base = effective_count; | ||
639 | base += sizeof(unsigned); | ||
640 | } | ||
641 | |||
642 | /* Decode nested field */ | ||
643 | son = f->fields; | ||
644 | if (base) | ||
645 | base -= son->offset; | ||
646 | for (i = 0; i < count; i++) { | ||
647 | if (son->attr & OPEN) { | ||
648 | BYTE_ALIGN(bs); | ||
649 | len = get_len(bs); | ||
650 | CHECK_BOUND(bs, len); | ||
651 | if (!base || !(son->attr & DECODE)) { | ||
652 | PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, | ||
653 | " ", son->name); | ||
654 | bs->cur += len; | ||
655 | continue; | ||
656 | } | ||
657 | beg = bs->cur; | ||
658 | |||
659 | if ((err = (Decoders[son->type]) (bs, son, | ||
660 | i < | ||
661 | effective_count ? | ||
662 | base : NULL, | ||
663 | level + 1)) > | ||
664 | H323_ERROR_STOP) | ||
665 | return err; | ||
666 | |||
667 | bs->cur = beg + len; | ||
668 | bs->bit = 0; | ||
669 | } else | ||
670 | if ((err = (Decoders[son->type]) (bs, son, | ||
671 | i < effective_count ? | ||
672 | base : NULL, | ||
673 | level + 1))) | ||
674 | return err; | ||
675 | |||
676 | if (base) | ||
677 | base += son->offset; | ||
678 | } | ||
679 | |||
680 | return H323_ERROR_NONE; | ||
681 | } | ||
682 | |||
683 | |||
684 | /****************************************************************************/ | ||
685 | int decode_choice(bitstr_t * bs, field_t * f, char *base, int level) | ||
686 | { | ||
687 | unsigned type, ext, len = 0; | ||
688 | int err; | ||
689 | field_t *son; | ||
690 | unsigned char *beg = NULL; | ||
691 | |||
692 | PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name); | ||
693 | |||
694 | /* Decode? */ | ||
695 | base = (base && (f->attr & DECODE)) ? base + f->offset : NULL; | ||
696 | |||
697 | /* Decode the choice index number */ | ||
698 | if ((f->attr & EXT) && get_bit(bs)) { | ||
699 | ext = 1; | ||
700 | type = get_bits(bs, 7) + f->lb; | ||
701 | } else { | ||
702 | ext = 0; | ||
703 | type = get_bits(bs, f->sz); | ||
704 | } | ||
705 | |||
706 | /* Check Range */ | ||
707 | if (type >= f->ub) { /* Newer version? */ | ||
708 | BYTE_ALIGN(bs); | ||
709 | len = get_len(bs); | ||
710 | CHECK_BOUND(bs, len); | ||
711 | bs->cur += len; | ||
712 | return H323_ERROR_NONE; | ||
713 | } | ||
714 | |||
715 | /* Write Type */ | ||
716 | if (base) | ||
717 | *(unsigned *) base = type; | ||
718 | |||
719 | /* Transfer to son level */ | ||
720 | son = &f->fields[type]; | ||
721 | if (son->attr & STOP) { | ||
722 | PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", son->name); | ||
723 | return H323_ERROR_STOP; | ||
724 | } | ||
725 | |||
726 | if (ext || (son->attr & OPEN)) { | ||
727 | BYTE_ALIGN(bs); | ||
728 | len = get_len(bs); | ||
729 | CHECK_BOUND(bs, len); | ||
730 | if (!base || !(son->attr & DECODE)) { | ||
731 | PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", | ||
732 | son->name); | ||
733 | bs->cur += len; | ||
734 | return H323_ERROR_NONE; | ||
735 | } | ||
736 | beg = bs->cur; | ||
737 | |||
738 | if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) > | ||
739 | H323_ERROR_STOP) | ||
740 | return err; | ||
741 | |||
742 | bs->cur = beg + len; | ||
743 | bs->bit = 0; | ||
744 | } else if ((err = (Decoders[son->type]) (bs, son, base, level + 1))) | ||
745 | return err; | ||
746 | |||
747 | return H323_ERROR_NONE; | ||
748 | } | ||
749 | |||
750 | /****************************************************************************/ | ||
751 | int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras) | ||
752 | { | ||
753 | static field_t ras_message = { | ||
754 | FNAME("RasMessage") CHOICE, 5, 24, 32, DECODE | EXT, | ||
755 | 0, _RasMessage | ||
756 | }; | ||
757 | bitstr_t bs; | ||
758 | |||
759 | bs.buf = bs.beg = bs.cur = buf; | ||
760 | bs.end = buf + sz; | ||
761 | bs.bit = 0; | ||
762 | |||
763 | return decode_choice(&bs, &ras_message, (char *) ras, 0); | ||
764 | } | ||
765 | |||
766 | /****************************************************************************/ | ||
767 | static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg, | ||
768 | size_t sz, H323_UserInformation * uuie) | ||
769 | { | ||
770 | static field_t h323_userinformation = { | ||
771 | FNAME("H323-UserInformation") SEQ, 1, 2, 2, DECODE | EXT, | ||
772 | 0, _H323_UserInformation | ||
773 | }; | ||
774 | bitstr_t bs; | ||
775 | |||
776 | bs.buf = buf; | ||
777 | bs.beg = bs.cur = beg; | ||
778 | bs.end = beg + sz; | ||
779 | bs.bit = 0; | ||
780 | |||
781 | return decode_seq(&bs, &h323_userinformation, (char *) uuie, 0); | ||
782 | } | ||
783 | |||
784 | /****************************************************************************/ | ||
785 | int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz, | ||
786 | MultimediaSystemControlMessage * | ||
787 | mscm) | ||
788 | { | ||
789 | static field_t multimediasystemcontrolmessage = { | ||
790 | FNAME("MultimediaSystemControlMessage") CHOICE, 2, 4, 4, | ||
791 | DECODE | EXT, 0, _MultimediaSystemControlMessage | ||
792 | }; | ||
793 | bitstr_t bs; | ||
794 | |||
795 | bs.buf = bs.beg = bs.cur = buf; | ||
796 | bs.end = buf + sz; | ||
797 | bs.bit = 0; | ||
798 | |||
799 | return decode_choice(&bs, &multimediasystemcontrolmessage, | ||
800 | (char *) mscm, 0); | ||
801 | } | ||
802 | |||
803 | /****************************************************************************/ | ||
804 | int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931) | ||
805 | { | ||
806 | unsigned char *p = buf; | ||
807 | int len; | ||
808 | |||
809 | if (!p || sz < 1) | ||
810 | return H323_ERROR_BOUND; | ||
811 | |||
812 | /* Protocol Discriminator */ | ||
813 | if (*p != 0x08) { | ||
814 | PRINT("Unknown Protocol Discriminator\n"); | ||
815 | return H323_ERROR_RANGE; | ||
816 | } | ||
817 | p++; | ||
818 | sz--; | ||
819 | |||
820 | /* CallReferenceValue */ | ||
821 | if (sz < 1) | ||
822 | return H323_ERROR_BOUND; | ||
823 | len = *p++; | ||
824 | sz--; | ||
825 | if (sz < len) | ||
826 | return H323_ERROR_BOUND; | ||
827 | p += len; | ||
828 | sz -= len; | ||
829 | |||
830 | /* Message Type */ | ||
831 | if (sz < 1) | ||
832 | return H323_ERROR_BOUND; | ||
833 | q931->MessageType = *p++; | ||
834 | PRINT("MessageType = %02X\n", q931->MessageType); | ||
835 | if (*p & 0x80) { | ||
836 | p++; | ||
837 | sz--; | ||
838 | } | ||
839 | |||
840 | /* Decode Information Elements */ | ||
841 | while (sz > 0) { | ||
842 | if (*p == 0x7e) { /* UserUserIE */ | ||
843 | if (sz < 3) | ||
844 | break; | ||
845 | p++; | ||
846 | len = *p++ << 8; | ||
847 | len |= *p++; | ||
848 | sz -= 3; | ||
849 | if (sz < len) | ||
850 | break; | ||
851 | p++; | ||
852 | len--; | ||
853 | return DecodeH323_UserInformation(buf, p, len, | ||
854 | &q931->UUIE); | ||
855 | } | ||
856 | p++; | ||
857 | sz--; | ||
858 | if (sz < 1) | ||
859 | break; | ||
860 | len = *p++; | ||
861 | if (sz < len) | ||
862 | break; | ||
863 | p += len; | ||
864 | sz -= len; | ||
865 | } | ||
866 | |||
867 | PRINT("Q.931 UUIE not found\n"); | ||
868 | |||
869 | return H323_ERROR_BOUND; | ||
870 | } | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.h b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.h new file mode 100644 index 000000000000..0bd828081c0c --- /dev/null +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.h | |||
@@ -0,0 +1,98 @@ | |||
1 | /**************************************************************************** | ||
2 | * ip_conntrack_helper_h323_asn1.h - BER and PER decoding library for H.323 | ||
3 | * conntrack/NAT module. | ||
4 | * | ||
5 | * Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@hotmail.com> | ||
6 | * | ||
7 | * This source code is licensed under General Public License version 2. | ||
8 | * | ||
9 | * | ||
10 | * This library is based on H.225 version 4, H.235 version 2 and H.245 | ||
11 | * version 7. It is extremely optimized to decode only the absolutely | ||
12 | * necessary objects in a signal for Linux kernel NAT module use, so don't | ||
13 | * expect it to be a full ASN.1 library. | ||
14 | * | ||
15 | * Features: | ||
16 | * | ||
17 | * 1. Small. The total size of code plus data is less than 20 KB (IA32). | ||
18 | * 2. Fast. Decoding Netmeeting's Setup signal 1 million times on a PIII 866 | ||
19 | * takes only 3.9 seconds. | ||
20 | * 3. No memory allocation. It uses a static object. No need to initialize or | ||
21 | * cleanup. | ||
22 | * 4. Thread safe. | ||
23 | * 5. Support embedded architectures that has no misaligned memory access | ||
24 | * support. | ||
25 | * | ||
26 | * Limitations: | ||
27 | * | ||
28 | * 1. At most 30 faststart entries. Actually this is limited by ethernet's MTU. | ||
29 | * If a Setup signal contains more than 30 faststart, the packet size will | ||
30 | * very likely exceed the MTU size, then the TPKT will be fragmented. I | ||
31 | * don't know how to handle this in a Netfilter module. Anybody can help? | ||
32 | * Although I think 30 is enough for most of the cases. | ||
33 | * 2. IPv4 addresses only. | ||
34 | * | ||
35 | ****************************************************************************/ | ||
36 | |||
37 | #ifndef _IP_CONNTRACK_HELPER_H323_ASN1_H_ | ||
38 | #define _IP_CONNTRACK_HELPER_H323_ASN1_H_ | ||
39 | |||
40 | /***************************************************************************** | ||
41 | * H.323 Types | ||
42 | ****************************************************************************/ | ||
43 | #include "ip_conntrack_helper_h323_types.h" | ||
44 | |||
45 | typedef struct { | ||
46 | enum { | ||
47 | Q931_NationalEscape = 0x00, | ||
48 | Q931_Alerting = 0x01, | ||
49 | Q931_CallProceeding = 0x02, | ||
50 | Q931_Connect = 0x07, | ||
51 | Q931_ConnectAck = 0x0F, | ||
52 | Q931_Progress = 0x03, | ||
53 | Q931_Setup = 0x05, | ||
54 | Q931_SetupAck = 0x0D, | ||
55 | Q931_Resume = 0x26, | ||
56 | Q931_ResumeAck = 0x2E, | ||
57 | Q931_ResumeReject = 0x22, | ||
58 | Q931_Suspend = 0x25, | ||
59 | Q931_SuspendAck = 0x2D, | ||
60 | Q931_SuspendReject = 0x21, | ||
61 | Q931_UserInformation = 0x20, | ||
62 | Q931_Disconnect = 0x45, | ||
63 | Q931_Release = 0x4D, | ||
64 | Q931_ReleaseComplete = 0x5A, | ||
65 | Q931_Restart = 0x46, | ||
66 | Q931_RestartAck = 0x4E, | ||
67 | Q931_Segment = 0x60, | ||
68 | Q931_CongestionCtrl = 0x79, | ||
69 | Q931_Information = 0x7B, | ||
70 | Q931_Notify = 0x6E, | ||
71 | Q931_Status = 0x7D, | ||
72 | Q931_StatusEnquiry = 0x75, | ||
73 | Q931_Facility = 0x62 | ||
74 | } MessageType; | ||
75 | H323_UserInformation UUIE; | ||
76 | } Q931; | ||
77 | |||
78 | /***************************************************************************** | ||
79 | * Decode Functions Return Codes | ||
80 | ****************************************************************************/ | ||
81 | |||
82 | #define H323_ERROR_NONE 0 /* Decoded successfully */ | ||
83 | #define H323_ERROR_STOP 1 /* Decoding stopped, not really an error */ | ||
84 | #define H323_ERROR_BOUND -1 | ||
85 | #define H323_ERROR_RANGE -2 | ||
86 | |||
87 | |||
88 | /***************************************************************************** | ||
89 | * Decode Functions | ||
90 | ****************************************************************************/ | ||
91 | |||
92 | int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras); | ||
93 | int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931); | ||
94 | int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz, | ||
95 | MultimediaSystemControlMessage * | ||
96 | mscm); | ||
97 | |||
98 | #endif | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c new file mode 100644 index 000000000000..022c47b9f6c9 --- /dev/null +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.c | |||
@@ -0,0 +1,1926 @@ | |||
1 | /* Generated by Jing Min Zhao's ASN.1 parser, Mar 15 2006 | ||
2 | * | ||
3 | * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net> | ||
4 | * | ||
5 | * This source code is licensed under General Public License version 2. | ||
6 | */ | ||
7 | |||
8 | static field_t _TransportAddress_ipAddress[] = { /* SEQUENCE */ | ||
9 | {FNAME("ip") OCTSTR, FIXD, 4, 0, DECODE, | ||
10 | offsetof(TransportAddress_ipAddress, ip), NULL}, | ||
11 | {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
12 | }; | ||
13 | |||
14 | static field_t _TransportAddress_ipSourceRoute_route[] = { /* SEQUENCE OF */ | ||
15 | {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, | ||
16 | }; | ||
17 | |||
18 | static field_t _TransportAddress_ipSourceRoute_routing[] = { /* CHOICE */ | ||
19 | {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
20 | {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
21 | }; | ||
22 | |||
23 | static field_t _TransportAddress_ipSourceRoute[] = { /* SEQUENCE */ | ||
24 | {FNAME("ip") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, | ||
25 | {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
26 | {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0, | ||
27 | _TransportAddress_ipSourceRoute_route}, | ||
28 | {FNAME("routing") CHOICE, 1, 2, 2, SKIP | EXT, 0, | ||
29 | _TransportAddress_ipSourceRoute_routing}, | ||
30 | }; | ||
31 | |||
32 | static field_t _TransportAddress_ipxAddress[] = { /* SEQUENCE */ | ||
33 | {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL}, | ||
34 | {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, | ||
35 | {FNAME("port") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL}, | ||
36 | }; | ||
37 | |||
38 | static field_t _TransportAddress_ip6Address[] = { /* SEQUENCE */ | ||
39 | {FNAME("ip") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
40 | {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
41 | }; | ||
42 | |||
43 | static field_t _H221NonStandard[] = { /* SEQUENCE */ | ||
44 | {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL}, | ||
45 | {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL}, | ||
46 | {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
47 | }; | ||
48 | |||
49 | static field_t _NonStandardIdentifier[] = { /* CHOICE */ | ||
50 | {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
51 | {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP | EXT, 0, | ||
52 | _H221NonStandard}, | ||
53 | }; | ||
54 | |||
55 | static field_t _NonStandardParameter[] = { /* SEQUENCE */ | ||
56 | {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP | EXT, 0, | ||
57 | _NonStandardIdentifier}, | ||
58 | {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
59 | }; | ||
60 | |||
61 | static field_t _TransportAddress[] = { /* CHOICE */ | ||
62 | {FNAME("ipAddress") SEQ, 0, 2, 2, DECODE, | ||
63 | offsetof(TransportAddress, ipAddress), _TransportAddress_ipAddress}, | ||
64 | {FNAME("ipSourceRoute") SEQ, 0, 4, 4, SKIP | EXT, 0, | ||
65 | _TransportAddress_ipSourceRoute}, | ||
66 | {FNAME("ipxAddress") SEQ, 0, 3, 3, SKIP, 0, | ||
67 | _TransportAddress_ipxAddress}, | ||
68 | {FNAME("ip6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, | ||
69 | _TransportAddress_ip6Address}, | ||
70 | {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
71 | {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, | ||
72 | {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, | ||
73 | _NonStandardParameter}, | ||
74 | }; | ||
75 | |||
76 | static field_t _AliasAddress[] = { /* CHOICE */ | ||
77 | {FNAME("dialedDigits") NUMDGT, 7, 1, 0, SKIP, 0, NULL}, | ||
78 | {FNAME("h323-ID") BMPSTR, BYTE, 1, 0, SKIP, 0, NULL}, | ||
79 | {FNAME("url-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL}, | ||
80 | {FNAME("transportID") CHOICE, 3, 7, 7, SKIP | EXT, 0, NULL}, | ||
81 | {FNAME("email-ID") IA5STR, WORD, 1, 0, SKIP, 0, NULL}, | ||
82 | {FNAME("partyNumber") CHOICE, 3, 5, 5, SKIP | EXT, 0, NULL}, | ||
83 | {FNAME("mobileUIM") CHOICE, 1, 2, 2, SKIP | EXT, 0, NULL}, | ||
84 | }; | ||
85 | |||
86 | static field_t _Setup_UUIE_sourceAddress[] = { /* SEQUENCE OF */ | ||
87 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
88 | }; | ||
89 | |||
90 | static field_t _VendorIdentifier[] = { /* SEQUENCE */ | ||
91 | {FNAME("vendor") SEQ, 0, 3, 3, SKIP | EXT, 0, _H221NonStandard}, | ||
92 | {FNAME("productId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL}, | ||
93 | {FNAME("versionId") OCTSTR, BYTE, 1, 0, SKIP | OPT, 0, NULL}, | ||
94 | }; | ||
95 | |||
96 | static field_t _GatekeeperInfo[] = { /* SEQUENCE */ | ||
97 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
98 | _NonStandardParameter}, | ||
99 | }; | ||
100 | |||
101 | static field_t _H310Caps[] = { /* SEQUENCE */ | ||
102 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
103 | _NonStandardParameter}, | ||
104 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
105 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
106 | }; | ||
107 | |||
108 | static field_t _H320Caps[] = { /* SEQUENCE */ | ||
109 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
110 | _NonStandardParameter}, | ||
111 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
112 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
113 | }; | ||
114 | |||
115 | static field_t _H321Caps[] = { /* SEQUENCE */ | ||
116 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
117 | _NonStandardParameter}, | ||
118 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
119 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
120 | }; | ||
121 | |||
122 | static field_t _H322Caps[] = { /* SEQUENCE */ | ||
123 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
124 | _NonStandardParameter}, | ||
125 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
126 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
127 | }; | ||
128 | |||
129 | static field_t _H323Caps[] = { /* SEQUENCE */ | ||
130 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
131 | _NonStandardParameter}, | ||
132 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
133 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
134 | }; | ||
135 | |||
136 | static field_t _H324Caps[] = { /* SEQUENCE */ | ||
137 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
138 | _NonStandardParameter}, | ||
139 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
140 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
141 | }; | ||
142 | |||
143 | static field_t _VoiceCaps[] = { /* SEQUENCE */ | ||
144 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
145 | _NonStandardParameter}, | ||
146 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
147 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
148 | }; | ||
149 | |||
150 | static field_t _T120OnlyCaps[] = { /* SEQUENCE */ | ||
151 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
152 | _NonStandardParameter}, | ||
153 | {FNAME("dataRatesSupported") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
154 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, SKIP, 0, NULL}, | ||
155 | }; | ||
156 | |||
157 | static field_t _SupportedProtocols[] = { /* CHOICE */ | ||
158 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP, 0, | ||
159 | _NonStandardParameter}, | ||
160 | {FNAME("h310") SEQ, 1, 1, 3, SKIP | EXT, 0, _H310Caps}, | ||
161 | {FNAME("h320") SEQ, 1, 1, 3, SKIP | EXT, 0, _H320Caps}, | ||
162 | {FNAME("h321") SEQ, 1, 1, 3, SKIP | EXT, 0, _H321Caps}, | ||
163 | {FNAME("h322") SEQ, 1, 1, 3, SKIP | EXT, 0, _H322Caps}, | ||
164 | {FNAME("h323") SEQ, 1, 1, 3, SKIP | EXT, 0, _H323Caps}, | ||
165 | {FNAME("h324") SEQ, 1, 1, 3, SKIP | EXT, 0, _H324Caps}, | ||
166 | {FNAME("voice") SEQ, 1, 1, 3, SKIP | EXT, 0, _VoiceCaps}, | ||
167 | {FNAME("t120-only") SEQ, 1, 1, 3, SKIP | EXT, 0, _T120OnlyCaps}, | ||
168 | {FNAME("nonStandardProtocol") SEQ, 2, 3, 3, SKIP | EXT, 0, NULL}, | ||
169 | {FNAME("t38FaxAnnexbOnly") SEQ, 2, 5, 5, SKIP | EXT, 0, NULL}, | ||
170 | }; | ||
171 | |||
172 | static field_t _GatewayInfo_protocol[] = { /* SEQUENCE OF */ | ||
173 | {FNAME("item") CHOICE, 4, 9, 11, SKIP | EXT, 0, _SupportedProtocols}, | ||
174 | }; | ||
175 | |||
176 | static field_t _GatewayInfo[] = { /* SEQUENCE */ | ||
177 | {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
178 | _GatewayInfo_protocol}, | ||
179 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
180 | _NonStandardParameter}, | ||
181 | }; | ||
182 | |||
183 | static field_t _McuInfo[] = { /* SEQUENCE */ | ||
184 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
185 | _NonStandardParameter}, | ||
186 | {FNAME("protocol") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
187 | }; | ||
188 | |||
189 | static field_t _TerminalInfo[] = { /* SEQUENCE */ | ||
190 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
191 | _NonStandardParameter}, | ||
192 | }; | ||
193 | |||
194 | static field_t _EndpointType[] = { /* SEQUENCE */ | ||
195 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
196 | _NonStandardParameter}, | ||
197 | {FNAME("vendor") SEQ, 2, 3, 3, SKIP | EXT | OPT, 0, | ||
198 | _VendorIdentifier}, | ||
199 | {FNAME("gatekeeper") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0, | ||
200 | _GatekeeperInfo}, | ||
201 | {FNAME("gateway") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, _GatewayInfo}, | ||
202 | {FNAME("mcu") SEQ, 1, 1, 2, SKIP | EXT | OPT, 0, _McuInfo}, | ||
203 | {FNAME("terminal") SEQ, 1, 1, 1, SKIP | EXT | OPT, 0, _TerminalInfo}, | ||
204 | {FNAME("mc") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
205 | {FNAME("undefinedNode") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
206 | {FNAME("set") BITSTR, FIXD, 32, 0, SKIP | OPT, 0, NULL}, | ||
207 | {FNAME("supportedTunnelledProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT, | ||
208 | 0, NULL}, | ||
209 | }; | ||
210 | |||
211 | static field_t _Setup_UUIE_destinationAddress[] = { /* SEQUENCE OF */ | ||
212 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
213 | }; | ||
214 | |||
215 | static field_t _Setup_UUIE_destExtraCallInfo[] = { /* SEQUENCE OF */ | ||
216 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
217 | }; | ||
218 | |||
219 | static field_t _Setup_UUIE_destExtraCRV[] = { /* SEQUENCE OF */ | ||
220 | {FNAME("item") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
221 | }; | ||
222 | |||
223 | static field_t _Setup_UUIE_conferenceGoal[] = { /* CHOICE */ | ||
224 | {FNAME("create") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
225 | {FNAME("join") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
226 | {FNAME("invite") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
227 | {FNAME("capability-negotiation") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
228 | {FNAME("callIndependentSupplementaryService") NUL, FIXD, 0, 0, SKIP, | ||
229 | 0, NULL}, | ||
230 | }; | ||
231 | |||
232 | static field_t _Q954Details[] = { /* SEQUENCE */ | ||
233 | {FNAME("conferenceCalling") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
234 | {FNAME("threePartyService") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
235 | }; | ||
236 | |||
237 | static field_t _QseriesOptions[] = { /* SEQUENCE */ | ||
238 | {FNAME("q932Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
239 | {FNAME("q951Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
240 | {FNAME("q952Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
241 | {FNAME("q953Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
242 | {FNAME("q955Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
243 | {FNAME("q956Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
244 | {FNAME("q957Full") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
245 | {FNAME("q954Info") SEQ, 0, 2, 2, SKIP | EXT, 0, _Q954Details}, | ||
246 | }; | ||
247 | |||
248 | static field_t _CallType[] = { /* CHOICE */ | ||
249 | {FNAME("pointToPoint") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
250 | {FNAME("oneToN") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
251 | {FNAME("nToOne") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
252 | {FNAME("nToN") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
253 | }; | ||
254 | |||
255 | static field_t _H245_NonStandardIdentifier_h221NonStandard[] = { /* SEQUENCE */ | ||
256 | {FNAME("t35CountryCode") INT, BYTE, 0, 0, SKIP, 0, NULL}, | ||
257 | {FNAME("t35Extension") INT, BYTE, 0, 0, SKIP, 0, NULL}, | ||
258 | {FNAME("manufacturerCode") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
259 | }; | ||
260 | |||
261 | static field_t _H245_NonStandardIdentifier[] = { /* CHOICE */ | ||
262 | {FNAME("object") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
263 | {FNAME("h221NonStandard") SEQ, 0, 3, 3, SKIP, 0, | ||
264 | _H245_NonStandardIdentifier_h221NonStandard}, | ||
265 | }; | ||
266 | |||
267 | static field_t _H245_NonStandardParameter[] = { /* SEQUENCE */ | ||
268 | {FNAME("nonStandardIdentifier") CHOICE, 1, 2, 2, SKIP, 0, | ||
269 | _H245_NonStandardIdentifier}, | ||
270 | {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
271 | }; | ||
272 | |||
273 | static field_t _H261VideoCapability[] = { /* SEQUENCE */ | ||
274 | {FNAME("qcifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL}, | ||
275 | {FNAME("cifMPI") INT, 2, 1, 0, SKIP | OPT, 0, NULL}, | ||
276 | {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0, | ||
277 | NULL}, | ||
278 | {FNAME("maxBitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
279 | {FNAME("stillImageTransmission") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
280 | {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
281 | }; | ||
282 | |||
283 | static field_t _H262VideoCapability[] = { /* SEQUENCE */ | ||
284 | {FNAME("profileAndLevel-SPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
285 | {FNAME("profileAndLevel-MPatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
286 | {FNAME("profileAndLevel-MPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
287 | {FNAME("profileAndLevel-MPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
288 | {FNAME("profileAndLevel-MPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
289 | {FNAME("profileAndLevel-SNRatLL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
290 | {FNAME("profileAndLevel-SNRatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
291 | {FNAME("profileAndLevel-SpatialatH-14") BOOL, FIXD, 0, 0, SKIP, 0, | ||
292 | NULL}, | ||
293 | {FNAME("profileAndLevel-HPatML") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
294 | {FNAME("profileAndLevel-HPatH-14") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
295 | {FNAME("profileAndLevel-HPatHL") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
296 | {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, | ||
297 | {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, | ||
298 | {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
299 | {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
300 | {FNAME("framesPerSecond") INT, 4, 0, 0, SKIP | OPT, 0, NULL}, | ||
301 | {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, | ||
302 | {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
303 | }; | ||
304 | |||
305 | static field_t _H263VideoCapability[] = { /* SEQUENCE */ | ||
306 | {FNAME("sqcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, | ||
307 | {FNAME("qcifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, | ||
308 | {FNAME("cifMPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, | ||
309 | {FNAME("cif4MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, | ||
310 | {FNAME("cif16MPI") INT, 5, 1, 0, SKIP | OPT, 0, NULL}, | ||
311 | {FNAME("maxBitRate") INT, CONS, 1, 0, SKIP, 0, NULL}, | ||
312 | {FNAME("unrestrictedVector") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
313 | {FNAME("arithmeticCoding") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
314 | {FNAME("advancedPrediction") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
315 | {FNAME("pbFrames") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
316 | {FNAME("temporalSpatialTradeOffCapability") BOOL, FIXD, 0, 0, SKIP, 0, | ||
317 | NULL}, | ||
318 | {FNAME("hrd-B") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, | ||
319 | {FNAME("bppMaxKb") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
320 | {FNAME("slowSqcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
321 | {FNAME("slowQcifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
322 | {FNAME("slowCifMPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
323 | {FNAME("slowCif4MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
324 | {FNAME("slowCif16MPI") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
325 | {FNAME("errorCompensation") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
326 | {FNAME("enhancementLayerInfo") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, | ||
327 | NULL}, | ||
328 | {FNAME("h263Options") SEQ, 5, 29, 31, SKIP | EXT | OPT, 0, NULL}, | ||
329 | }; | ||
330 | |||
331 | static field_t _IS11172VideoCapability[] = { /* SEQUENCE */ | ||
332 | {FNAME("constrainedBitstream") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
333 | {FNAME("videoBitRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, | ||
334 | {FNAME("vbvBufferSize") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, | ||
335 | {FNAME("samplesPerLine") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
336 | {FNAME("linesPerFrame") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
337 | {FNAME("pictureRate") INT, 4, 0, 0, SKIP | OPT, 0, NULL}, | ||
338 | {FNAME("luminanceSampleRate") INT, CONS, 0, 0, SKIP | OPT, 0, NULL}, | ||
339 | {FNAME("videoBadMBsCap") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
340 | }; | ||
341 | |||
342 | static field_t _VideoCapability[] = { /* CHOICE */ | ||
343 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, | ||
344 | _H245_NonStandardParameter}, | ||
345 | {FNAME("h261VideoCapability") SEQ, 2, 5, 6, SKIP | EXT, 0, | ||
346 | _H261VideoCapability}, | ||
347 | {FNAME("h262VideoCapability") SEQ, 6, 17, 18, SKIP | EXT, 0, | ||
348 | _H262VideoCapability}, | ||
349 | {FNAME("h263VideoCapability") SEQ, 7, 13, 21, SKIP | EXT, 0, | ||
350 | _H263VideoCapability}, | ||
351 | {FNAME("is11172VideoCapability") SEQ, 6, 7, 8, SKIP | EXT, 0, | ||
352 | _IS11172VideoCapability}, | ||
353 | {FNAME("genericVideoCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, | ||
354 | }; | ||
355 | |||
356 | static field_t _AudioCapability_g7231[] = { /* SEQUENCE */ | ||
357 | {FNAME("maxAl-sduAudioFrames") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
358 | {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
359 | }; | ||
360 | |||
361 | static field_t _IS11172AudioCapability[] = { /* SEQUENCE */ | ||
362 | {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
363 | {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
364 | {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
365 | {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
366 | {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
367 | {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
368 | {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
369 | {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
370 | {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
371 | }; | ||
372 | |||
373 | static field_t _IS13818AudioCapability[] = { /* SEQUENCE */ | ||
374 | {FNAME("audioLayer1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
375 | {FNAME("audioLayer2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
376 | {FNAME("audioLayer3") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
377 | {FNAME("audioSampling16k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
378 | {FNAME("audioSampling22k05") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
379 | {FNAME("audioSampling24k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
380 | {FNAME("audioSampling32k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
381 | {FNAME("audioSampling44k1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
382 | {FNAME("audioSampling48k") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
383 | {FNAME("singleChannel") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
384 | {FNAME("twoChannels") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
385 | {FNAME("threeChannels2-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
386 | {FNAME("threeChannels3-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
387 | {FNAME("fourChannels2-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
388 | {FNAME("fourChannels2-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
389 | {FNAME("fourChannels3-1") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
390 | {FNAME("fiveChannels3-0-2-0") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
391 | {FNAME("fiveChannels3-2") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
392 | {FNAME("lowFrequencyEnhancement") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
393 | {FNAME("multilingual") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
394 | {FNAME("bitRate") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
395 | }; | ||
396 | |||
397 | static field_t _AudioCapability[] = { /* CHOICE */ | ||
398 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, | ||
399 | _H245_NonStandardParameter}, | ||
400 | {FNAME("g711Alaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
401 | {FNAME("g711Alaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
402 | {FNAME("g711Ulaw64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
403 | {FNAME("g711Ulaw56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
404 | {FNAME("g722-64k") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
405 | {FNAME("g722-56k") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
406 | {FNAME("g722-48k") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
407 | {FNAME("g7231") SEQ, 0, 2, 2, SKIP, 0, _AudioCapability_g7231}, | ||
408 | {FNAME("g728") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
409 | {FNAME("g729") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
410 | {FNAME("g729AnnexA") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
411 | {FNAME("is11172AudioCapability") SEQ, 0, 9, 9, SKIP | EXT, 0, | ||
412 | _IS11172AudioCapability}, | ||
413 | {FNAME("is13818AudioCapability") SEQ, 0, 21, 21, SKIP | EXT, 0, | ||
414 | _IS13818AudioCapability}, | ||
415 | {FNAME("g729wAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
416 | {FNAME("g729AnnexAwAnnexB") INT, BYTE, 1, 0, SKIP, 0, NULL}, | ||
417 | {FNAME("g7231AnnexCCapability") SEQ, 1, 3, 3, SKIP | EXT, 0, NULL}, | ||
418 | {FNAME("gsmFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, | ||
419 | {FNAME("gsmHalfRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, | ||
420 | {FNAME("gsmEnhancedFullRate") SEQ, 0, 3, 3, SKIP | EXT, 0, NULL}, | ||
421 | {FNAME("genericAudioCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, | ||
422 | {FNAME("g729Extensions") SEQ, 1, 8, 8, SKIP | EXT, 0, NULL}, | ||
423 | }; | ||
424 | |||
425 | static field_t _DataProtocolCapability[] = { /* CHOICE */ | ||
426 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, | ||
427 | _H245_NonStandardParameter}, | ||
428 | {FNAME("v14buffered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
429 | {FNAME("v42lapm") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
430 | {FNAME("hdlcFrameTunnelling") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
431 | {FNAME("h310SeparateVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
432 | {FNAME("h310SingleVCStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
433 | {FNAME("transparent") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
434 | {FNAME("segmentationAndReassembly") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
435 | {FNAME("hdlcFrameTunnelingwSAR") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
436 | {FNAME("v120") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
437 | {FNAME("separateLANStack") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
438 | {FNAME("v76wCompression") CHOICE, 2, 3, 3, SKIP | EXT, 0, NULL}, | ||
439 | {FNAME("tcp") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
440 | {FNAME("udp") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
441 | }; | ||
442 | |||
443 | static field_t _T84Profile_t84Restricted[] = { /* SEQUENCE */ | ||
444 | {FNAME("qcif") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
445 | {FNAME("cif") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
446 | {FNAME("ccir601Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
447 | {FNAME("ccir601Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
448 | {FNAME("hdtvSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
449 | {FNAME("hdtvProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
450 | {FNAME("g3FacsMH200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
451 | {FNAME("g3FacsMH200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
452 | {FNAME("g4FacsMMR200x100") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
453 | {FNAME("g4FacsMMR200x200") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
454 | {FNAME("jbig200x200Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
455 | {FNAME("jbig200x200Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
456 | {FNAME("jbig300x300Seq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
457 | {FNAME("jbig300x300Prog") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
458 | {FNAME("digPhotoLow") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
459 | {FNAME("digPhotoMedSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
460 | {FNAME("digPhotoMedProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
461 | {FNAME("digPhotoHighSeq") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
462 | {FNAME("digPhotoHighProg") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
463 | }; | ||
464 | |||
465 | static field_t _T84Profile[] = { /* CHOICE */ | ||
466 | {FNAME("t84Unrestricted") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
467 | {FNAME("t84Restricted") SEQ, 0, 19, 19, SKIP | EXT, 0, | ||
468 | _T84Profile_t84Restricted}, | ||
469 | }; | ||
470 | |||
471 | static field_t _DataApplicationCapability_application_t84[] = { /* SEQUENCE */ | ||
472 | {FNAME("t84Protocol") CHOICE, 3, 7, 14, SKIP | EXT, 0, | ||
473 | _DataProtocolCapability}, | ||
474 | {FNAME("t84Profile") CHOICE, 1, 2, 2, SKIP, 0, _T84Profile}, | ||
475 | }; | ||
476 | |||
477 | static field_t _DataApplicationCapability_application_nlpid[] = { /* SEQUENCE */ | ||
478 | {FNAME("nlpidProtocol") CHOICE, 3, 7, 14, SKIP | EXT, 0, | ||
479 | _DataProtocolCapability}, | ||
480 | {FNAME("nlpidData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
481 | }; | ||
482 | |||
483 | static field_t _DataApplicationCapability_application[] = { /* CHOICE */ | ||
484 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, | ||
485 | _H245_NonStandardParameter}, | ||
486 | {FNAME("t120") CHOICE, 3, 7, 14, DECODE | EXT, | ||
487 | offsetof(DataApplicationCapability_application, t120), | ||
488 | _DataProtocolCapability}, | ||
489 | {FNAME("dsm-cc") CHOICE, 3, 7, 14, SKIP | EXT, 0, | ||
490 | _DataProtocolCapability}, | ||
491 | {FNAME("userData") CHOICE, 3, 7, 14, SKIP | EXT, 0, | ||
492 | _DataProtocolCapability}, | ||
493 | {FNAME("t84") SEQ, 0, 2, 2, SKIP, 0, | ||
494 | _DataApplicationCapability_application_t84}, | ||
495 | {FNAME("t434") CHOICE, 3, 7, 14, SKIP | EXT, 0, | ||
496 | _DataProtocolCapability}, | ||
497 | {FNAME("h224") CHOICE, 3, 7, 14, SKIP | EXT, 0, | ||
498 | _DataProtocolCapability}, | ||
499 | {FNAME("nlpid") SEQ, 0, 2, 2, SKIP, 0, | ||
500 | _DataApplicationCapability_application_nlpid}, | ||
501 | {FNAME("dsvdControl") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
502 | {FNAME("h222DataPartitioning") CHOICE, 3, 7, 14, SKIP | EXT, 0, | ||
503 | _DataProtocolCapability}, | ||
504 | {FNAME("t30fax") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL}, | ||
505 | {FNAME("t140") CHOICE, 3, 7, 14, SKIP | EXT, 0, NULL}, | ||
506 | {FNAME("t38fax") SEQ, 0, 2, 2, SKIP, 0, NULL}, | ||
507 | {FNAME("genericDataCapability") SEQ, 5, 6, 6, SKIP | EXT, 0, NULL}, | ||
508 | }; | ||
509 | |||
510 | static field_t _DataApplicationCapability[] = { /* SEQUENCE */ | ||
511 | {FNAME("application") CHOICE, 4, 10, 14, DECODE | EXT, | ||
512 | offsetof(DataApplicationCapability, application), | ||
513 | _DataApplicationCapability_application}, | ||
514 | {FNAME("maxBitRate") INT, CONS, 0, 0, SKIP, 0, NULL}, | ||
515 | }; | ||
516 | |||
517 | static field_t _EncryptionMode[] = { /* CHOICE */ | ||
518 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, | ||
519 | _H245_NonStandardParameter}, | ||
520 | {FNAME("h233Encryption") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
521 | }; | ||
522 | |||
523 | static field_t _DataType[] = { /* CHOICE */ | ||
524 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, | ||
525 | _H245_NonStandardParameter}, | ||
526 | {FNAME("nullData") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
527 | {FNAME("videoData") CHOICE, 3, 5, 6, SKIP | EXT, 0, _VideoCapability}, | ||
528 | {FNAME("audioData") CHOICE, 4, 14, 22, SKIP | EXT, 0, | ||
529 | _AudioCapability}, | ||
530 | {FNAME("data") SEQ, 0, 2, 2, DECODE | EXT, offsetof(DataType, data), | ||
531 | _DataApplicationCapability}, | ||
532 | {FNAME("encryptionData") CHOICE, 1, 2, 2, SKIP | EXT, 0, | ||
533 | _EncryptionMode}, | ||
534 | {FNAME("h235Control") SEQ, 0, 2, 2, SKIP, 0, NULL}, | ||
535 | {FNAME("h235Media") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, | ||
536 | {FNAME("multiplexedStream") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, | ||
537 | }; | ||
538 | |||
539 | static field_t _H222LogicalChannelParameters[] = { /* SEQUENCE */ | ||
540 | {FNAME("resourceID") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
541 | {FNAME("subChannelID") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
542 | {FNAME("pcr-pid") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
543 | {FNAME("programDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
544 | {FNAME("streamDescriptors") OCTSTR, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
545 | }; | ||
546 | |||
547 | static field_t _H223LogicalChannelParameters_adaptationLayerType_al3[] = { /* SEQUENCE */ | ||
548 | {FNAME("controlFieldOctets") INT, 2, 0, 0, SKIP, 0, NULL}, | ||
549 | {FNAME("sendBufferSize") INT, CONS, 0, 0, SKIP, 0, NULL}, | ||
550 | }; | ||
551 | |||
552 | static field_t _H223LogicalChannelParameters_adaptationLayerType[] = { /* CHOICE */ | ||
553 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, | ||
554 | _H245_NonStandardParameter}, | ||
555 | {FNAME("al1Framed") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
556 | {FNAME("al1NotFramed") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
557 | {FNAME("al2WithoutSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
558 | {FNAME("al2WithSequenceNumbers") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
559 | {FNAME("al3") SEQ, 0, 2, 2, SKIP, 0, | ||
560 | _H223LogicalChannelParameters_adaptationLayerType_al3}, | ||
561 | {FNAME("al1M") SEQ, 0, 7, 8, SKIP | EXT, 0, NULL}, | ||
562 | {FNAME("al2M") SEQ, 0, 2, 2, SKIP | EXT, 0, NULL}, | ||
563 | {FNAME("al3M") SEQ, 0, 5, 6, SKIP | EXT, 0, NULL}, | ||
564 | }; | ||
565 | |||
566 | static field_t _H223LogicalChannelParameters[] = { /* SEQUENCE */ | ||
567 | {FNAME("adaptationLayerType") CHOICE, 3, 6, 9, SKIP | EXT, 0, | ||
568 | _H223LogicalChannelParameters_adaptationLayerType}, | ||
569 | {FNAME("segmentableFlag") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
570 | }; | ||
571 | |||
572 | static field_t _CRCLength[] = { /* CHOICE */ | ||
573 | {FNAME("crc8bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
574 | {FNAME("crc16bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
575 | {FNAME("crc32bit") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
576 | }; | ||
577 | |||
578 | static field_t _V76HDLCParameters[] = { /* SEQUENCE */ | ||
579 | {FNAME("crcLength") CHOICE, 2, 3, 3, SKIP | EXT, 0, _CRCLength}, | ||
580 | {FNAME("n401") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
581 | {FNAME("loopbackTestProcedure") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
582 | }; | ||
583 | |||
584 | static field_t _V76LogicalChannelParameters_suspendResume[] = { /* CHOICE */ | ||
585 | {FNAME("noSuspendResume") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
586 | {FNAME("suspendResumewAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
587 | {FNAME("suspendResumewoAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
588 | }; | ||
589 | |||
590 | static field_t _V76LogicalChannelParameters_mode_eRM_recovery[] = { /* CHOICE */ | ||
591 | {FNAME("rej") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
592 | {FNAME("sREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
593 | {FNAME("mSREJ") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
594 | }; | ||
595 | |||
596 | static field_t _V76LogicalChannelParameters_mode_eRM[] = { /* SEQUENCE */ | ||
597 | {FNAME("windowSize") INT, 7, 1, 0, SKIP, 0, NULL}, | ||
598 | {FNAME("recovery") CHOICE, 2, 3, 3, SKIP | EXT, 0, | ||
599 | _V76LogicalChannelParameters_mode_eRM_recovery}, | ||
600 | }; | ||
601 | |||
602 | static field_t _V76LogicalChannelParameters_mode[] = { /* CHOICE */ | ||
603 | {FNAME("eRM") SEQ, 0, 2, 2, SKIP | EXT, 0, | ||
604 | _V76LogicalChannelParameters_mode_eRM}, | ||
605 | {FNAME("uNERM") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
606 | }; | ||
607 | |||
608 | static field_t _V75Parameters[] = { /* SEQUENCE */ | ||
609 | {FNAME("audioHeaderPresent") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
610 | }; | ||
611 | |||
612 | static field_t _V76LogicalChannelParameters[] = { /* SEQUENCE */ | ||
613 | {FNAME("hdlcParameters") SEQ, 0, 3, 3, SKIP | EXT, 0, | ||
614 | _V76HDLCParameters}, | ||
615 | {FNAME("suspendResume") CHOICE, 2, 3, 3, SKIP | EXT, 0, | ||
616 | _V76LogicalChannelParameters_suspendResume}, | ||
617 | {FNAME("uIH") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
618 | {FNAME("mode") CHOICE, 1, 2, 2, SKIP | EXT, 0, | ||
619 | _V76LogicalChannelParameters_mode}, | ||
620 | {FNAME("v75Parameters") SEQ, 0, 1, 1, SKIP | EXT, 0, _V75Parameters}, | ||
621 | }; | ||
622 | |||
623 | static field_t _H2250LogicalChannelParameters_nonStandard[] = { /* SEQUENCE OF */ | ||
624 | {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter}, | ||
625 | }; | ||
626 | |||
627 | static field_t _UnicastAddress_iPAddress[] = { /* SEQUENCE */ | ||
628 | {FNAME("network") OCTSTR, FIXD, 4, 0, DECODE, | ||
629 | offsetof(UnicastAddress_iPAddress, network), NULL}, | ||
630 | {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
631 | }; | ||
632 | |||
633 | static field_t _UnicastAddress_iPXAddress[] = { /* SEQUENCE */ | ||
634 | {FNAME("node") OCTSTR, FIXD, 6, 0, SKIP, 0, NULL}, | ||
635 | {FNAME("netnum") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, | ||
636 | {FNAME("tsapIdentifier") OCTSTR, FIXD, 2, 0, SKIP, 0, NULL}, | ||
637 | }; | ||
638 | |||
639 | static field_t _UnicastAddress_iP6Address[] = { /* SEQUENCE */ | ||
640 | {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
641 | {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
642 | }; | ||
643 | |||
644 | static field_t _UnicastAddress_iPSourceRouteAddress_routing[] = { /* CHOICE */ | ||
645 | {FNAME("strict") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
646 | {FNAME("loose") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
647 | }; | ||
648 | |||
649 | static field_t _UnicastAddress_iPSourceRouteAddress_route[] = { /* SEQUENCE OF */ | ||
650 | {FNAME("item") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, | ||
651 | }; | ||
652 | |||
653 | static field_t _UnicastAddress_iPSourceRouteAddress[] = { /* SEQUENCE */ | ||
654 | {FNAME("routing") CHOICE, 1, 2, 2, SKIP, 0, | ||
655 | _UnicastAddress_iPSourceRouteAddress_routing}, | ||
656 | {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, | ||
657 | {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
658 | {FNAME("route") SEQOF, SEMI, 0, 0, SKIP, 0, | ||
659 | _UnicastAddress_iPSourceRouteAddress_route}, | ||
660 | }; | ||
661 | |||
662 | static field_t _UnicastAddress[] = { /* CHOICE */ | ||
663 | {FNAME("iPAddress") SEQ, 0, 2, 2, DECODE | EXT, | ||
664 | offsetof(UnicastAddress, iPAddress), _UnicastAddress_iPAddress}, | ||
665 | {FNAME("iPXAddress") SEQ, 0, 3, 3, SKIP | EXT, 0, | ||
666 | _UnicastAddress_iPXAddress}, | ||
667 | {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, | ||
668 | _UnicastAddress_iP6Address}, | ||
669 | {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
670 | {FNAME("iPSourceRouteAddress") SEQ, 0, 4, 4, SKIP | EXT, 0, | ||
671 | _UnicastAddress_iPSourceRouteAddress}, | ||
672 | {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, | ||
673 | {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL}, | ||
674 | }; | ||
675 | |||
676 | static field_t _MulticastAddress_iPAddress[] = { /* SEQUENCE */ | ||
677 | {FNAME("network") OCTSTR, FIXD, 4, 0, SKIP, 0, NULL}, | ||
678 | {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
679 | }; | ||
680 | |||
681 | static field_t _MulticastAddress_iP6Address[] = { /* SEQUENCE */ | ||
682 | {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
683 | {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, | ||
684 | }; | ||
685 | |||
686 | static field_t _MulticastAddress[] = { /* CHOICE */ | ||
687 | {FNAME("iPAddress") SEQ, 0, 2, 2, SKIP | EXT, 0, | ||
688 | _MulticastAddress_iPAddress}, | ||
689 | {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, | ||
690 | _MulticastAddress_iP6Address}, | ||
691 | {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, | ||
692 | {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, NULL}, | ||
693 | }; | ||
694 | |||
695 | static field_t _H245_TransportAddress[] = { /* CHOICE */ | ||
696 | {FNAME("unicastAddress") CHOICE, 3, 5, 7, DECODE | EXT, | ||
697 | offsetof(H245_TransportAddress, unicastAddress), _UnicastAddress}, | ||
698 | {FNAME("multicastAddress") CHOICE, 1, 2, 4, SKIP | EXT, 0, | ||
699 | _MulticastAddress}, | ||
700 | }; | ||
701 | |||
702 | static field_t _H2250LogicalChannelParameters[] = { /* SEQUENCE */ | ||
703 | {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
704 | _H2250LogicalChannelParameters_nonStandard}, | ||
705 | {FNAME("sessionID") INT, BYTE, 0, 0, SKIP, 0, NULL}, | ||
706 | {FNAME("associatedSessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL}, | ||
707 | {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, | ||
708 | offsetof(H2250LogicalChannelParameters, mediaChannel), | ||
709 | _H245_TransportAddress}, | ||
710 | {FNAME("mediaGuaranteedDelivery") BOOL, FIXD, 0, 0, SKIP | OPT, 0, | ||
711 | NULL}, | ||
712 | {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, | ||
713 | offsetof(H2250LogicalChannelParameters, mediaControlChannel), | ||
714 | _H245_TransportAddress}, | ||
715 | {FNAME("mediaControlGuaranteedDelivery") BOOL, FIXD, 0, 0, STOP | OPT, | ||
716 | 0, NULL}, | ||
717 | {FNAME("silenceSuppression") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, | ||
718 | {FNAME("destination") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
719 | {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, STOP | OPT, 0, NULL}, | ||
720 | {FNAME("mediaPacketization") CHOICE, 0, 1, 2, STOP | EXT | OPT, 0, | ||
721 | NULL}, | ||
722 | {FNAME("transportCapability") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, | ||
723 | NULL}, | ||
724 | {FNAME("redundancyEncoding") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
725 | {FNAME("source") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, NULL}, | ||
726 | }; | ||
727 | |||
728 | static field_t _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ | ||
729 | {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0, | ||
730 | _H222LogicalChannelParameters}, | ||
731 | {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0, | ||
732 | _H223LogicalChannelParameters}, | ||
733 | {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0, | ||
734 | _V76LogicalChannelParameters}, | ||
735 | {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, | ||
736 | offsetof | ||
737 | (OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters, | ||
738 | h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, | ||
739 | {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
740 | }; | ||
741 | |||
742 | static field_t _OpenLogicalChannel_forwardLogicalChannelParameters[] = { /* SEQUENCE */ | ||
743 | {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
744 | {FNAME("dataType") CHOICE, 3, 6, 9, DECODE | EXT, | ||
745 | offsetof(OpenLogicalChannel_forwardLogicalChannelParameters, | ||
746 | dataType), _DataType}, | ||
747 | {FNAME("multiplexParameters") CHOICE, 2, 3, 5, DECODE | EXT, | ||
748 | offsetof(OpenLogicalChannel_forwardLogicalChannelParameters, | ||
749 | multiplexParameters), | ||
750 | _OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters}, | ||
751 | {FNAME("forwardLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT, | ||
752 | 0, NULL}, | ||
753 | {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
754 | }; | ||
755 | |||
756 | static field_t _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ | ||
757 | {FNAME("h223LogicalChannelParameters") SEQ, 0, 2, 2, SKIP | EXT, 0, | ||
758 | _H223LogicalChannelParameters}, | ||
759 | {FNAME("v76LogicalChannelParameters") SEQ, 0, 5, 5, SKIP | EXT, 0, | ||
760 | _V76LogicalChannelParameters}, | ||
761 | {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, | ||
762 | offsetof | ||
763 | (OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters, | ||
764 | h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, | ||
765 | }; | ||
766 | |||
767 | static field_t _OpenLogicalChannel_reverseLogicalChannelParameters[] = { /* SEQUENCE */ | ||
768 | {FNAME("dataType") CHOICE, 3, 6, 9, SKIP | EXT, 0, _DataType}, | ||
769 | {FNAME("multiplexParameters") CHOICE, 1, 2, 3, DECODE | EXT | OPT, | ||
770 | offsetof(OpenLogicalChannel_reverseLogicalChannelParameters, | ||
771 | multiplexParameters), | ||
772 | _OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters}, | ||
773 | {FNAME("reverseLogicalChannelDependency") INT, WORD, 1, 0, SKIP | OPT, | ||
774 | 0, NULL}, | ||
775 | {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
776 | }; | ||
777 | |||
778 | static field_t _NetworkAccessParameters_distribution[] = { /* CHOICE */ | ||
779 | {FNAME("unicast") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
780 | {FNAME("multicast") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
781 | }; | ||
782 | |||
783 | static field_t _Q2931Address_address[] = { /* CHOICE */ | ||
784 | {FNAME("internationalNumber") NUMSTR, 4, 1, 0, SKIP, 0, NULL}, | ||
785 | {FNAME("nsapAddress") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, | ||
786 | }; | ||
787 | |||
788 | static field_t _Q2931Address[] = { /* SEQUENCE */ | ||
789 | {FNAME("address") CHOICE, 1, 2, 2, SKIP | EXT, 0, | ||
790 | _Q2931Address_address}, | ||
791 | {FNAME("subaddress") OCTSTR, 5, 1, 0, SKIP | OPT, 0, NULL}, | ||
792 | }; | ||
793 | |||
794 | static field_t _NetworkAccessParameters_networkAddress[] = { /* CHOICE */ | ||
795 | {FNAME("q2931Address") SEQ, 1, 2, 2, SKIP | EXT, 0, _Q2931Address}, | ||
796 | {FNAME("e164Address") NUMDGT, 7, 1, 0, SKIP, 0, NULL}, | ||
797 | {FNAME("localAreaAddress") CHOICE, 1, 2, 2, DECODE | EXT, | ||
798 | offsetof(NetworkAccessParameters_networkAddress, localAreaAddress), | ||
799 | _H245_TransportAddress}, | ||
800 | }; | ||
801 | |||
802 | static field_t _NetworkAccessParameters[] = { /* SEQUENCE */ | ||
803 | {FNAME("distribution") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, | ||
804 | _NetworkAccessParameters_distribution}, | ||
805 | {FNAME("networkAddress") CHOICE, 2, 3, 3, DECODE | EXT, | ||
806 | offsetof(NetworkAccessParameters, networkAddress), | ||
807 | _NetworkAccessParameters_networkAddress}, | ||
808 | {FNAME("associateConference") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
809 | {FNAME("externalReference") OCTSTR, 8, 1, 0, SKIP | OPT, 0, NULL}, | ||
810 | {FNAME("t120SetupProcedure") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, | ||
811 | NULL}, | ||
812 | }; | ||
813 | |||
814 | static field_t _OpenLogicalChannel[] = { /* SEQUENCE */ | ||
815 | {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
816 | {FNAME("forwardLogicalChannelParameters") SEQ, 1, 3, 5, DECODE | EXT, | ||
817 | offsetof(OpenLogicalChannel, forwardLogicalChannelParameters), | ||
818 | _OpenLogicalChannel_forwardLogicalChannelParameters}, | ||
819 | {FNAME("reverseLogicalChannelParameters") SEQ, 1, 2, 4, | ||
820 | DECODE | EXT | OPT, offsetof(OpenLogicalChannel, | ||
821 | reverseLogicalChannelParameters), | ||
822 | _OpenLogicalChannel_reverseLogicalChannelParameters}, | ||
823 | {FNAME("separateStack") SEQ, 2, 4, 5, DECODE | EXT | OPT, | ||
824 | offsetof(OpenLogicalChannel, separateStack), | ||
825 | _NetworkAccessParameters}, | ||
826 | {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
827 | }; | ||
828 | |||
829 | static field_t _Setup_UUIE_fastStart[] = { /* SEQUENCE OF */ | ||
830 | {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, | ||
831 | sizeof(OpenLogicalChannel), _OpenLogicalChannel} | ||
832 | , | ||
833 | }; | ||
834 | |||
835 | static field_t _Setup_UUIE[] = { /* SEQUENCE */ | ||
836 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
837 | {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
838 | offsetof(Setup_UUIE, h245Address), _TransportAddress}, | ||
839 | {FNAME("sourceAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
840 | _Setup_UUIE_sourceAddress}, | ||
841 | {FNAME("sourceInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, | ||
842 | {FNAME("destinationAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
843 | _Setup_UUIE_destinationAddress}, | ||
844 | {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
845 | offsetof(Setup_UUIE, destCallSignalAddress), _TransportAddress}, | ||
846 | {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
847 | _Setup_UUIE_destExtraCallInfo}, | ||
848 | {FNAME("destExtraCRV") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
849 | _Setup_UUIE_destExtraCRV}, | ||
850 | {FNAME("activeMC") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
851 | {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
852 | {FNAME("conferenceGoal") CHOICE, 2, 3, 5, SKIP | EXT, 0, | ||
853 | _Setup_UUIE_conferenceGoal}, | ||
854 | {FNAME("callServices") SEQ, 0, 8, 8, SKIP | EXT | OPT, 0, | ||
855 | _QseriesOptions}, | ||
856 | {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType}, | ||
857 | {FNAME("sourceCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
858 | offsetof(Setup_UUIE, sourceCallSignalAddress), _TransportAddress}, | ||
859 | {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0, | ||
860 | NULL}, | ||
861 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, | ||
862 | {FNAME("h245SecurityCapability") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
863 | NULL}, | ||
864 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
865 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
866 | {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, | ||
867 | offsetof(Setup_UUIE, fastStart), _Setup_UUIE_fastStart}, | ||
868 | {FNAME("mediaWaitForConnect") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
869 | {FNAME("canOverlapSend") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
870 | {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, | ||
871 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
872 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
873 | {FNAME("connectionParameters") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0, | ||
874 | NULL}, | ||
875 | {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
876 | {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, | ||
877 | NULL}, | ||
878 | {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, | ||
879 | NULL}, | ||
880 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
881 | {FNAME("symmetricOperationRequired") NUL, FIXD, 0, 0, SKIP | OPT, 0, | ||
882 | NULL}, | ||
883 | {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, | ||
884 | {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, | ||
885 | {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
886 | {FNAME("neededFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
887 | {FNAME("desiredFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
888 | {FNAME("supportedFeatures") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
889 | {FNAME("parallelH245Control") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
890 | {FNAME("additionalSourceAddresses") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
891 | NULL}, | ||
892 | }; | ||
893 | |||
894 | static field_t _CallProceeding_UUIE_fastStart[] = { /* SEQUENCE OF */ | ||
895 | {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, | ||
896 | sizeof(OpenLogicalChannel), _OpenLogicalChannel} | ||
897 | , | ||
898 | }; | ||
899 | |||
900 | static field_t _CallProceeding_UUIE[] = { /* SEQUENCE */ | ||
901 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
902 | {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, | ||
903 | _EndpointType}, | ||
904 | {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
905 | offsetof(CallProceeding_UUIE, h245Address), _TransportAddress}, | ||
906 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, | ||
907 | {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, | ||
908 | NULL}, | ||
909 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
910 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
911 | {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, | ||
912 | offsetof(CallProceeding_UUIE, fastStart), | ||
913 | _CallProceeding_UUIE_fastStart}, | ||
914 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
915 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
916 | {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, | ||
917 | {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, | ||
918 | }; | ||
919 | |||
920 | static field_t _Connect_UUIE_fastStart[] = { /* SEQUENCE OF */ | ||
921 | {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, | ||
922 | sizeof(OpenLogicalChannel), _OpenLogicalChannel} | ||
923 | , | ||
924 | }; | ||
925 | |||
926 | static field_t _Connect_UUIE[] = { /* SEQUENCE */ | ||
927 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
928 | {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
929 | offsetof(Connect_UUIE, h245Address), _TransportAddress}, | ||
930 | {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, | ||
931 | _EndpointType}, | ||
932 | {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
933 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, | ||
934 | {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, | ||
935 | NULL}, | ||
936 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
937 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
938 | {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, | ||
939 | offsetof(Connect_UUIE, fastStart), _Connect_UUIE_fastStart}, | ||
940 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
941 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
942 | {FNAME("language") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
943 | {FNAME("connectedAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
944 | {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, | ||
945 | NULL}, | ||
946 | {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, | ||
947 | NULL}, | ||
948 | {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, | ||
949 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
950 | {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, | ||
951 | {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, | ||
952 | }; | ||
953 | |||
954 | static field_t _Alerting_UUIE_fastStart[] = { /* SEQUENCE OF */ | ||
955 | {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, | ||
956 | sizeof(OpenLogicalChannel), _OpenLogicalChannel} | ||
957 | , | ||
958 | }; | ||
959 | |||
960 | static field_t _Alerting_UUIE[] = { /* SEQUENCE */ | ||
961 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
962 | {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, | ||
963 | _EndpointType}, | ||
964 | {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
965 | offsetof(Alerting_UUIE, h245Address), _TransportAddress}, | ||
966 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, | ||
967 | {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, | ||
968 | NULL}, | ||
969 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
970 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
971 | {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, | ||
972 | offsetof(Alerting_UUIE, fastStart), _Alerting_UUIE_fastStart}, | ||
973 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
974 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
975 | {FNAME("alertingAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
976 | {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, | ||
977 | NULL}, | ||
978 | {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, | ||
979 | NULL}, | ||
980 | {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, | ||
981 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
982 | {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, | ||
983 | {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, | ||
984 | }; | ||
985 | |||
986 | static field_t _Information_UUIE_fastStart[] = { /* SEQUENCE OF */ | ||
987 | {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, | ||
988 | sizeof(OpenLogicalChannel), _OpenLogicalChannel} | ||
989 | , | ||
990 | }; | ||
991 | |||
992 | static field_t _Information_UUIE[] = { /* SEQUENCE */ | ||
993 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
994 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, | ||
995 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
996 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
997 | {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, | ||
998 | offsetof(Information_UUIE, fastStart), _Information_UUIE_fastStart}, | ||
999 | {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, | ||
1000 | {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, | ||
1001 | }; | ||
1002 | |||
1003 | static field_t _ReleaseCompleteReason[] = { /* CHOICE */ | ||
1004 | {FNAME("noBandwidth") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1005 | {FNAME("gatekeeperResources") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1006 | {FNAME("unreachableDestination") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1007 | {FNAME("destinationRejection") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1008 | {FNAME("invalidRevision") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1009 | {FNAME("noPermission") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1010 | {FNAME("unreachableGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1011 | {FNAME("gatewayResources") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1012 | {FNAME("badFormatAddress") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1013 | {FNAME("adaptiveBusy") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1014 | {FNAME("inConf") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1015 | {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1016 | {FNAME("facilityCallDeflection") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1017 | {FNAME("securityDenied") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1018 | {FNAME("calledPartyNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1019 | {FNAME("callerNotRegistered") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1020 | {FNAME("newConnectionNeeded") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1021 | {FNAME("nonStandardReason") SEQ, 0, 2, 2, SKIP, 0, NULL}, | ||
1022 | {FNAME("replaceWithConferenceInvite") OCTSTR, FIXD, 16, 0, SKIP, 0, | ||
1023 | NULL}, | ||
1024 | {FNAME("genericDataReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1025 | {FNAME("neededFeatureNotSupported") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1026 | {FNAME("tunnelledSignallingRejected") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1027 | }; | ||
1028 | |||
1029 | static field_t _ReleaseComplete_UUIE[] = { /* SEQUENCE */ | ||
1030 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1031 | {FNAME("reason") CHOICE, 4, 12, 22, SKIP | EXT | OPT, 0, | ||
1032 | _ReleaseCompleteReason}, | ||
1033 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, | ||
1034 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1035 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1036 | {FNAME("busyAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1037 | {FNAME("presentationIndicator") CHOICE, 2, 3, 3, SKIP | EXT | OPT, 0, | ||
1038 | NULL}, | ||
1039 | {FNAME("screeningIndicator") ENUM, 2, 0, 0, SKIP | EXT | OPT, 0, | ||
1040 | NULL}, | ||
1041 | {FNAME("capacity") SEQ, 2, 2, 2, SKIP | EXT | OPT, 0, NULL}, | ||
1042 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1043 | {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, | ||
1044 | }; | ||
1045 | |||
1046 | static field_t _Facility_UUIE_alternativeAliasAddress[] = { /* SEQUENCE OF */ | ||
1047 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1048 | }; | ||
1049 | |||
1050 | static field_t _FacilityReason[] = { /* CHOICE */ | ||
1051 | {FNAME("routeCallToGatekeeper") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1052 | {FNAME("callForwarded") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1053 | {FNAME("routeCallToMC") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1054 | {FNAME("undefinedReason") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1055 | {FNAME("conferenceListChoice") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1056 | {FNAME("startH245") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1057 | {FNAME("noH245") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1058 | {FNAME("newTokens") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1059 | {FNAME("featureSetUpdate") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1060 | {FNAME("forwardedElements") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1061 | {FNAME("transportedInformation") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1062 | }; | ||
1063 | |||
1064 | static field_t _Facility_UUIE_fastStart[] = { /* SEQUENCE OF */ | ||
1065 | {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, | ||
1066 | sizeof(OpenLogicalChannel), _OpenLogicalChannel} | ||
1067 | , | ||
1068 | }; | ||
1069 | |||
1070 | static field_t _Facility_UUIE[] = { /* SEQUENCE */ | ||
1071 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1072 | {FNAME("alternativeAddress") CHOICE, 3, 7, 7, SKIP | EXT | OPT, 0, | ||
1073 | _TransportAddress}, | ||
1074 | {FNAME("alternativeAliasAddress") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1075 | _Facility_UUIE_alternativeAliasAddress}, | ||
1076 | {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL}, | ||
1077 | {FNAME("reason") CHOICE, 2, 4, 11, DECODE | EXT, | ||
1078 | offsetof(Facility_UUIE, reason), _FacilityReason}, | ||
1079 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, | ||
1080 | {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1081 | {FNAME("remoteExtensionAddress") CHOICE, 1, 2, 7, SKIP | EXT | OPT, 0, | ||
1082 | NULL}, | ||
1083 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1084 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1085 | {FNAME("conferences") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1086 | {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
1087 | offsetof(Facility_UUIE, h245Address), _TransportAddress}, | ||
1088 | {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, | ||
1089 | offsetof(Facility_UUIE, fastStart), _Facility_UUIE_fastStart}, | ||
1090 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1091 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1092 | {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, | ||
1093 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1094 | {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, | ||
1095 | {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, | ||
1096 | {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT | OPT, 0, NULL}, | ||
1097 | {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, | ||
1098 | NULL}, | ||
1099 | }; | ||
1100 | |||
1101 | static field_t _CallIdentifier[] = { /* SEQUENCE */ | ||
1102 | {FNAME("guid") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, | ||
1103 | }; | ||
1104 | |||
1105 | static field_t _SecurityServiceMode[] = { /* CHOICE */ | ||
1106 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter}, | ||
1107 | {FNAME("none") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1108 | {FNAME("default") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1109 | }; | ||
1110 | |||
1111 | static field_t _SecurityCapabilities[] = { /* SEQUENCE */ | ||
1112 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1113 | _NonStandardParameter}, | ||
1114 | {FNAME("encryption") CHOICE, 2, 3, 3, SKIP | EXT, 0, | ||
1115 | _SecurityServiceMode}, | ||
1116 | {FNAME("authenticaton") CHOICE, 2, 3, 3, SKIP | EXT, 0, | ||
1117 | _SecurityServiceMode}, | ||
1118 | {FNAME("integrity") CHOICE, 2, 3, 3, SKIP | EXT, 0, | ||
1119 | _SecurityServiceMode}, | ||
1120 | }; | ||
1121 | |||
1122 | static field_t _H245Security[] = { /* CHOICE */ | ||
1123 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP, 0, _NonStandardParameter}, | ||
1124 | {FNAME("noSecurity") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1125 | {FNAME("tls") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities}, | ||
1126 | {FNAME("ipsec") SEQ, 1, 4, 4, SKIP | EXT, 0, _SecurityCapabilities}, | ||
1127 | }; | ||
1128 | |||
1129 | static field_t _DHset[] = { /* SEQUENCE */ | ||
1130 | {FNAME("halfkey") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, | ||
1131 | {FNAME("modSize") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, | ||
1132 | {FNAME("generator") BITSTR, WORD, 0, 0, SKIP, 0, NULL}, | ||
1133 | }; | ||
1134 | |||
1135 | static field_t _TypedCertificate[] = { /* SEQUENCE */ | ||
1136 | {FNAME("type") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1137 | {FNAME("certificate") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1138 | }; | ||
1139 | |||
1140 | static field_t _H235_NonStandardParameter[] = { /* SEQUENCE */ | ||
1141 | {FNAME("nonStandardIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1142 | {FNAME("data") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1143 | }; | ||
1144 | |||
1145 | static field_t _ClearToken[] = { /* SEQUENCE */ | ||
1146 | {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1147 | {FNAME("timeStamp") INT, CONS, 1, 0, SKIP | OPT, 0, NULL}, | ||
1148 | {FNAME("password") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, | ||
1149 | {FNAME("dhkey") SEQ, 0, 3, 3, SKIP | EXT | OPT, 0, _DHset}, | ||
1150 | {FNAME("challenge") OCTSTR, 7, 8, 0, SKIP | OPT, 0, NULL}, | ||
1151 | {FNAME("random") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL}, | ||
1152 | {FNAME("certificate") SEQ, 0, 2, 2, SKIP | EXT | OPT, 0, | ||
1153 | _TypedCertificate}, | ||
1154 | {FNAME("generalID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, | ||
1155 | {FNAME("nonStandard") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1156 | _H235_NonStandardParameter}, | ||
1157 | {FNAME("eckasdhkey") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, NULL}, | ||
1158 | {FNAME("sendersID") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, | ||
1159 | }; | ||
1160 | |||
1161 | static field_t _Progress_UUIE_tokens[] = { /* SEQUENCE OF */ | ||
1162 | {FNAME("item") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken}, | ||
1163 | }; | ||
1164 | |||
1165 | static field_t _Params[] = { /* SEQUENCE */ | ||
1166 | {FNAME("ranInt") INT, UNCO, 0, 0, SKIP | OPT, 0, NULL}, | ||
1167 | {FNAME("iv8") OCTSTR, FIXD, 8, 0, SKIP | OPT, 0, NULL}, | ||
1168 | {FNAME("iv16") OCTSTR, FIXD, 16, 0, SKIP | OPT, 0, NULL}, | ||
1169 | }; | ||
1170 | |||
1171 | static field_t _CryptoH323Token_cryptoEPPwdHash_token[] = { /* SEQUENCE */ | ||
1172 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1173 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1174 | {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1175 | }; | ||
1176 | |||
1177 | static field_t _CryptoH323Token_cryptoEPPwdHash[] = { /* SEQUENCE */ | ||
1178 | {FNAME("alias") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1179 | {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL}, | ||
1180 | {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, | ||
1181 | _CryptoH323Token_cryptoEPPwdHash_token}, | ||
1182 | }; | ||
1183 | |||
1184 | static field_t _CryptoH323Token_cryptoGKPwdHash_token[] = { /* SEQUENCE */ | ||
1185 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1186 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1187 | {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1188 | }; | ||
1189 | |||
1190 | static field_t _CryptoH323Token_cryptoGKPwdHash[] = { /* SEQUENCE */ | ||
1191 | {FNAME("gatekeeperId") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, | ||
1192 | {FNAME("timeStamp") INT, CONS, 1, 0, SKIP, 0, NULL}, | ||
1193 | {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, | ||
1194 | _CryptoH323Token_cryptoGKPwdHash_token}, | ||
1195 | }; | ||
1196 | |||
1197 | static field_t _CryptoH323Token_cryptoEPPwdEncr[] = { /* SEQUENCE */ | ||
1198 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1199 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1200 | {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1201 | }; | ||
1202 | |||
1203 | static field_t _CryptoH323Token_cryptoGKPwdEncr[] = { /* SEQUENCE */ | ||
1204 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1205 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1206 | {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1207 | }; | ||
1208 | |||
1209 | static field_t _CryptoH323Token_cryptoEPCert[] = { /* SEQUENCE */ | ||
1210 | {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, | ||
1211 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1212 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1213 | {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1214 | }; | ||
1215 | |||
1216 | static field_t _CryptoH323Token_cryptoGKCert[] = { /* SEQUENCE */ | ||
1217 | {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, | ||
1218 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1219 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1220 | {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1221 | }; | ||
1222 | |||
1223 | static field_t _CryptoH323Token_cryptoFastStart[] = { /* SEQUENCE */ | ||
1224 | {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, | ||
1225 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1226 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1227 | {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1228 | }; | ||
1229 | |||
1230 | static field_t _CryptoToken_cryptoEncryptedToken_token[] = { /* SEQUENCE */ | ||
1231 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1232 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1233 | {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1234 | }; | ||
1235 | |||
1236 | static field_t _CryptoToken_cryptoEncryptedToken[] = { /* SEQUENCE */ | ||
1237 | {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1238 | {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, | ||
1239 | _CryptoToken_cryptoEncryptedToken_token}, | ||
1240 | }; | ||
1241 | |||
1242 | static field_t _CryptoToken_cryptoSignedToken_token[] = { /* SEQUENCE */ | ||
1243 | {FNAME("toBeSigned") SEQ, 8, 9, 11, SKIP | OPEN | EXT, 0, NULL}, | ||
1244 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1245 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1246 | {FNAME("signature") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1247 | }; | ||
1248 | |||
1249 | static field_t _CryptoToken_cryptoSignedToken[] = { /* SEQUENCE */ | ||
1250 | {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1251 | {FNAME("token") SEQ, 0, 4, 4, SKIP, 0, | ||
1252 | _CryptoToken_cryptoSignedToken_token}, | ||
1253 | }; | ||
1254 | |||
1255 | static field_t _CryptoToken_cryptoHashedToken_token[] = { /* SEQUENCE */ | ||
1256 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1257 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1258 | {FNAME("hash") BITSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1259 | }; | ||
1260 | |||
1261 | static field_t _CryptoToken_cryptoHashedToken[] = { /* SEQUENCE */ | ||
1262 | {FNAME("tokenOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1263 | {FNAME("hashedVals") SEQ, 8, 9, 11, SKIP | EXT, 0, _ClearToken}, | ||
1264 | {FNAME("token") SEQ, 0, 3, 3, SKIP, 0, | ||
1265 | _CryptoToken_cryptoHashedToken_token}, | ||
1266 | }; | ||
1267 | |||
1268 | static field_t _CryptoToken_cryptoPwdEncr[] = { /* SEQUENCE */ | ||
1269 | {FNAME("algorithmOID") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1270 | {FNAME("paramS") SEQ, 2, 2, 3, SKIP | EXT, 0, _Params}, | ||
1271 | {FNAME("encryptedData") OCTSTR, SEMI, 0, 0, SKIP, 0, NULL}, | ||
1272 | }; | ||
1273 | |||
1274 | static field_t _CryptoToken[] = { /* CHOICE */ | ||
1275 | {FNAME("cryptoEncryptedToken") SEQ, 0, 2, 2, SKIP, 0, | ||
1276 | _CryptoToken_cryptoEncryptedToken}, | ||
1277 | {FNAME("cryptoSignedToken") SEQ, 0, 2, 2, SKIP, 0, | ||
1278 | _CryptoToken_cryptoSignedToken}, | ||
1279 | {FNAME("cryptoHashedToken") SEQ, 0, 3, 3, SKIP, 0, | ||
1280 | _CryptoToken_cryptoHashedToken}, | ||
1281 | {FNAME("cryptoPwdEncr") SEQ, 0, 3, 3, SKIP, 0, | ||
1282 | _CryptoToken_cryptoPwdEncr}, | ||
1283 | }; | ||
1284 | |||
1285 | static field_t _CryptoH323Token[] = { /* CHOICE */ | ||
1286 | {FNAME("cryptoEPPwdHash") SEQ, 0, 3, 3, SKIP, 0, | ||
1287 | _CryptoH323Token_cryptoEPPwdHash}, | ||
1288 | {FNAME("cryptoGKPwdHash") SEQ, 0, 3, 3, SKIP, 0, | ||
1289 | _CryptoH323Token_cryptoGKPwdHash}, | ||
1290 | {FNAME("cryptoEPPwdEncr") SEQ, 0, 3, 3, SKIP, 0, | ||
1291 | _CryptoH323Token_cryptoEPPwdEncr}, | ||
1292 | {FNAME("cryptoGKPwdEncr") SEQ, 0, 3, 3, SKIP, 0, | ||
1293 | _CryptoH323Token_cryptoGKPwdEncr}, | ||
1294 | {FNAME("cryptoEPCert") SEQ, 0, 4, 4, SKIP, 0, | ||
1295 | _CryptoH323Token_cryptoEPCert}, | ||
1296 | {FNAME("cryptoGKCert") SEQ, 0, 4, 4, SKIP, 0, | ||
1297 | _CryptoH323Token_cryptoGKCert}, | ||
1298 | {FNAME("cryptoFastStart") SEQ, 0, 4, 4, SKIP, 0, | ||
1299 | _CryptoH323Token_cryptoFastStart}, | ||
1300 | {FNAME("nestedcryptoToken") CHOICE, 2, 4, 4, SKIP | EXT, 0, | ||
1301 | _CryptoToken}, | ||
1302 | }; | ||
1303 | |||
1304 | static field_t _Progress_UUIE_cryptoTokens[] = { /* SEQUENCE OF */ | ||
1305 | {FNAME("item") CHOICE, 3, 8, 8, SKIP | EXT, 0, _CryptoH323Token}, | ||
1306 | }; | ||
1307 | |||
1308 | static field_t _Progress_UUIE_fastStart[] = { /* SEQUENCE OF */ | ||
1309 | {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, | ||
1310 | sizeof(OpenLogicalChannel), _OpenLogicalChannel} | ||
1311 | , | ||
1312 | }; | ||
1313 | |||
1314 | static field_t _Progress_UUIE[] = { /* SEQUENCE */ | ||
1315 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1316 | {FNAME("destinationInfo") SEQ, 6, 8, 10, SKIP | EXT, 0, | ||
1317 | _EndpointType}, | ||
1318 | {FNAME("h245Address") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
1319 | offsetof(Progress_UUIE, h245Address), _TransportAddress}, | ||
1320 | {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, | ||
1321 | _CallIdentifier}, | ||
1322 | {FNAME("h245SecurityMode") CHOICE, 2, 4, 4, SKIP | EXT | OPT, 0, | ||
1323 | _H245Security}, | ||
1324 | {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1325 | _Progress_UUIE_tokens}, | ||
1326 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1327 | _Progress_UUIE_cryptoTokens}, | ||
1328 | {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, | ||
1329 | offsetof(Progress_UUIE, fastStart), _Progress_UUIE_fastStart}, | ||
1330 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1331 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1332 | {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, | ||
1333 | }; | ||
1334 | |||
1335 | static field_t _H323_UU_PDU_h323_message_body[] = { /* CHOICE */ | ||
1336 | {FNAME("setup") SEQ, 7, 13, 39, DECODE | EXT, | ||
1337 | offsetof(H323_UU_PDU_h323_message_body, setup), _Setup_UUIE}, | ||
1338 | {FNAME("callProceeding") SEQ, 1, 3, 12, DECODE | EXT, | ||
1339 | offsetof(H323_UU_PDU_h323_message_body, callProceeding), | ||
1340 | _CallProceeding_UUIE}, | ||
1341 | {FNAME("connect") SEQ, 1, 4, 19, DECODE | EXT, | ||
1342 | offsetof(H323_UU_PDU_h323_message_body, connect), _Connect_UUIE}, | ||
1343 | {FNAME("alerting") SEQ, 1, 3, 17, DECODE | EXT, | ||
1344 | offsetof(H323_UU_PDU_h323_message_body, alerting), _Alerting_UUIE}, | ||
1345 | {FNAME("information") SEQ, 0, 1, 7, DECODE | EXT, | ||
1346 | offsetof(H323_UU_PDU_h323_message_body, information), | ||
1347 | _Information_UUIE}, | ||
1348 | {FNAME("releaseComplete") SEQ, 1, 2, 11, SKIP | EXT, 0, | ||
1349 | _ReleaseComplete_UUIE}, | ||
1350 | {FNAME("facility") SEQ, 3, 5, 21, DECODE | EXT, | ||
1351 | offsetof(H323_UU_PDU_h323_message_body, facility), _Facility_UUIE}, | ||
1352 | {FNAME("progress") SEQ, 5, 8, 11, DECODE | EXT, | ||
1353 | offsetof(H323_UU_PDU_h323_message_body, progress), _Progress_UUIE}, | ||
1354 | {FNAME("empty") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1355 | {FNAME("status") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, | ||
1356 | {FNAME("statusInquiry") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, | ||
1357 | {FNAME("setupAcknowledge") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, | ||
1358 | {FNAME("notify") SEQ, 2, 4, 4, SKIP | EXT, 0, NULL}, | ||
1359 | }; | ||
1360 | |||
1361 | static field_t _RequestMessage[] = { /* CHOICE */ | ||
1362 | {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1363 | {FNAME("masterSlaveDetermination") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1364 | {FNAME("terminalCapabilitySet") SEQ, 3, 5, 5, STOP | EXT, 0, NULL}, | ||
1365 | {FNAME("openLogicalChannel") SEQ, 1, 3, 5, DECODE | EXT, | ||
1366 | offsetof(RequestMessage, openLogicalChannel), _OpenLogicalChannel}, | ||
1367 | {FNAME("closeLogicalChannel") SEQ, 0, 2, 3, STOP | EXT, 0, NULL}, | ||
1368 | {FNAME("requestChannelClose") SEQ, 0, 1, 3, STOP | EXT, 0, NULL}, | ||
1369 | {FNAME("multiplexEntrySend") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1370 | {FNAME("requestMultiplexEntry") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1371 | {FNAME("requestMode") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1372 | {FNAME("roundTripDelayRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1373 | {FNAME("maintenanceLoopRequest") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1374 | {FNAME("communicationModeRequest") SEQ, 0, 0, 0, STOP | EXT, 0, NULL}, | ||
1375 | {FNAME("conferenceRequest") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL}, | ||
1376 | {FNAME("multilinkRequest") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL}, | ||
1377 | {FNAME("logicalChannelRateRequest") SEQ, 0, 3, 3, STOP | EXT, 0, | ||
1378 | NULL}, | ||
1379 | }; | ||
1380 | |||
1381 | static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters[] = { /* CHOICE */ | ||
1382 | {FNAME("h222LogicalChannelParameters") SEQ, 3, 5, 5, SKIP | EXT, 0, | ||
1383 | _H222LogicalChannelParameters}, | ||
1384 | {FNAME("h2250LogicalChannelParameters") SEQ, 10, 11, 14, DECODE | EXT, | ||
1385 | offsetof | ||
1386 | (OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters, | ||
1387 | h2250LogicalChannelParameters), _H2250LogicalChannelParameters}, | ||
1388 | }; | ||
1389 | |||
1390 | static field_t _OpenLogicalChannelAck_reverseLogicalChannelParameters[] = { /* SEQUENCE */ | ||
1391 | {FNAME("reverseLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1392 | {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
1393 | {FNAME("multiplexParameters") CHOICE, 0, 1, 2, DECODE | EXT | OPT, | ||
1394 | offsetof(OpenLogicalChannelAck_reverseLogicalChannelParameters, | ||
1395 | multiplexParameters), | ||
1396 | _OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters}, | ||
1397 | {FNAME("replacementFor") INT, WORD, 1, 0, SKIP | OPT, 0, NULL}, | ||
1398 | }; | ||
1399 | |||
1400 | static field_t _H2250LogicalChannelAckParameters_nonStandard[] = { /* SEQUENCE OF */ | ||
1401 | {FNAME("item") SEQ, 0, 2, 2, SKIP, 0, _H245_NonStandardParameter}, | ||
1402 | }; | ||
1403 | |||
1404 | static field_t _H2250LogicalChannelAckParameters[] = { /* SEQUENCE */ | ||
1405 | {FNAME("nonStandard") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1406 | _H2250LogicalChannelAckParameters_nonStandard}, | ||
1407 | {FNAME("sessionID") INT, 8, 1, 0, SKIP | OPT, 0, NULL}, | ||
1408 | {FNAME("mediaChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, | ||
1409 | offsetof(H2250LogicalChannelAckParameters, mediaChannel), | ||
1410 | _H245_TransportAddress}, | ||
1411 | {FNAME("mediaControlChannel") CHOICE, 1, 2, 2, DECODE | EXT | OPT, | ||
1412 | offsetof(H2250LogicalChannelAckParameters, mediaControlChannel), | ||
1413 | _H245_TransportAddress}, | ||
1414 | {FNAME("dynamicRTPPayloadType") INT, 5, 96, 0, SKIP | OPT, 0, NULL}, | ||
1415 | {FNAME("flowControlToZero") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1416 | {FNAME("portNumber") INT, WORD, 0, 0, SKIP | OPT, 0, NULL}, | ||
1417 | }; | ||
1418 | |||
1419 | static field_t _OpenLogicalChannelAck_forwardMultiplexAckParameters[] = { /* CHOICE */ | ||
1420 | {FNAME("h2250LogicalChannelAckParameters") SEQ, 5, 5, 7, DECODE | EXT, | ||
1421 | offsetof(OpenLogicalChannelAck_forwardMultiplexAckParameters, | ||
1422 | h2250LogicalChannelAckParameters), | ||
1423 | _H2250LogicalChannelAckParameters}, | ||
1424 | }; | ||
1425 | |||
1426 | static field_t _OpenLogicalChannelAck[] = { /* SEQUENCE */ | ||
1427 | {FNAME("forwardLogicalChannelNumber") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1428 | {FNAME("reverseLogicalChannelParameters") SEQ, 2, 3, 4, | ||
1429 | DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, | ||
1430 | reverseLogicalChannelParameters), | ||
1431 | _OpenLogicalChannelAck_reverseLogicalChannelParameters}, | ||
1432 | {FNAME("separateStack") SEQ, 2, 4, 5, SKIP | EXT | OPT, 0, NULL}, | ||
1433 | {FNAME("forwardMultiplexAckParameters") CHOICE, 0, 1, 1, | ||
1434 | DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, | ||
1435 | forwardMultiplexAckParameters), | ||
1436 | _OpenLogicalChannelAck_forwardMultiplexAckParameters}, | ||
1437 | {FNAME("encryptionSync") SEQ, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1438 | }; | ||
1439 | |||
1440 | static field_t _ResponseMessage[] = { /* CHOICE */ | ||
1441 | {FNAME("nonStandard") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1442 | {FNAME("masterSlaveDeterminationAck") SEQ, 0, 1, 1, STOP | EXT, 0, | ||
1443 | NULL}, | ||
1444 | {FNAME("masterSlaveDeterminationReject") SEQ, 0, 1, 1, STOP | EXT, 0, | ||
1445 | NULL}, | ||
1446 | {FNAME("terminalCapabilitySetAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1447 | {FNAME("terminalCapabilitySetReject") SEQ, 0, 2, 2, STOP | EXT, 0, | ||
1448 | NULL}, | ||
1449 | {FNAME("openLogicalChannelAck") SEQ, 1, 2, 5, DECODE | EXT, | ||
1450 | offsetof(ResponseMessage, openLogicalChannelAck), | ||
1451 | _OpenLogicalChannelAck}, | ||
1452 | {FNAME("openLogicalChannelReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1453 | {FNAME("closeLogicalChannelAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1454 | {FNAME("requestChannelCloseAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1455 | {FNAME("requestChannelCloseReject") SEQ, 0, 2, 2, STOP | EXT, 0, | ||
1456 | NULL}, | ||
1457 | {FNAME("multiplexEntrySendAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1458 | {FNAME("multiplexEntrySendReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1459 | {FNAME("requestMultiplexEntryAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1460 | {FNAME("requestMultiplexEntryReject") SEQ, 0, 2, 2, STOP | EXT, 0, | ||
1461 | NULL}, | ||
1462 | {FNAME("requestModeAck") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1463 | {FNAME("requestModeReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1464 | {FNAME("roundTripDelayResponse") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1465 | {FNAME("maintenanceLoopAck") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1466 | {FNAME("maintenanceLoopReject") SEQ, 0, 2, 2, STOP | EXT, 0, NULL}, | ||
1467 | {FNAME("communicationModeResponse") CHOICE, 0, 1, 1, STOP | EXT, 0, | ||
1468 | NULL}, | ||
1469 | {FNAME("conferenceResponse") CHOICE, 3, 8, 16, STOP | EXT, 0, NULL}, | ||
1470 | {FNAME("multilinkResponse") CHOICE, 3, 5, 5, STOP | EXT, 0, NULL}, | ||
1471 | {FNAME("logicalChannelRateAcknowledge") SEQ, 0, 3, 3, STOP | EXT, 0, | ||
1472 | NULL}, | ||
1473 | {FNAME("logicalChannelRateReject") SEQ, 1, 4, 4, STOP | EXT, 0, NULL}, | ||
1474 | }; | ||
1475 | |||
1476 | static field_t _MultimediaSystemControlMessage[] = { /* CHOICE */ | ||
1477 | {FNAME("request") CHOICE, 4, 11, 15, DECODE | EXT, | ||
1478 | offsetof(MultimediaSystemControlMessage, request), _RequestMessage}, | ||
1479 | {FNAME("response") CHOICE, 5, 19, 24, DECODE | EXT, | ||
1480 | offsetof(MultimediaSystemControlMessage, response), | ||
1481 | _ResponseMessage}, | ||
1482 | {FNAME("command") CHOICE, 3, 7, 12, STOP | EXT, 0, NULL}, | ||
1483 | {FNAME("indication") CHOICE, 4, 14, 23, STOP | EXT, 0, NULL}, | ||
1484 | }; | ||
1485 | |||
1486 | static field_t _H323_UU_PDU_h245Control[] = { /* SEQUENCE OF */ | ||
1487 | {FNAME("item") CHOICE, 2, 4, 4, DECODE | OPEN | EXT, | ||
1488 | sizeof(MultimediaSystemControlMessage), | ||
1489 | _MultimediaSystemControlMessage} | ||
1490 | , | ||
1491 | }; | ||
1492 | |||
1493 | static field_t _H323_UU_PDU[] = { /* SEQUENCE */ | ||
1494 | {FNAME("h323-message-body") CHOICE, 3, 7, 13, DECODE | EXT, | ||
1495 | offsetof(H323_UU_PDU, h323_message_body), | ||
1496 | _H323_UU_PDU_h323_message_body}, | ||
1497 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1498 | _NonStandardParameter}, | ||
1499 | {FNAME("h4501SupplementaryService") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1500 | NULL}, | ||
1501 | {FNAME("h245Tunneling") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1502 | {FNAME("h245Control") SEQOF, SEMI, 0, 4, DECODE | OPT, | ||
1503 | offsetof(H323_UU_PDU, h245Control), _H323_UU_PDU_h245Control}, | ||
1504 | {FNAME("nonStandardControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1505 | {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
1506 | {FNAME("tunnelledSignallingMessage") SEQ, 2, 4, 4, STOP | EXT | OPT, | ||
1507 | 0, NULL}, | ||
1508 | {FNAME("provisionalRespToH245Tunneling") NUL, FIXD, 0, 0, STOP | OPT, | ||
1509 | 0, NULL}, | ||
1510 | {FNAME("stimulusControl") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1511 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1512 | }; | ||
1513 | |||
1514 | static field_t _H323_UserInformation[] = { /* SEQUENCE */ | ||
1515 | {FNAME("h323-uu-pdu") SEQ, 1, 2, 11, DECODE | EXT, | ||
1516 | offsetof(H323_UserInformation, h323_uu_pdu), _H323_UU_PDU}, | ||
1517 | {FNAME("user-data") SEQ, 0, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
1518 | }; | ||
1519 | |||
1520 | static field_t _GatekeeperRequest[] = { /* SEQUENCE */ | ||
1521 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1522 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1523 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1524 | _NonStandardParameter}, | ||
1525 | {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1526 | offsetof(GatekeeperRequest, rasAddress), _TransportAddress}, | ||
1527 | {FNAME("endpointType") SEQ, 6, 8, 10, STOP | EXT, 0, NULL}, | ||
1528 | {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, | ||
1529 | {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL}, | ||
1530 | {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1531 | {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1532 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1533 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1534 | {FNAME("authenticationCapability") SEQOF, SEMI, 0, 0, STOP | OPT, 0, | ||
1535 | NULL}, | ||
1536 | {FNAME("algorithmOIDs") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1537 | {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1538 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1539 | {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, | ||
1540 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1541 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1542 | }; | ||
1543 | |||
1544 | static field_t _GatekeeperConfirm[] = { /* SEQUENCE */ | ||
1545 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1546 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1547 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1548 | _NonStandardParameter}, | ||
1549 | {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, | ||
1550 | {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1551 | offsetof(GatekeeperConfirm, rasAddress), _TransportAddress}, | ||
1552 | {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1553 | {FNAME("authenticationMode") CHOICE, 3, 7, 8, STOP | EXT | OPT, 0, | ||
1554 | NULL}, | ||
1555 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1556 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1557 | {FNAME("algorithmOID") OID, BYTE, 0, 0, STOP | OPT, 0, NULL}, | ||
1558 | {FNAME("integrity") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1559 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1560 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1561 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1562 | }; | ||
1563 | |||
1564 | static field_t _RegistrationRequest_callSignalAddress[] = { /* SEQUENCE OF */ | ||
1565 | {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1566 | sizeof(TransportAddress), _TransportAddress} | ||
1567 | , | ||
1568 | }; | ||
1569 | |||
1570 | static field_t _RegistrationRequest_rasAddress[] = { /* SEQUENCE OF */ | ||
1571 | {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1572 | sizeof(TransportAddress), _TransportAddress} | ||
1573 | , | ||
1574 | }; | ||
1575 | |||
1576 | static field_t _RegistrationRequest_terminalAlias[] = { /* SEQUENCE OF */ | ||
1577 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1578 | }; | ||
1579 | |||
1580 | static field_t _RegistrationRequest[] = { /* SEQUENCE */ | ||
1581 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1582 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1583 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1584 | _NonStandardParameter}, | ||
1585 | {FNAME("discoveryComplete") BOOL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1586 | {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, | ||
1587 | offsetof(RegistrationRequest, callSignalAddress), | ||
1588 | _RegistrationRequest_callSignalAddress}, | ||
1589 | {FNAME("rasAddress") SEQOF, SEMI, 0, 10, DECODE, | ||
1590 | offsetof(RegistrationRequest, rasAddress), | ||
1591 | _RegistrationRequest_rasAddress}, | ||
1592 | {FNAME("terminalType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, | ||
1593 | {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1594 | _RegistrationRequest_terminalAlias}, | ||
1595 | {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, | ||
1596 | {FNAME("endpointVendor") SEQ, 2, 3, 3, SKIP | EXT, 0, | ||
1597 | _VendorIdentifier}, | ||
1598 | {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1599 | {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT, | ||
1600 | offsetof(RegistrationRequest, timeToLive), NULL}, | ||
1601 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1602 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1603 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1604 | {FNAME("keepAlive") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1605 | {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, | ||
1606 | {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1607 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1608 | {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, | ||
1609 | 0, NULL}, | ||
1610 | {FNAME("additiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, | ||
1611 | {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, | ||
1612 | NULL}, | ||
1613 | {FNAME("supportsAltGK") NUL, FIXD, 0, 0, STOP | OPT, 0, NULL}, | ||
1614 | {FNAME("usageReportingCapability") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, | ||
1615 | NULL}, | ||
1616 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, | ||
1617 | {FNAME("supportedH248Packages") SEQOF, SEMI, 0, 0, STOP | OPT, 0, | ||
1618 | NULL}, | ||
1619 | {FNAME("callCreditCapability") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, | ||
1620 | NULL}, | ||
1621 | {FNAME("capacityReportingCapability") SEQ, 0, 1, 1, STOP | EXT | OPT, | ||
1622 | 0, NULL}, | ||
1623 | {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
1624 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1625 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1626 | }; | ||
1627 | |||
1628 | static field_t _RegistrationConfirm_callSignalAddress[] = { /* SEQUENCE OF */ | ||
1629 | {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1630 | sizeof(TransportAddress), _TransportAddress} | ||
1631 | , | ||
1632 | }; | ||
1633 | |||
1634 | static field_t _RegistrationConfirm_terminalAlias[] = { /* SEQUENCE OF */ | ||
1635 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1636 | }; | ||
1637 | |||
1638 | static field_t _RegistrationConfirm[] = { /* SEQUENCE */ | ||
1639 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1640 | {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, | ||
1641 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1642 | _NonStandardParameter}, | ||
1643 | {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, | ||
1644 | offsetof(RegistrationConfirm, callSignalAddress), | ||
1645 | _RegistrationConfirm_callSignalAddress}, | ||
1646 | {FNAME("terminalAlias") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1647 | _RegistrationConfirm_terminalAlias}, | ||
1648 | {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, | ||
1649 | {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, | ||
1650 | {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, | ||
1651 | {FNAME("timeToLive") INT, CONS, 1, 0, DECODE | OPT, | ||
1652 | offsetof(RegistrationConfirm, timeToLive), NULL}, | ||
1653 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1654 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1655 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1656 | {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1657 | {FNAME("preGrantedARQ") SEQ, 0, 4, 8, STOP | EXT | OPT, 0, NULL}, | ||
1658 | {FNAME("maintainConnection") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1659 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1660 | {FNAME("supportsAdditiveRegistration") NUL, FIXD, 0, 0, STOP | OPT, 0, | ||
1661 | NULL}, | ||
1662 | {FNAME("terminalAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, | ||
1663 | NULL}, | ||
1664 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1665 | {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1666 | {FNAME("featureServerAlias") CHOICE, 1, 2, 7, STOP | EXT | OPT, 0, | ||
1667 | NULL}, | ||
1668 | {FNAME("capacityReportingSpec") SEQ, 0, 1, 1, STOP | EXT | OPT, 0, | ||
1669 | NULL}, | ||
1670 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1671 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1672 | }; | ||
1673 | |||
1674 | static field_t _UnregistrationRequest_callSignalAddress[] = { /* SEQUENCE OF */ | ||
1675 | {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1676 | sizeof(TransportAddress), _TransportAddress} | ||
1677 | , | ||
1678 | }; | ||
1679 | |||
1680 | static field_t _UnregistrationRequest[] = { /* SEQUENCE */ | ||
1681 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1682 | {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, | ||
1683 | offsetof(UnregistrationRequest, callSignalAddress), | ||
1684 | _UnregistrationRequest_callSignalAddress}, | ||
1685 | {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1686 | {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1687 | {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, | ||
1688 | {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1689 | {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, | ||
1690 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1691 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1692 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1693 | {FNAME("reason") CHOICE, 2, 4, 5, STOP | EXT | OPT, 0, NULL}, | ||
1694 | {FNAME("endpointAliasPattern") SEQOF, SEMI, 0, 0, STOP | OPT, 0, | ||
1695 | NULL}, | ||
1696 | {FNAME("supportedPrefixes") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1697 | {FNAME("alternateGatekeeper") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1698 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1699 | }; | ||
1700 | |||
1701 | static field_t _CallModel[] = { /* CHOICE */ | ||
1702 | {FNAME("direct") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1703 | {FNAME("gatekeeperRouted") NUL, FIXD, 0, 0, SKIP, 0, NULL}, | ||
1704 | }; | ||
1705 | |||
1706 | static field_t _AdmissionRequest_destinationInfo[] = { /* SEQUENCE OF */ | ||
1707 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1708 | }; | ||
1709 | |||
1710 | static field_t _AdmissionRequest_destExtraCallInfo[] = { /* SEQUENCE OF */ | ||
1711 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1712 | }; | ||
1713 | |||
1714 | static field_t _AdmissionRequest_srcInfo[] = { /* SEQUENCE OF */ | ||
1715 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1716 | }; | ||
1717 | |||
1718 | static field_t _AdmissionRequest[] = { /* SEQUENCE */ | ||
1719 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1720 | {FNAME("callType") CHOICE, 2, 4, 4, SKIP | EXT, 0, _CallType}, | ||
1721 | {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT | OPT, 0, _CallModel}, | ||
1722 | {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, | ||
1723 | {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1724 | _AdmissionRequest_destinationInfo}, | ||
1725 | {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
1726 | offsetof(AdmissionRequest, destCallSignalAddress), | ||
1727 | _TransportAddress}, | ||
1728 | {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, | ||
1729 | _AdmissionRequest_destExtraCallInfo}, | ||
1730 | {FNAME("srcInfo") SEQOF, SEMI, 0, 0, SKIP, 0, | ||
1731 | _AdmissionRequest_srcInfo}, | ||
1732 | {FNAME("srcCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT | OPT, | ||
1733 | offsetof(AdmissionRequest, srcCallSignalAddress), _TransportAddress}, | ||
1734 | {FNAME("bandWidth") INT, CONS, 0, 0, STOP, 0, NULL}, | ||
1735 | {FNAME("callReferenceValue") INT, WORD, 0, 0, STOP, 0, NULL}, | ||
1736 | {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1737 | {FNAME("callServices") SEQ, 0, 8, 8, STOP | EXT | OPT, 0, NULL}, | ||
1738 | {FNAME("conferenceID") OCTSTR, FIXD, 16, 0, STOP, 0, NULL}, | ||
1739 | {FNAME("activeMC") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1740 | {FNAME("answerCall") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1741 | {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1742 | {FNAME("callIdentifier") SEQ, 0, 1, 1, STOP | EXT, 0, NULL}, | ||
1743 | {FNAME("srcAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1744 | {FNAME("destAlternatives") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1745 | {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, | ||
1746 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1747 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1748 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1749 | {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1750 | {FNAME("willSupplyUUIEs") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1751 | {FNAME("callLinkage") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
1752 | {FNAME("gatewayDataRate") SEQ, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1753 | {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
1754 | {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1755 | {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1756 | {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, | ||
1757 | NULL}, | ||
1758 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1759 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1760 | }; | ||
1761 | |||
1762 | static field_t _AdmissionConfirm[] = { /* SEQUENCE */ | ||
1763 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1764 | {FNAME("bandWidth") INT, CONS, 0, 0, SKIP, 0, NULL}, | ||
1765 | {FNAME("callModel") CHOICE, 1, 2, 2, SKIP | EXT, 0, _CallModel}, | ||
1766 | {FNAME("destCallSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1767 | offsetof(AdmissionConfirm, destCallSignalAddress), | ||
1768 | _TransportAddress}, | ||
1769 | {FNAME("irrFrequency") INT, WORD, 1, 0, STOP | OPT, 0, NULL}, | ||
1770 | {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1771 | {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1772 | {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1773 | {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL}, | ||
1774 | {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0, | ||
1775 | NULL}, | ||
1776 | {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1777 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1778 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1779 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1780 | {FNAME("transportQOS") CHOICE, 2, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1781 | {FNAME("willRespondToIRR") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1782 | {FNAME("uuiesRequested") SEQ, 0, 9, 13, STOP | EXT, 0, NULL}, | ||
1783 | {FNAME("language") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1784 | {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, | ||
1785 | 0, NULL}, | ||
1786 | {FNAME("useSpecifiedTransport") CHOICE, 1, 2, 2, STOP | EXT | OPT, 0, | ||
1787 | NULL}, | ||
1788 | {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1789 | {FNAME("usageSpec") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1790 | {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1791 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1792 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, | ||
1793 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1794 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1795 | }; | ||
1796 | |||
1797 | static field_t _LocationRequest_destinationInfo[] = { /* SEQUENCE OF */ | ||
1798 | {FNAME("item") CHOICE, 1, 2, 7, SKIP | EXT, 0, _AliasAddress}, | ||
1799 | }; | ||
1800 | |||
1801 | static field_t _LocationRequest[] = { /* SEQUENCE */ | ||
1802 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1803 | {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP | OPT, 0, NULL}, | ||
1804 | {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, SKIP, 0, | ||
1805 | _LocationRequest_destinationInfo}, | ||
1806 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1807 | _NonStandardParameter}, | ||
1808 | {FNAME("replyAddress") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1809 | offsetof(LocationRequest, replyAddress), _TransportAddress}, | ||
1810 | {FNAME("sourceInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1811 | {FNAME("canMapAlias") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1812 | {FNAME("gatekeeperIdentifier") BMPSTR, 7, 1, 0, STOP | OPT, 0, NULL}, | ||
1813 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1814 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1815 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1816 | {FNAME("desiredProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1817 | {FNAME("desiredTunnelledProtocol") SEQ, 1, 2, 2, STOP | EXT | OPT, 0, | ||
1818 | NULL}, | ||
1819 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1820 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1821 | {FNAME("hopCount") INT, 8, 1, 0, STOP | OPT, 0, NULL}, | ||
1822 | {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1823 | }; | ||
1824 | |||
1825 | static field_t _LocationConfirm[] = { /* SEQUENCE */ | ||
1826 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1827 | {FNAME("callSignalAddress") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1828 | offsetof(LocationConfirm, callSignalAddress), _TransportAddress}, | ||
1829 | {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1830 | offsetof(LocationConfirm, rasAddress), _TransportAddress}, | ||
1831 | {FNAME("nonStandardData") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1832 | {FNAME("destinationInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1833 | {FNAME("destExtraCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1834 | {FNAME("destinationType") SEQ, 6, 8, 10, STOP | EXT | OPT, 0, NULL}, | ||
1835 | {FNAME("remoteExtensionAddress") SEQOF, SEMI, 0, 0, STOP | OPT, 0, | ||
1836 | NULL}, | ||
1837 | {FNAME("alternateEndpoints") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1838 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1839 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1840 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1841 | {FNAME("alternateTransportAddresses") SEQ, 1, 1, 1, STOP | EXT | OPT, | ||
1842 | 0, NULL}, | ||
1843 | {FNAME("supportedProtocols") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1844 | {FNAME("multipleCalls") BOOL, FIXD, 0, 0, STOP | OPT, 0, NULL}, | ||
1845 | {FNAME("featureSet") SEQ, 3, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1846 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1847 | {FNAME("circuitInfo") SEQ, 3, 3, 3, STOP | EXT | OPT, 0, NULL}, | ||
1848 | {FNAME("serviceControl") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1849 | }; | ||
1850 | |||
1851 | static field_t _InfoRequestResponse_callSignalAddress[] = { /* SEQUENCE OF */ | ||
1852 | {FNAME("item") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1853 | sizeof(TransportAddress), _TransportAddress} | ||
1854 | , | ||
1855 | }; | ||
1856 | |||
1857 | static field_t _InfoRequestResponse[] = { /* SEQUENCE */ | ||
1858 | {FNAME("nonStandardData") SEQ, 0, 2, 2, SKIP | OPT, 0, | ||
1859 | _NonStandardParameter}, | ||
1860 | {FNAME("requestSeqNum") INT, WORD, 1, 0, SKIP, 0, NULL}, | ||
1861 | {FNAME("endpointType") SEQ, 6, 8, 10, SKIP | EXT, 0, _EndpointType}, | ||
1862 | {FNAME("endpointIdentifier") BMPSTR, 7, 1, 0, SKIP, 0, NULL}, | ||
1863 | {FNAME("rasAddress") CHOICE, 3, 7, 7, DECODE | EXT, | ||
1864 | offsetof(InfoRequestResponse, rasAddress), _TransportAddress}, | ||
1865 | {FNAME("callSignalAddress") SEQOF, SEMI, 0, 10, DECODE, | ||
1866 | offsetof(InfoRequestResponse, callSignalAddress), | ||
1867 | _InfoRequestResponse_callSignalAddress}, | ||
1868 | {FNAME("endpointAlias") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1869 | {FNAME("perCallInfo") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1870 | {FNAME("tokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1871 | {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1872 | {FNAME("integrityCheckValue") SEQ, 0, 2, 2, STOP | OPT, 0, NULL}, | ||
1873 | {FNAME("needResponse") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1874 | {FNAME("capacity") SEQ, 2, 2, 2, STOP | EXT | OPT, 0, NULL}, | ||
1875 | {FNAME("irrStatus") CHOICE, 2, 4, 4, STOP | EXT | OPT, 0, NULL}, | ||
1876 | {FNAME("unsolicited") BOOL, FIXD, 0, 0, STOP, 0, NULL}, | ||
1877 | {FNAME("genericData") SEQOF, SEMI, 0, 0, STOP | OPT, 0, NULL}, | ||
1878 | }; | ||
1879 | |||
1880 | static field_t _RasMessage[] = { /* CHOICE */ | ||
1881 | {FNAME("gatekeeperRequest") SEQ, 4, 8, 18, DECODE | EXT, | ||
1882 | offsetof(RasMessage, gatekeeperRequest), _GatekeeperRequest}, | ||
1883 | {FNAME("gatekeeperConfirm") SEQ, 2, 5, 14, DECODE | EXT, | ||
1884 | offsetof(RasMessage, gatekeeperConfirm), _GatekeeperConfirm}, | ||
1885 | {FNAME("gatekeeperReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL}, | ||
1886 | {FNAME("registrationRequest") SEQ, 3, 10, 31, DECODE | EXT, | ||
1887 | offsetof(RasMessage, registrationRequest), _RegistrationRequest}, | ||
1888 | {FNAME("registrationConfirm") SEQ, 3, 7, 24, DECODE | EXT, | ||
1889 | offsetof(RasMessage, registrationConfirm), _RegistrationConfirm}, | ||
1890 | {FNAME("registrationReject") SEQ, 2, 5, 11, STOP | EXT, 0, NULL}, | ||
1891 | {FNAME("unregistrationRequest") SEQ, 3, 5, 15, DECODE | EXT, | ||
1892 | offsetof(RasMessage, unregistrationRequest), _UnregistrationRequest}, | ||
1893 | {FNAME("unregistrationConfirm") SEQ, 1, 2, 6, STOP | EXT, 0, NULL}, | ||
1894 | {FNAME("unregistrationReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, | ||
1895 | {FNAME("admissionRequest") SEQ, 7, 16, 34, DECODE | EXT, | ||
1896 | offsetof(RasMessage, admissionRequest), _AdmissionRequest}, | ||
1897 | {FNAME("admissionConfirm") SEQ, 2, 6, 27, DECODE | EXT, | ||
1898 | offsetof(RasMessage, admissionConfirm), _AdmissionConfirm}, | ||
1899 | {FNAME("admissionReject") SEQ, 1, 3, 11, STOP | EXT, 0, NULL}, | ||
1900 | {FNAME("bandwidthRequest") SEQ, 2, 7, 18, STOP | EXT, 0, NULL}, | ||
1901 | {FNAME("bandwidthConfirm") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, | ||
1902 | {FNAME("bandwidthReject") SEQ, 1, 4, 9, STOP | EXT, 0, NULL}, | ||
1903 | {FNAME("disengageRequest") SEQ, 1, 6, 19, STOP | EXT, 0, NULL}, | ||
1904 | {FNAME("disengageConfirm") SEQ, 1, 2, 9, STOP | EXT, 0, NULL}, | ||
1905 | {FNAME("disengageReject") SEQ, 1, 3, 8, STOP | EXT, 0, NULL}, | ||
1906 | {FNAME("locationRequest") SEQ, 2, 5, 17, DECODE | EXT, | ||
1907 | offsetof(RasMessage, locationRequest), _LocationRequest}, | ||
1908 | {FNAME("locationConfirm") SEQ, 1, 4, 19, DECODE | EXT, | ||
1909 | offsetof(RasMessage, locationConfirm), _LocationConfirm}, | ||
1910 | {FNAME("locationReject") SEQ, 1, 3, 10, STOP | EXT, 0, NULL}, | ||
1911 | {FNAME("infoRequest") SEQ, 2, 4, 15, STOP | EXT, 0, NULL}, | ||
1912 | {FNAME("infoRequestResponse") SEQ, 3, 8, 16, DECODE | EXT, | ||
1913 | offsetof(RasMessage, infoRequestResponse), _InfoRequestResponse}, | ||
1914 | {FNAME("nonStandardMessage") SEQ, 0, 2, 7, STOP | EXT, 0, NULL}, | ||
1915 | {FNAME("unknownMessageResponse") SEQ, 0, 1, 5, STOP | EXT, 0, NULL}, | ||
1916 | {FNAME("requestInProgress") SEQ, 4, 6, 6, STOP | EXT, 0, NULL}, | ||
1917 | {FNAME("resourcesAvailableIndicate") SEQ, 4, 9, 11, STOP | EXT, 0, | ||
1918 | NULL}, | ||
1919 | {FNAME("resourcesAvailableConfirm") SEQ, 4, 6, 7, STOP | EXT, 0, | ||
1920 | NULL}, | ||
1921 | {FNAME("infoRequestAck") SEQ, 4, 5, 5, STOP | EXT, 0, NULL}, | ||
1922 | {FNAME("infoRequestNak") SEQ, 5, 7, 7, STOP | EXT, 0, NULL}, | ||
1923 | {FNAME("serviceControlIndication") SEQ, 8, 10, 10, STOP | EXT, 0, | ||
1924 | NULL}, | ||
1925 | {FNAME("serviceControlResponse") SEQ, 7, 8, 8, STOP | EXT, 0, NULL}, | ||
1926 | }; | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.h b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.h new file mode 100644 index 000000000000..cc98f7aa5abe --- /dev/null +++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_types.h | |||
@@ -0,0 +1,938 @@ | |||
1 | /* Generated by Jing Min Zhao's ASN.1 parser, Mar 15 2006 | ||
2 | * | ||
3 | * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net> | ||
4 | * | ||
5 | * This source code is licensed under General Public License version 2. | ||
6 | */ | ||
7 | |||
8 | typedef struct TransportAddress_ipAddress { /* SEQUENCE */ | ||
9 | int options; /* No use */ | ||
10 | unsigned ip; | ||
11 | } TransportAddress_ipAddress; | ||
12 | |||
13 | typedef struct TransportAddress { /* CHOICE */ | ||
14 | enum { | ||
15 | eTransportAddress_ipAddress, | ||
16 | eTransportAddress_ipSourceRoute, | ||
17 | eTransportAddress_ipxAddress, | ||
18 | eTransportAddress_ip6Address, | ||
19 | eTransportAddress_netBios, | ||
20 | eTransportAddress_nsap, | ||
21 | eTransportAddress_nonStandardAddress, | ||
22 | } choice; | ||
23 | union { | ||
24 | TransportAddress_ipAddress ipAddress; | ||
25 | }; | ||
26 | } TransportAddress; | ||
27 | |||
28 | typedef struct DataProtocolCapability { /* CHOICE */ | ||
29 | enum { | ||
30 | eDataProtocolCapability_nonStandard, | ||
31 | eDataProtocolCapability_v14buffered, | ||
32 | eDataProtocolCapability_v42lapm, | ||
33 | eDataProtocolCapability_hdlcFrameTunnelling, | ||
34 | eDataProtocolCapability_h310SeparateVCStack, | ||
35 | eDataProtocolCapability_h310SingleVCStack, | ||
36 | eDataProtocolCapability_transparent, | ||
37 | eDataProtocolCapability_segmentationAndReassembly, | ||
38 | eDataProtocolCapability_hdlcFrameTunnelingwSAR, | ||
39 | eDataProtocolCapability_v120, | ||
40 | eDataProtocolCapability_separateLANStack, | ||
41 | eDataProtocolCapability_v76wCompression, | ||
42 | eDataProtocolCapability_tcp, | ||
43 | eDataProtocolCapability_udp, | ||
44 | } choice; | ||
45 | } DataProtocolCapability; | ||
46 | |||
47 | typedef struct DataApplicationCapability_application { /* CHOICE */ | ||
48 | enum { | ||
49 | eDataApplicationCapability_application_nonStandard, | ||
50 | eDataApplicationCapability_application_t120, | ||
51 | eDataApplicationCapability_application_dsm_cc, | ||
52 | eDataApplicationCapability_application_userData, | ||
53 | eDataApplicationCapability_application_t84, | ||
54 | eDataApplicationCapability_application_t434, | ||
55 | eDataApplicationCapability_application_h224, | ||
56 | eDataApplicationCapability_application_nlpid, | ||
57 | eDataApplicationCapability_application_dsvdControl, | ||
58 | eDataApplicationCapability_application_h222DataPartitioning, | ||
59 | eDataApplicationCapability_application_t30fax, | ||
60 | eDataApplicationCapability_application_t140, | ||
61 | eDataApplicationCapability_application_t38fax, | ||
62 | eDataApplicationCapability_application_genericDataCapability, | ||
63 | } choice; | ||
64 | union { | ||
65 | DataProtocolCapability t120; | ||
66 | }; | ||
67 | } DataApplicationCapability_application; | ||
68 | |||
69 | typedef struct DataApplicationCapability { /* SEQUENCE */ | ||
70 | int options; /* No use */ | ||
71 | DataApplicationCapability_application application; | ||
72 | } DataApplicationCapability; | ||
73 | |||
74 | typedef struct DataType { /* CHOICE */ | ||
75 | enum { | ||
76 | eDataType_nonStandard, | ||
77 | eDataType_nullData, | ||
78 | eDataType_videoData, | ||
79 | eDataType_audioData, | ||
80 | eDataType_data, | ||
81 | eDataType_encryptionData, | ||
82 | eDataType_h235Control, | ||
83 | eDataType_h235Media, | ||
84 | eDataType_multiplexedStream, | ||
85 | } choice; | ||
86 | union { | ||
87 | DataApplicationCapability data; | ||
88 | }; | ||
89 | } DataType; | ||
90 | |||
91 | typedef struct UnicastAddress_iPAddress { /* SEQUENCE */ | ||
92 | int options; /* No use */ | ||
93 | unsigned network; | ||
94 | } UnicastAddress_iPAddress; | ||
95 | |||
96 | typedef struct UnicastAddress { /* CHOICE */ | ||
97 | enum { | ||
98 | eUnicastAddress_iPAddress, | ||
99 | eUnicastAddress_iPXAddress, | ||
100 | eUnicastAddress_iP6Address, | ||
101 | eUnicastAddress_netBios, | ||
102 | eUnicastAddress_iPSourceRouteAddress, | ||
103 | eUnicastAddress_nsap, | ||
104 | eUnicastAddress_nonStandardAddress, | ||
105 | } choice; | ||
106 | union { | ||
107 | UnicastAddress_iPAddress iPAddress; | ||
108 | }; | ||
109 | } UnicastAddress; | ||
110 | |||
111 | typedef struct H245_TransportAddress { /* CHOICE */ | ||
112 | enum { | ||
113 | eH245_TransportAddress_unicastAddress, | ||
114 | eH245_TransportAddress_multicastAddress, | ||
115 | } choice; | ||
116 | union { | ||
117 | UnicastAddress unicastAddress; | ||
118 | }; | ||
119 | } H245_TransportAddress; | ||
120 | |||
121 | typedef struct H2250LogicalChannelParameters { /* SEQUENCE */ | ||
122 | enum { | ||
123 | eH2250LogicalChannelParameters_nonStandard = (1 << 31), | ||
124 | eH2250LogicalChannelParameters_associatedSessionID = | ||
125 | (1 << 30), | ||
126 | eH2250LogicalChannelParameters_mediaChannel = (1 << 29), | ||
127 | eH2250LogicalChannelParameters_mediaGuaranteedDelivery = | ||
128 | (1 << 28), | ||
129 | eH2250LogicalChannelParameters_mediaControlChannel = | ||
130 | (1 << 27), | ||
131 | eH2250LogicalChannelParameters_mediaControlGuaranteedDelivery | ||
132 | = (1 << 26), | ||
133 | eH2250LogicalChannelParameters_silenceSuppression = (1 << 25), | ||
134 | eH2250LogicalChannelParameters_destination = (1 << 24), | ||
135 | eH2250LogicalChannelParameters_dynamicRTPPayloadType = | ||
136 | (1 << 23), | ||
137 | eH2250LogicalChannelParameters_mediaPacketization = (1 << 22), | ||
138 | eH2250LogicalChannelParameters_transportCapability = | ||
139 | (1 << 21), | ||
140 | eH2250LogicalChannelParameters_redundancyEncoding = (1 << 20), | ||
141 | eH2250LogicalChannelParameters_source = (1 << 19), | ||
142 | } options; | ||
143 | H245_TransportAddress mediaChannel; | ||
144 | H245_TransportAddress mediaControlChannel; | ||
145 | } H2250LogicalChannelParameters; | ||
146 | |||
147 | typedef struct OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters { /* CHOICE */ | ||
148 | enum { | ||
149 | eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h222LogicalChannelParameters, | ||
150 | eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h223LogicalChannelParameters, | ||
151 | eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_v76LogicalChannelParameters, | ||
152 | eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, | ||
153 | eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_none, | ||
154 | } choice; | ||
155 | union { | ||
156 | H2250LogicalChannelParameters h2250LogicalChannelParameters; | ||
157 | }; | ||
158 | } OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters; | ||
159 | |||
160 | typedef struct OpenLogicalChannel_forwardLogicalChannelParameters { /* SEQUENCE */ | ||
161 | enum { | ||
162 | eOpenLogicalChannel_forwardLogicalChannelParameters_portNumber | ||
163 | = (1 << 31), | ||
164 | eOpenLogicalChannel_forwardLogicalChannelParameters_forwardLogicalChannelDependency | ||
165 | = (1 << 30), | ||
166 | eOpenLogicalChannel_forwardLogicalChannelParameters_replacementFor | ||
167 | = (1 << 29), | ||
168 | } options; | ||
169 | DataType dataType; | ||
170 | OpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters | ||
171 | multiplexParameters; | ||
172 | } OpenLogicalChannel_forwardLogicalChannelParameters; | ||
173 | |||
174 | typedef struct OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters { /* CHOICE */ | ||
175 | enum { | ||
176 | eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h223LogicalChannelParameters, | ||
177 | eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_v76LogicalChannelParameters, | ||
178 | eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, | ||
179 | } choice; | ||
180 | union { | ||
181 | H2250LogicalChannelParameters h2250LogicalChannelParameters; | ||
182 | }; | ||
183 | } OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters; | ||
184 | |||
185 | typedef struct OpenLogicalChannel_reverseLogicalChannelParameters { /* SEQUENCE */ | ||
186 | enum { | ||
187 | eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters | ||
188 | = (1 << 31), | ||
189 | eOpenLogicalChannel_reverseLogicalChannelParameters_reverseLogicalChannelDependency | ||
190 | = (1 << 30), | ||
191 | eOpenLogicalChannel_reverseLogicalChannelParameters_replacementFor | ||
192 | = (1 << 29), | ||
193 | } options; | ||
194 | OpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters | ||
195 | multiplexParameters; | ||
196 | } OpenLogicalChannel_reverseLogicalChannelParameters; | ||
197 | |||
198 | typedef struct NetworkAccessParameters_networkAddress { /* CHOICE */ | ||
199 | enum { | ||
200 | eNetworkAccessParameters_networkAddress_q2931Address, | ||
201 | eNetworkAccessParameters_networkAddress_e164Address, | ||
202 | eNetworkAccessParameters_networkAddress_localAreaAddress, | ||
203 | } choice; | ||
204 | union { | ||
205 | H245_TransportAddress localAreaAddress; | ||
206 | }; | ||
207 | } NetworkAccessParameters_networkAddress; | ||
208 | |||
209 | typedef struct NetworkAccessParameters { /* SEQUENCE */ | ||
210 | enum { | ||
211 | eNetworkAccessParameters_distribution = (1 << 31), | ||
212 | eNetworkAccessParameters_externalReference = (1 << 30), | ||
213 | eNetworkAccessParameters_t120SetupProcedure = (1 << 29), | ||
214 | } options; | ||
215 | NetworkAccessParameters_networkAddress networkAddress; | ||
216 | } NetworkAccessParameters; | ||
217 | |||
218 | typedef struct OpenLogicalChannel { /* SEQUENCE */ | ||
219 | enum { | ||
220 | eOpenLogicalChannel_reverseLogicalChannelParameters = | ||
221 | (1 << 31), | ||
222 | eOpenLogicalChannel_separateStack = (1 << 30), | ||
223 | eOpenLogicalChannel_encryptionSync = (1 << 29), | ||
224 | } options; | ||
225 | OpenLogicalChannel_forwardLogicalChannelParameters | ||
226 | forwardLogicalChannelParameters; | ||
227 | OpenLogicalChannel_reverseLogicalChannelParameters | ||
228 | reverseLogicalChannelParameters; | ||
229 | NetworkAccessParameters separateStack; | ||
230 | } OpenLogicalChannel; | ||
231 | |||
232 | typedef struct Setup_UUIE_fastStart { /* SEQUENCE OF */ | ||
233 | int count; | ||
234 | OpenLogicalChannel item[30]; | ||
235 | } Setup_UUIE_fastStart; | ||
236 | |||
237 | typedef struct Setup_UUIE { /* SEQUENCE */ | ||
238 | enum { | ||
239 | eSetup_UUIE_h245Address = (1 << 31), | ||
240 | eSetup_UUIE_sourceAddress = (1 << 30), | ||
241 | eSetup_UUIE_destinationAddress = (1 << 29), | ||
242 | eSetup_UUIE_destCallSignalAddress = (1 << 28), | ||
243 | eSetup_UUIE_destExtraCallInfo = (1 << 27), | ||
244 | eSetup_UUIE_destExtraCRV = (1 << 26), | ||
245 | eSetup_UUIE_callServices = (1 << 25), | ||
246 | eSetup_UUIE_sourceCallSignalAddress = (1 << 24), | ||
247 | eSetup_UUIE_remoteExtensionAddress = (1 << 23), | ||
248 | eSetup_UUIE_callIdentifier = (1 << 22), | ||
249 | eSetup_UUIE_h245SecurityCapability = (1 << 21), | ||
250 | eSetup_UUIE_tokens = (1 << 20), | ||
251 | eSetup_UUIE_cryptoTokens = (1 << 19), | ||
252 | eSetup_UUIE_fastStart = (1 << 18), | ||
253 | eSetup_UUIE_mediaWaitForConnect = (1 << 17), | ||
254 | eSetup_UUIE_canOverlapSend = (1 << 16), | ||
255 | eSetup_UUIE_endpointIdentifier = (1 << 15), | ||
256 | eSetup_UUIE_multipleCalls = (1 << 14), | ||
257 | eSetup_UUIE_maintainConnection = (1 << 13), | ||
258 | eSetup_UUIE_connectionParameters = (1 << 12), | ||
259 | eSetup_UUIE_language = (1 << 11), | ||
260 | eSetup_UUIE_presentationIndicator = (1 << 10), | ||
261 | eSetup_UUIE_screeningIndicator = (1 << 9), | ||
262 | eSetup_UUIE_serviceControl = (1 << 8), | ||
263 | eSetup_UUIE_symmetricOperationRequired = (1 << 7), | ||
264 | eSetup_UUIE_capacity = (1 << 6), | ||
265 | eSetup_UUIE_circuitInfo = (1 << 5), | ||
266 | eSetup_UUIE_desiredProtocols = (1 << 4), | ||
267 | eSetup_UUIE_neededFeatures = (1 << 3), | ||
268 | eSetup_UUIE_desiredFeatures = (1 << 2), | ||
269 | eSetup_UUIE_supportedFeatures = (1 << 1), | ||
270 | eSetup_UUIE_parallelH245Control = (1 << 0), | ||
271 | } options; | ||
272 | TransportAddress h245Address; | ||
273 | TransportAddress destCallSignalAddress; | ||
274 | TransportAddress sourceCallSignalAddress; | ||
275 | Setup_UUIE_fastStart fastStart; | ||
276 | } Setup_UUIE; | ||
277 | |||
278 | typedef struct CallProceeding_UUIE_fastStart { /* SEQUENCE OF */ | ||
279 | int count; | ||
280 | OpenLogicalChannel item[30]; | ||
281 | } CallProceeding_UUIE_fastStart; | ||
282 | |||
283 | typedef struct CallProceeding_UUIE { /* SEQUENCE */ | ||
284 | enum { | ||
285 | eCallProceeding_UUIE_h245Address = (1 << 31), | ||
286 | eCallProceeding_UUIE_callIdentifier = (1 << 30), | ||
287 | eCallProceeding_UUIE_h245SecurityMode = (1 << 29), | ||
288 | eCallProceeding_UUIE_tokens = (1 << 28), | ||
289 | eCallProceeding_UUIE_cryptoTokens = (1 << 27), | ||
290 | eCallProceeding_UUIE_fastStart = (1 << 26), | ||
291 | eCallProceeding_UUIE_multipleCalls = (1 << 25), | ||
292 | eCallProceeding_UUIE_maintainConnection = (1 << 24), | ||
293 | eCallProceeding_UUIE_fastConnectRefused = (1 << 23), | ||
294 | eCallProceeding_UUIE_featureSet = (1 << 22), | ||
295 | } options; | ||
296 | TransportAddress h245Address; | ||
297 | CallProceeding_UUIE_fastStart fastStart; | ||
298 | } CallProceeding_UUIE; | ||
299 | |||
300 | typedef struct Connect_UUIE_fastStart { /* SEQUENCE OF */ | ||
301 | int count; | ||
302 | OpenLogicalChannel item[30]; | ||
303 | } Connect_UUIE_fastStart; | ||
304 | |||
305 | typedef struct Connect_UUIE { /* SEQUENCE */ | ||
306 | enum { | ||
307 | eConnect_UUIE_h245Address = (1 << 31), | ||
308 | eConnect_UUIE_callIdentifier = (1 << 30), | ||
309 | eConnect_UUIE_h245SecurityMode = (1 << 29), | ||
310 | eConnect_UUIE_tokens = (1 << 28), | ||
311 | eConnect_UUIE_cryptoTokens = (1 << 27), | ||
312 | eConnect_UUIE_fastStart = (1 << 26), | ||
313 | eConnect_UUIE_multipleCalls = (1 << 25), | ||
314 | eConnect_UUIE_maintainConnection = (1 << 24), | ||
315 | eConnect_UUIE_language = (1 << 23), | ||
316 | eConnect_UUIE_connectedAddress = (1 << 22), | ||
317 | eConnect_UUIE_presentationIndicator = (1 << 21), | ||
318 | eConnect_UUIE_screeningIndicator = (1 << 20), | ||
319 | eConnect_UUIE_fastConnectRefused = (1 << 19), | ||
320 | eConnect_UUIE_serviceControl = (1 << 18), | ||
321 | eConnect_UUIE_capacity = (1 << 17), | ||
322 | eConnect_UUIE_featureSet = (1 << 16), | ||
323 | } options; | ||
324 | TransportAddress h245Address; | ||
325 | Connect_UUIE_fastStart fastStart; | ||
326 | } Connect_UUIE; | ||
327 | |||
328 | typedef struct Alerting_UUIE_fastStart { /* SEQUENCE OF */ | ||
329 | int count; | ||
330 | OpenLogicalChannel item[30]; | ||
331 | } Alerting_UUIE_fastStart; | ||
332 | |||
333 | typedef struct Alerting_UUIE { /* SEQUENCE */ | ||
334 | enum { | ||
335 | eAlerting_UUIE_h245Address = (1 << 31), | ||
336 | eAlerting_UUIE_callIdentifier = (1 << 30), | ||
337 | eAlerting_UUIE_h245SecurityMode = (1 << 29), | ||
338 | eAlerting_UUIE_tokens = (1 << 28), | ||
339 | eAlerting_UUIE_cryptoTokens = (1 << 27), | ||
340 | eAlerting_UUIE_fastStart = (1 << 26), | ||
341 | eAlerting_UUIE_multipleCalls = (1 << 25), | ||
342 | eAlerting_UUIE_maintainConnection = (1 << 24), | ||
343 | eAlerting_UUIE_alertingAddress = (1 << 23), | ||
344 | eAlerting_UUIE_presentationIndicator = (1 << 22), | ||
345 | eAlerting_UUIE_screeningIndicator = (1 << 21), | ||
346 | eAlerting_UUIE_fastConnectRefused = (1 << 20), | ||
347 | eAlerting_UUIE_serviceControl = (1 << 19), | ||
348 | eAlerting_UUIE_capacity = (1 << 18), | ||
349 | eAlerting_UUIE_featureSet = (1 << 17), | ||
350 | } options; | ||
351 | TransportAddress h245Address; | ||
352 | Alerting_UUIE_fastStart fastStart; | ||
353 | } Alerting_UUIE; | ||
354 | |||
355 | typedef struct Information_UUIE_fastStart { /* SEQUENCE OF */ | ||
356 | int count; | ||
357 | OpenLogicalChannel item[30]; | ||
358 | } Information_UUIE_fastStart; | ||
359 | |||
360 | typedef struct Information_UUIE { /* SEQUENCE */ | ||
361 | enum { | ||
362 | eInformation_UUIE_callIdentifier = (1 << 31), | ||
363 | eInformation_UUIE_tokens = (1 << 30), | ||
364 | eInformation_UUIE_cryptoTokens = (1 << 29), | ||
365 | eInformation_UUIE_fastStart = (1 << 28), | ||
366 | eInformation_UUIE_fastConnectRefused = (1 << 27), | ||
367 | eInformation_UUIE_circuitInfo = (1 << 26), | ||
368 | } options; | ||
369 | Information_UUIE_fastStart fastStart; | ||
370 | } Information_UUIE; | ||
371 | |||
372 | typedef struct FacilityReason { /* CHOICE */ | ||
373 | enum { | ||
374 | eFacilityReason_routeCallToGatekeeper, | ||
375 | eFacilityReason_callForwarded, | ||
376 | eFacilityReason_routeCallToMC, | ||
377 | eFacilityReason_undefinedReason, | ||
378 | eFacilityReason_conferenceListChoice, | ||
379 | eFacilityReason_startH245, | ||
380 | eFacilityReason_noH245, | ||
381 | eFacilityReason_newTokens, | ||
382 | eFacilityReason_featureSetUpdate, | ||
383 | eFacilityReason_forwardedElements, | ||
384 | eFacilityReason_transportedInformation, | ||
385 | } choice; | ||
386 | } FacilityReason; | ||
387 | |||
388 | typedef struct Facility_UUIE_fastStart { /* SEQUENCE OF */ | ||
389 | int count; | ||
390 | OpenLogicalChannel item[30]; | ||
391 | } Facility_UUIE_fastStart; | ||
392 | |||
393 | typedef struct Facility_UUIE { /* SEQUENCE */ | ||
394 | enum { | ||
395 | eFacility_UUIE_alternativeAddress = (1 << 31), | ||
396 | eFacility_UUIE_alternativeAliasAddress = (1 << 30), | ||
397 | eFacility_UUIE_conferenceID = (1 << 29), | ||
398 | eFacility_UUIE_callIdentifier = (1 << 28), | ||
399 | eFacility_UUIE_destExtraCallInfo = (1 << 27), | ||
400 | eFacility_UUIE_remoteExtensionAddress = (1 << 26), | ||
401 | eFacility_UUIE_tokens = (1 << 25), | ||
402 | eFacility_UUIE_cryptoTokens = (1 << 24), | ||
403 | eFacility_UUIE_conferences = (1 << 23), | ||
404 | eFacility_UUIE_h245Address = (1 << 22), | ||
405 | eFacility_UUIE_fastStart = (1 << 21), | ||
406 | eFacility_UUIE_multipleCalls = (1 << 20), | ||
407 | eFacility_UUIE_maintainConnection = (1 << 19), | ||
408 | eFacility_UUIE_fastConnectRefused = (1 << 18), | ||
409 | eFacility_UUIE_serviceControl = (1 << 17), | ||
410 | eFacility_UUIE_circuitInfo = (1 << 16), | ||
411 | eFacility_UUIE_featureSet = (1 << 15), | ||
412 | eFacility_UUIE_destinationInfo = (1 << 14), | ||
413 | eFacility_UUIE_h245SecurityMode = (1 << 13), | ||
414 | } options; | ||
415 | FacilityReason reason; | ||
416 | TransportAddress h245Address; | ||
417 | Facility_UUIE_fastStart fastStart; | ||
418 | } Facility_UUIE; | ||
419 | |||
420 | typedef struct Progress_UUIE_fastStart { /* SEQUENCE OF */ | ||
421 | int count; | ||
422 | OpenLogicalChannel item[30]; | ||
423 | } Progress_UUIE_fastStart; | ||
424 | |||
425 | typedef struct Progress_UUIE { /* SEQUENCE */ | ||
426 | enum { | ||
427 | eProgress_UUIE_h245Address = (1 << 31), | ||
428 | eProgress_UUIE_h245SecurityMode = (1 << 30), | ||
429 | eProgress_UUIE_tokens = (1 << 29), | ||
430 | eProgress_UUIE_cryptoTokens = (1 << 28), | ||
431 | eProgress_UUIE_fastStart = (1 << 27), | ||
432 | eProgress_UUIE_multipleCalls = (1 << 26), | ||
433 | eProgress_UUIE_maintainConnection = (1 << 25), | ||
434 | eProgress_UUIE_fastConnectRefused = (1 << 24), | ||
435 | } options; | ||
436 | TransportAddress h245Address; | ||
437 | Progress_UUIE_fastStart fastStart; | ||
438 | } Progress_UUIE; | ||
439 | |||
440 | typedef struct H323_UU_PDU_h323_message_body { /* CHOICE */ | ||
441 | enum { | ||
442 | eH323_UU_PDU_h323_message_body_setup, | ||
443 | eH323_UU_PDU_h323_message_body_callProceeding, | ||
444 | eH323_UU_PDU_h323_message_body_connect, | ||
445 | eH323_UU_PDU_h323_message_body_alerting, | ||
446 | eH323_UU_PDU_h323_message_body_information, | ||
447 | eH323_UU_PDU_h323_message_body_releaseComplete, | ||
448 | eH323_UU_PDU_h323_message_body_facility, | ||
449 | eH323_UU_PDU_h323_message_body_progress, | ||
450 | eH323_UU_PDU_h323_message_body_empty, | ||
451 | eH323_UU_PDU_h323_message_body_status, | ||
452 | eH323_UU_PDU_h323_message_body_statusInquiry, | ||
453 | eH323_UU_PDU_h323_message_body_setupAcknowledge, | ||
454 | eH323_UU_PDU_h323_message_body_notify, | ||
455 | } choice; | ||
456 | union { | ||
457 | Setup_UUIE setup; | ||
458 | CallProceeding_UUIE callProceeding; | ||
459 | Connect_UUIE connect; | ||
460 | Alerting_UUIE alerting; | ||
461 | Information_UUIE information; | ||
462 | Facility_UUIE facility; | ||
463 | Progress_UUIE progress; | ||
464 | }; | ||
465 | } H323_UU_PDU_h323_message_body; | ||
466 | |||
467 | typedef struct RequestMessage { /* CHOICE */ | ||
468 | enum { | ||
469 | eRequestMessage_nonStandard, | ||
470 | eRequestMessage_masterSlaveDetermination, | ||
471 | eRequestMessage_terminalCapabilitySet, | ||
472 | eRequestMessage_openLogicalChannel, | ||
473 | eRequestMessage_closeLogicalChannel, | ||
474 | eRequestMessage_requestChannelClose, | ||
475 | eRequestMessage_multiplexEntrySend, | ||
476 | eRequestMessage_requestMultiplexEntry, | ||
477 | eRequestMessage_requestMode, | ||
478 | eRequestMessage_roundTripDelayRequest, | ||
479 | eRequestMessage_maintenanceLoopRequest, | ||
480 | eRequestMessage_communicationModeRequest, | ||
481 | eRequestMessage_conferenceRequest, | ||
482 | eRequestMessage_multilinkRequest, | ||
483 | eRequestMessage_logicalChannelRateRequest, | ||
484 | } choice; | ||
485 | union { | ||
486 | OpenLogicalChannel openLogicalChannel; | ||
487 | }; | ||
488 | } RequestMessage; | ||
489 | |||
490 | typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters { /* CHOICE */ | ||
491 | enum { | ||
492 | eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h222LogicalChannelParameters, | ||
493 | eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters, | ||
494 | } choice; | ||
495 | union { | ||
496 | H2250LogicalChannelParameters h2250LogicalChannelParameters; | ||
497 | }; | ||
498 | } OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters; | ||
499 | |||
500 | typedef struct OpenLogicalChannelAck_reverseLogicalChannelParameters { /* SEQUENCE */ | ||
501 | enum { | ||
502 | eOpenLogicalChannelAck_reverseLogicalChannelParameters_portNumber | ||
503 | = (1 << 31), | ||
504 | eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters | ||
505 | = (1 << 30), | ||
506 | eOpenLogicalChannelAck_reverseLogicalChannelParameters_replacementFor | ||
507 | = (1 << 29), | ||
508 | } options; | ||
509 | OpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters | ||
510 | multiplexParameters; | ||
511 | } OpenLogicalChannelAck_reverseLogicalChannelParameters; | ||
512 | |||
513 | typedef struct H2250LogicalChannelAckParameters { /* SEQUENCE */ | ||
514 | enum { | ||
515 | eH2250LogicalChannelAckParameters_nonStandard = (1 << 31), | ||
516 | eH2250LogicalChannelAckParameters_sessionID = (1 << 30), | ||
517 | eH2250LogicalChannelAckParameters_mediaChannel = (1 << 29), | ||
518 | eH2250LogicalChannelAckParameters_mediaControlChannel = | ||
519 | (1 << 28), | ||
520 | eH2250LogicalChannelAckParameters_dynamicRTPPayloadType = | ||
521 | (1 << 27), | ||
522 | eH2250LogicalChannelAckParameters_flowControlToZero = | ||
523 | (1 << 26), | ||
524 | eH2250LogicalChannelAckParameters_portNumber = (1 << 25), | ||
525 | } options; | ||
526 | H245_TransportAddress mediaChannel; | ||
527 | H245_TransportAddress mediaControlChannel; | ||
528 | } H2250LogicalChannelAckParameters; | ||
529 | |||
530 | typedef struct OpenLogicalChannelAck_forwardMultiplexAckParameters { /* CHOICE */ | ||
531 | enum { | ||
532 | eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters, | ||
533 | } choice; | ||
534 | union { | ||
535 | H2250LogicalChannelAckParameters | ||
536 | h2250LogicalChannelAckParameters; | ||
537 | }; | ||
538 | } OpenLogicalChannelAck_forwardMultiplexAckParameters; | ||
539 | |||
540 | typedef struct OpenLogicalChannelAck { /* SEQUENCE */ | ||
541 | enum { | ||
542 | eOpenLogicalChannelAck_reverseLogicalChannelParameters = | ||
543 | (1 << 31), | ||
544 | eOpenLogicalChannelAck_separateStack = (1 << 30), | ||
545 | eOpenLogicalChannelAck_forwardMultiplexAckParameters = | ||
546 | (1 << 29), | ||
547 | eOpenLogicalChannelAck_encryptionSync = (1 << 28), | ||
548 | } options; | ||
549 | OpenLogicalChannelAck_reverseLogicalChannelParameters | ||
550 | reverseLogicalChannelParameters; | ||
551 | OpenLogicalChannelAck_forwardMultiplexAckParameters | ||
552 | forwardMultiplexAckParameters; | ||
553 | } OpenLogicalChannelAck; | ||
554 | |||
555 | typedef struct ResponseMessage { /* CHOICE */ | ||
556 | enum { | ||
557 | eResponseMessage_nonStandard, | ||
558 | eResponseMessage_masterSlaveDeterminationAck, | ||
559 | eResponseMessage_masterSlaveDeterminationReject, | ||
560 | eResponseMessage_terminalCapabilitySetAck, | ||
561 | eResponseMessage_terminalCapabilitySetReject, | ||
562 | eResponseMessage_openLogicalChannelAck, | ||
563 | eResponseMessage_openLogicalChannelReject, | ||
564 | eResponseMessage_closeLogicalChannelAck, | ||
565 | eResponseMessage_requestChannelCloseAck, | ||
566 | eResponseMessage_requestChannelCloseReject, | ||
567 | eResponseMessage_multiplexEntrySendAck, | ||
568 | eResponseMessage_multiplexEntrySendReject, | ||
569 | eResponseMessage_requestMultiplexEntryAck, | ||
570 | eResponseMessage_requestMultiplexEntryReject, | ||
571 | eResponseMessage_requestModeAck, | ||
572 | eResponseMessage_requestModeReject, | ||
573 | eResponseMessage_roundTripDelayResponse, | ||
574 | eResponseMessage_maintenanceLoopAck, | ||
575 | eResponseMessage_maintenanceLoopReject, | ||
576 | eResponseMessage_communicationModeResponse, | ||
577 | eResponseMessage_conferenceResponse, | ||
578 | eResponseMessage_multilinkResponse, | ||
579 | eResponseMessage_logicalChannelRateAcknowledge, | ||
580 | eResponseMessage_logicalChannelRateReject, | ||
581 | } choice; | ||
582 | union { | ||
583 | OpenLogicalChannelAck openLogicalChannelAck; | ||
584 | }; | ||
585 | } ResponseMessage; | ||
586 | |||
587 | typedef struct MultimediaSystemControlMessage { /* CHOICE */ | ||
588 | enum { | ||
589 | eMultimediaSystemControlMessage_request, | ||
590 | eMultimediaSystemControlMessage_response, | ||
591 | eMultimediaSystemControlMessage_command, | ||
592 | eMultimediaSystemControlMessage_indication, | ||
593 | } choice; | ||
594 | union { | ||
595 | RequestMessage request; | ||
596 | ResponseMessage response; | ||
597 | }; | ||
598 | } MultimediaSystemControlMessage; | ||
599 | |||
600 | typedef struct H323_UU_PDU_h245Control { /* SEQUENCE OF */ | ||
601 | int count; | ||
602 | MultimediaSystemControlMessage item[4]; | ||
603 | } H323_UU_PDU_h245Control; | ||
604 | |||
605 | typedef struct H323_UU_PDU { /* SEQUENCE */ | ||
606 | enum { | ||
607 | eH323_UU_PDU_nonStandardData = (1 << 31), | ||
608 | eH323_UU_PDU_h4501SupplementaryService = (1 << 30), | ||
609 | eH323_UU_PDU_h245Tunneling = (1 << 29), | ||
610 | eH323_UU_PDU_h245Control = (1 << 28), | ||
611 | eH323_UU_PDU_nonStandardControl = (1 << 27), | ||
612 | eH323_UU_PDU_callLinkage = (1 << 26), | ||
613 | eH323_UU_PDU_tunnelledSignallingMessage = (1 << 25), | ||
614 | eH323_UU_PDU_provisionalRespToH245Tunneling = (1 << 24), | ||
615 | eH323_UU_PDU_stimulusControl = (1 << 23), | ||
616 | eH323_UU_PDU_genericData = (1 << 22), | ||
617 | } options; | ||
618 | H323_UU_PDU_h323_message_body h323_message_body; | ||
619 | H323_UU_PDU_h245Control h245Control; | ||
620 | } H323_UU_PDU; | ||
621 | |||
622 | typedef struct H323_UserInformation { /* SEQUENCE */ | ||
623 | enum { | ||
624 | eH323_UserInformation_user_data = (1 << 31), | ||
625 | } options; | ||
626 | H323_UU_PDU h323_uu_pdu; | ||
627 | } H323_UserInformation; | ||
628 | |||
629 | typedef struct GatekeeperRequest { /* SEQUENCE */ | ||
630 | enum { | ||
631 | eGatekeeperRequest_nonStandardData = (1 << 31), | ||
632 | eGatekeeperRequest_gatekeeperIdentifier = (1 << 30), | ||
633 | eGatekeeperRequest_callServices = (1 << 29), | ||
634 | eGatekeeperRequest_endpointAlias = (1 << 28), | ||
635 | eGatekeeperRequest_alternateEndpoints = (1 << 27), | ||
636 | eGatekeeperRequest_tokens = (1 << 26), | ||
637 | eGatekeeperRequest_cryptoTokens = (1 << 25), | ||
638 | eGatekeeperRequest_authenticationCapability = (1 << 24), | ||
639 | eGatekeeperRequest_algorithmOIDs = (1 << 23), | ||
640 | eGatekeeperRequest_integrity = (1 << 22), | ||
641 | eGatekeeperRequest_integrityCheckValue = (1 << 21), | ||
642 | eGatekeeperRequest_supportsAltGK = (1 << 20), | ||
643 | eGatekeeperRequest_featureSet = (1 << 19), | ||
644 | eGatekeeperRequest_genericData = (1 << 18), | ||
645 | } options; | ||
646 | TransportAddress rasAddress; | ||
647 | } GatekeeperRequest; | ||
648 | |||
649 | typedef struct GatekeeperConfirm { /* SEQUENCE */ | ||
650 | enum { | ||
651 | eGatekeeperConfirm_nonStandardData = (1 << 31), | ||
652 | eGatekeeperConfirm_gatekeeperIdentifier = (1 << 30), | ||
653 | eGatekeeperConfirm_alternateGatekeeper = (1 << 29), | ||
654 | eGatekeeperConfirm_authenticationMode = (1 << 28), | ||
655 | eGatekeeperConfirm_tokens = (1 << 27), | ||
656 | eGatekeeperConfirm_cryptoTokens = (1 << 26), | ||
657 | eGatekeeperConfirm_algorithmOID = (1 << 25), | ||
658 | eGatekeeperConfirm_integrity = (1 << 24), | ||
659 | eGatekeeperConfirm_integrityCheckValue = (1 << 23), | ||
660 | eGatekeeperConfirm_featureSet = (1 << 22), | ||
661 | eGatekeeperConfirm_genericData = (1 << 21), | ||
662 | } options; | ||
663 | TransportAddress rasAddress; | ||
664 | } GatekeeperConfirm; | ||
665 | |||
666 | typedef struct RegistrationRequest_callSignalAddress { /* SEQUENCE OF */ | ||
667 | int count; | ||
668 | TransportAddress item[10]; | ||
669 | } RegistrationRequest_callSignalAddress; | ||
670 | |||
671 | typedef struct RegistrationRequest_rasAddress { /* SEQUENCE OF */ | ||
672 | int count; | ||
673 | TransportAddress item[10]; | ||
674 | } RegistrationRequest_rasAddress; | ||
675 | |||
676 | typedef struct RegistrationRequest { /* SEQUENCE */ | ||
677 | enum { | ||
678 | eRegistrationRequest_nonStandardData = (1 << 31), | ||
679 | eRegistrationRequest_terminalAlias = (1 << 30), | ||
680 | eRegistrationRequest_gatekeeperIdentifier = (1 << 29), | ||
681 | eRegistrationRequest_alternateEndpoints = (1 << 28), | ||
682 | eRegistrationRequest_timeToLive = (1 << 27), | ||
683 | eRegistrationRequest_tokens = (1 << 26), | ||
684 | eRegistrationRequest_cryptoTokens = (1 << 25), | ||
685 | eRegistrationRequest_integrityCheckValue = (1 << 24), | ||
686 | eRegistrationRequest_keepAlive = (1 << 23), | ||
687 | eRegistrationRequest_endpointIdentifier = (1 << 22), | ||
688 | eRegistrationRequest_willSupplyUUIEs = (1 << 21), | ||
689 | eRegistrationRequest_maintainConnection = (1 << 20), | ||
690 | eRegistrationRequest_alternateTransportAddresses = (1 << 19), | ||
691 | eRegistrationRequest_additiveRegistration = (1 << 18), | ||
692 | eRegistrationRequest_terminalAliasPattern = (1 << 17), | ||
693 | eRegistrationRequest_supportsAltGK = (1 << 16), | ||
694 | eRegistrationRequest_usageReportingCapability = (1 << 15), | ||
695 | eRegistrationRequest_multipleCalls = (1 << 14), | ||
696 | eRegistrationRequest_supportedH248Packages = (1 << 13), | ||
697 | eRegistrationRequest_callCreditCapability = (1 << 12), | ||
698 | eRegistrationRequest_capacityReportingCapability = (1 << 11), | ||
699 | eRegistrationRequest_capacity = (1 << 10), | ||
700 | eRegistrationRequest_featureSet = (1 << 9), | ||
701 | eRegistrationRequest_genericData = (1 << 8), | ||
702 | } options; | ||
703 | RegistrationRequest_callSignalAddress callSignalAddress; | ||
704 | RegistrationRequest_rasAddress rasAddress; | ||
705 | unsigned timeToLive; | ||
706 | } RegistrationRequest; | ||
707 | |||
708 | typedef struct RegistrationConfirm_callSignalAddress { /* SEQUENCE OF */ | ||
709 | int count; | ||
710 | TransportAddress item[10]; | ||
711 | } RegistrationConfirm_callSignalAddress; | ||
712 | |||
713 | typedef struct RegistrationConfirm { /* SEQUENCE */ | ||
714 | enum { | ||
715 | eRegistrationConfirm_nonStandardData = (1 << 31), | ||
716 | eRegistrationConfirm_terminalAlias = (1 << 30), | ||
717 | eRegistrationConfirm_gatekeeperIdentifier = (1 << 29), | ||
718 | eRegistrationConfirm_alternateGatekeeper = (1 << 28), | ||
719 | eRegistrationConfirm_timeToLive = (1 << 27), | ||
720 | eRegistrationConfirm_tokens = (1 << 26), | ||
721 | eRegistrationConfirm_cryptoTokens = (1 << 25), | ||
722 | eRegistrationConfirm_integrityCheckValue = (1 << 24), | ||
723 | eRegistrationConfirm_willRespondToIRR = (1 << 23), | ||
724 | eRegistrationConfirm_preGrantedARQ = (1 << 22), | ||
725 | eRegistrationConfirm_maintainConnection = (1 << 21), | ||
726 | eRegistrationConfirm_serviceControl = (1 << 20), | ||
727 | eRegistrationConfirm_supportsAdditiveRegistration = (1 << 19), | ||
728 | eRegistrationConfirm_terminalAliasPattern = (1 << 18), | ||
729 | eRegistrationConfirm_supportedPrefixes = (1 << 17), | ||
730 | eRegistrationConfirm_usageSpec = (1 << 16), | ||
731 | eRegistrationConfirm_featureServerAlias = (1 << 15), | ||
732 | eRegistrationConfirm_capacityReportingSpec = (1 << 14), | ||
733 | eRegistrationConfirm_featureSet = (1 << 13), | ||
734 | eRegistrationConfirm_genericData = (1 << 12), | ||
735 | } options; | ||
736 | RegistrationConfirm_callSignalAddress callSignalAddress; | ||
737 | unsigned timeToLive; | ||
738 | } RegistrationConfirm; | ||
739 | |||
740 | typedef struct UnregistrationRequest_callSignalAddress { /* SEQUENCE OF */ | ||
741 | int count; | ||
742 | TransportAddress item[10]; | ||
743 | } UnregistrationRequest_callSignalAddress; | ||
744 | |||
745 | typedef struct UnregistrationRequest { /* SEQUENCE */ | ||
746 | enum { | ||
747 | eUnregistrationRequest_endpointAlias = (1 << 31), | ||
748 | eUnregistrationRequest_nonStandardData = (1 << 30), | ||
749 | eUnregistrationRequest_endpointIdentifier = (1 << 29), | ||
750 | eUnregistrationRequest_alternateEndpoints = (1 << 28), | ||
751 | eUnregistrationRequest_gatekeeperIdentifier = (1 << 27), | ||
752 | eUnregistrationRequest_tokens = (1 << 26), | ||
753 | eUnregistrationRequest_cryptoTokens = (1 << 25), | ||
754 | eUnregistrationRequest_integrityCheckValue = (1 << 24), | ||
755 | eUnregistrationRequest_reason = (1 << 23), | ||
756 | eUnregistrationRequest_endpointAliasPattern = (1 << 22), | ||
757 | eUnregistrationRequest_supportedPrefixes = (1 << 21), | ||
758 | eUnregistrationRequest_alternateGatekeeper = (1 << 20), | ||
759 | eUnregistrationRequest_genericData = (1 << 19), | ||
760 | } options; | ||
761 | UnregistrationRequest_callSignalAddress callSignalAddress; | ||
762 | } UnregistrationRequest; | ||
763 | |||
764 | typedef struct AdmissionRequest { /* SEQUENCE */ | ||
765 | enum { | ||
766 | eAdmissionRequest_callModel = (1 << 31), | ||
767 | eAdmissionRequest_destinationInfo = (1 << 30), | ||
768 | eAdmissionRequest_destCallSignalAddress = (1 << 29), | ||
769 | eAdmissionRequest_destExtraCallInfo = (1 << 28), | ||
770 | eAdmissionRequest_srcCallSignalAddress = (1 << 27), | ||
771 | eAdmissionRequest_nonStandardData = (1 << 26), | ||
772 | eAdmissionRequest_callServices = (1 << 25), | ||
773 | eAdmissionRequest_canMapAlias = (1 << 24), | ||
774 | eAdmissionRequest_callIdentifier = (1 << 23), | ||
775 | eAdmissionRequest_srcAlternatives = (1 << 22), | ||
776 | eAdmissionRequest_destAlternatives = (1 << 21), | ||
777 | eAdmissionRequest_gatekeeperIdentifier = (1 << 20), | ||
778 | eAdmissionRequest_tokens = (1 << 19), | ||
779 | eAdmissionRequest_cryptoTokens = (1 << 18), | ||
780 | eAdmissionRequest_integrityCheckValue = (1 << 17), | ||
781 | eAdmissionRequest_transportQOS = (1 << 16), | ||
782 | eAdmissionRequest_willSupplyUUIEs = (1 << 15), | ||
783 | eAdmissionRequest_callLinkage = (1 << 14), | ||
784 | eAdmissionRequest_gatewayDataRate = (1 << 13), | ||
785 | eAdmissionRequest_capacity = (1 << 12), | ||
786 | eAdmissionRequest_circuitInfo = (1 << 11), | ||
787 | eAdmissionRequest_desiredProtocols = (1 << 10), | ||
788 | eAdmissionRequest_desiredTunnelledProtocol = (1 << 9), | ||
789 | eAdmissionRequest_featureSet = (1 << 8), | ||
790 | eAdmissionRequest_genericData = (1 << 7), | ||
791 | } options; | ||
792 | TransportAddress destCallSignalAddress; | ||
793 | TransportAddress srcCallSignalAddress; | ||
794 | } AdmissionRequest; | ||
795 | |||
796 | typedef struct AdmissionConfirm { /* SEQUENCE */ | ||
797 | enum { | ||
798 | eAdmissionConfirm_irrFrequency = (1 << 31), | ||
799 | eAdmissionConfirm_nonStandardData = (1 << 30), | ||
800 | eAdmissionConfirm_destinationInfo = (1 << 29), | ||
801 | eAdmissionConfirm_destExtraCallInfo = (1 << 28), | ||
802 | eAdmissionConfirm_destinationType = (1 << 27), | ||
803 | eAdmissionConfirm_remoteExtensionAddress = (1 << 26), | ||
804 | eAdmissionConfirm_alternateEndpoints = (1 << 25), | ||
805 | eAdmissionConfirm_tokens = (1 << 24), | ||
806 | eAdmissionConfirm_cryptoTokens = (1 << 23), | ||
807 | eAdmissionConfirm_integrityCheckValue = (1 << 22), | ||
808 | eAdmissionConfirm_transportQOS = (1 << 21), | ||
809 | eAdmissionConfirm_willRespondToIRR = (1 << 20), | ||
810 | eAdmissionConfirm_uuiesRequested = (1 << 19), | ||
811 | eAdmissionConfirm_language = (1 << 18), | ||
812 | eAdmissionConfirm_alternateTransportAddresses = (1 << 17), | ||
813 | eAdmissionConfirm_useSpecifiedTransport = (1 << 16), | ||
814 | eAdmissionConfirm_circuitInfo = (1 << 15), | ||
815 | eAdmissionConfirm_usageSpec = (1 << 14), | ||
816 | eAdmissionConfirm_supportedProtocols = (1 << 13), | ||
817 | eAdmissionConfirm_serviceControl = (1 << 12), | ||
818 | eAdmissionConfirm_multipleCalls = (1 << 11), | ||
819 | eAdmissionConfirm_featureSet = (1 << 10), | ||
820 | eAdmissionConfirm_genericData = (1 << 9), | ||
821 | } options; | ||
822 | TransportAddress destCallSignalAddress; | ||
823 | } AdmissionConfirm; | ||
824 | |||
825 | typedef struct LocationRequest { /* SEQUENCE */ | ||
826 | enum { | ||
827 | eLocationRequest_endpointIdentifier = (1 << 31), | ||
828 | eLocationRequest_nonStandardData = (1 << 30), | ||
829 | eLocationRequest_sourceInfo = (1 << 29), | ||
830 | eLocationRequest_canMapAlias = (1 << 28), | ||
831 | eLocationRequest_gatekeeperIdentifier = (1 << 27), | ||
832 | eLocationRequest_tokens = (1 << 26), | ||
833 | eLocationRequest_cryptoTokens = (1 << 25), | ||
834 | eLocationRequest_integrityCheckValue = (1 << 24), | ||
835 | eLocationRequest_desiredProtocols = (1 << 23), | ||
836 | eLocationRequest_desiredTunnelledProtocol = (1 << 22), | ||
837 | eLocationRequest_featureSet = (1 << 21), | ||
838 | eLocationRequest_genericData = (1 << 20), | ||
839 | eLocationRequest_hopCount = (1 << 19), | ||
840 | eLocationRequest_circuitInfo = (1 << 18), | ||
841 | } options; | ||
842 | TransportAddress replyAddress; | ||
843 | } LocationRequest; | ||
844 | |||
845 | typedef struct LocationConfirm { /* SEQUENCE */ | ||
846 | enum { | ||
847 | eLocationConfirm_nonStandardData = (1 << 31), | ||
848 | eLocationConfirm_destinationInfo = (1 << 30), | ||
849 | eLocationConfirm_destExtraCallInfo = (1 << 29), | ||
850 | eLocationConfirm_destinationType = (1 << 28), | ||
851 | eLocationConfirm_remoteExtensionAddress = (1 << 27), | ||
852 | eLocationConfirm_alternateEndpoints = (1 << 26), | ||
853 | eLocationConfirm_tokens = (1 << 25), | ||
854 | eLocationConfirm_cryptoTokens = (1 << 24), | ||
855 | eLocationConfirm_integrityCheckValue = (1 << 23), | ||
856 | eLocationConfirm_alternateTransportAddresses = (1 << 22), | ||
857 | eLocationConfirm_supportedProtocols = (1 << 21), | ||
858 | eLocationConfirm_multipleCalls = (1 << 20), | ||
859 | eLocationConfirm_featureSet = (1 << 19), | ||
860 | eLocationConfirm_genericData = (1 << 18), | ||
861 | eLocationConfirm_circuitInfo = (1 << 17), | ||
862 | eLocationConfirm_serviceControl = (1 << 16), | ||
863 | } options; | ||
864 | TransportAddress callSignalAddress; | ||
865 | TransportAddress rasAddress; | ||
866 | } LocationConfirm; | ||
867 | |||
868 | typedef struct InfoRequestResponse_callSignalAddress { /* SEQUENCE OF */ | ||
869 | int count; | ||
870 | TransportAddress item[10]; | ||
871 | } InfoRequestResponse_callSignalAddress; | ||
872 | |||
873 | typedef struct InfoRequestResponse { /* SEQUENCE */ | ||
874 | enum { | ||
875 | eInfoRequestResponse_nonStandardData = (1 << 31), | ||
876 | eInfoRequestResponse_endpointAlias = (1 << 30), | ||
877 | eInfoRequestResponse_perCallInfo = (1 << 29), | ||
878 | eInfoRequestResponse_tokens = (1 << 28), | ||
879 | eInfoRequestResponse_cryptoTokens = (1 << 27), | ||
880 | eInfoRequestResponse_integrityCheckValue = (1 << 26), | ||
881 | eInfoRequestResponse_needResponse = (1 << 25), | ||
882 | eInfoRequestResponse_capacity = (1 << 24), | ||
883 | eInfoRequestResponse_irrStatus = (1 << 23), | ||
884 | eInfoRequestResponse_unsolicited = (1 << 22), | ||
885 | eInfoRequestResponse_genericData = (1 << 21), | ||
886 | } options; | ||
887 | TransportAddress rasAddress; | ||
888 | InfoRequestResponse_callSignalAddress callSignalAddress; | ||
889 | } InfoRequestResponse; | ||
890 | |||
891 | typedef struct RasMessage { /* CHOICE */ | ||
892 | enum { | ||
893 | eRasMessage_gatekeeperRequest, | ||
894 | eRasMessage_gatekeeperConfirm, | ||
895 | eRasMessage_gatekeeperReject, | ||
896 | eRasMessage_registrationRequest, | ||
897 | eRasMessage_registrationConfirm, | ||
898 | eRasMessage_registrationReject, | ||
899 | eRasMessage_unregistrationRequest, | ||
900 | eRasMessage_unregistrationConfirm, | ||
901 | eRasMessage_unregistrationReject, | ||
902 | eRasMessage_admissionRequest, | ||
903 | eRasMessage_admissionConfirm, | ||
904 | eRasMessage_admissionReject, | ||
905 | eRasMessage_bandwidthRequest, | ||
906 | eRasMessage_bandwidthConfirm, | ||
907 | eRasMessage_bandwidthReject, | ||
908 | eRasMessage_disengageRequest, | ||
909 | eRasMessage_disengageConfirm, | ||
910 | eRasMessage_disengageReject, | ||
911 | eRasMessage_locationRequest, | ||
912 | eRasMessage_locationConfirm, | ||
913 | eRasMessage_locationReject, | ||
914 | eRasMessage_infoRequest, | ||
915 | eRasMessage_infoRequestResponse, | ||
916 | eRasMessage_nonStandardMessage, | ||
917 | eRasMessage_unknownMessageResponse, | ||
918 | eRasMessage_requestInProgress, | ||
919 | eRasMessage_resourcesAvailableIndicate, | ||
920 | eRasMessage_resourcesAvailableConfirm, | ||
921 | eRasMessage_infoRequestAck, | ||
922 | eRasMessage_infoRequestNak, | ||
923 | eRasMessage_serviceControlIndication, | ||
924 | eRasMessage_serviceControlResponse, | ||
925 | } choice; | ||
926 | union { | ||
927 | GatekeeperRequest gatekeeperRequest; | ||
928 | GatekeeperConfirm gatekeeperConfirm; | ||
929 | RegistrationRequest registrationRequest; | ||
930 | RegistrationConfirm registrationConfirm; | ||
931 | UnregistrationRequest unregistrationRequest; | ||
932 | AdmissionRequest admissionRequest; | ||
933 | AdmissionConfirm admissionConfirm; | ||
934 | LocationRequest locationRequest; | ||
935 | LocationConfirm locationConfirm; | ||
936 | InfoRequestResponse infoRequestResponse; | ||
937 | }; | ||
938 | } RasMessage; | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index e0b5926c76f9..9b6e19bae90f 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * (C) 2001 by Jay Schulist <jschlst@samba.org> | 4 | * (C) 2001 by Jay Schulist <jschlst@samba.org> |
5 | * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org> | 5 | * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org> |
6 | * (C) 2003 by Patrick Mchardy <kaber@trash.net> | 6 | * (C) 2003 by Patrick Mchardy <kaber@trash.net> |
7 | * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net> | 7 | * (C) 2005-2006 by Pablo Neira Ayuso <pablo@eurodev.net> |
8 | * | 8 | * |
9 | * I've reworked this stuff to use attributes instead of conntrack | 9 | * I've reworked this stuff to use attributes instead of conntrack |
10 | * structures. 5.44 am. I need more tea. --pablo 05/07/11. | 10 | * structures. 5.44 am. I need more tea. --pablo 05/07/11. |
@@ -53,20 +53,18 @@ static char __initdata version[] = "0.90"; | |||
53 | 53 | ||
54 | static inline int | 54 | static inline int |
55 | ctnetlink_dump_tuples_proto(struct sk_buff *skb, | 55 | ctnetlink_dump_tuples_proto(struct sk_buff *skb, |
56 | const struct ip_conntrack_tuple *tuple) | 56 | const struct ip_conntrack_tuple *tuple, |
57 | struct ip_conntrack_protocol *proto) | ||
57 | { | 58 | { |
58 | struct ip_conntrack_protocol *proto; | ||
59 | int ret = 0; | 59 | int ret = 0; |
60 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); | ||
60 | 61 | ||
61 | NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); | 62 | NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); |
62 | 63 | ||
63 | /* If no protocol helper is found, this function will return the | ||
64 | * generic protocol helper, so proto won't *ever* be NULL */ | ||
65 | proto = ip_conntrack_proto_find_get(tuple->dst.protonum); | ||
66 | if (likely(proto->tuple_to_nfattr)) | 64 | if (likely(proto->tuple_to_nfattr)) |
67 | ret = proto->tuple_to_nfattr(skb, tuple); | 65 | ret = proto->tuple_to_nfattr(skb, tuple); |
68 | 66 | ||
69 | ip_conntrack_proto_put(proto); | 67 | NFA_NEST_END(skb, nest_parms); |
70 | 68 | ||
71 | return ret; | 69 | return ret; |
72 | 70 | ||
@@ -75,28 +73,41 @@ nfattr_failure: | |||
75 | } | 73 | } |
76 | 74 | ||
77 | static inline int | 75 | static inline int |
78 | ctnetlink_dump_tuples(struct sk_buff *skb, | 76 | ctnetlink_dump_tuples_ip(struct sk_buff *skb, |
79 | const struct ip_conntrack_tuple *tuple) | 77 | const struct ip_conntrack_tuple *tuple) |
80 | { | 78 | { |
81 | struct nfattr *nest_parms; | 79 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); |
82 | int ret; | ||
83 | 80 | ||
84 | nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); | ||
85 | NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip); | 81 | NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip); |
86 | NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t), &tuple->dst.ip); | 82 | NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t), &tuple->dst.ip); |
87 | NFA_NEST_END(skb, nest_parms); | ||
88 | 83 | ||
89 | nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); | ||
90 | ret = ctnetlink_dump_tuples_proto(skb, tuple); | ||
91 | NFA_NEST_END(skb, nest_parms); | 84 | NFA_NEST_END(skb, nest_parms); |
92 | 85 | ||
93 | return ret; | 86 | return 0; |
94 | 87 | ||
95 | nfattr_failure: | 88 | nfattr_failure: |
96 | return -1; | 89 | return -1; |
97 | } | 90 | } |
98 | 91 | ||
99 | static inline int | 92 | static inline int |
93 | ctnetlink_dump_tuples(struct sk_buff *skb, | ||
94 | const struct ip_conntrack_tuple *tuple) | ||
95 | { | ||
96 | int ret; | ||
97 | struct ip_conntrack_protocol *proto; | ||
98 | |||
99 | ret = ctnetlink_dump_tuples_ip(skb, tuple); | ||
100 | if (unlikely(ret < 0)) | ||
101 | return ret; | ||
102 | |||
103 | proto = ip_conntrack_proto_find_get(tuple->dst.protonum); | ||
104 | ret = ctnetlink_dump_tuples_proto(skb, tuple, proto); | ||
105 | ip_conntrack_proto_put(proto); | ||
106 | |||
107 | return ret; | ||
108 | } | ||
109 | |||
110 | static inline int | ||
100 | ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct) | 111 | ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct) |
101 | { | 112 | { |
102 | u_int32_t status = htonl((u_int32_t) ct->status); | 113 | u_int32_t status = htonl((u_int32_t) ct->status); |
@@ -327,9 +338,10 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, | |||
327 | group = NFNLGRP_CONNTRACK_UPDATE; | 338 | group = NFNLGRP_CONNTRACK_UPDATE; |
328 | } else | 339 | } else |
329 | return NOTIFY_DONE; | 340 | return NOTIFY_DONE; |
330 | 341 | ||
331 | /* FIXME: Check if there are any listeners before, don't hurt performance */ | 342 | if (!nfnetlink_has_listeners(group)) |
332 | 343 | return NOTIFY_DONE; | |
344 | |||
333 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | 345 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); |
334 | if (!skb) | 346 | if (!skb) |
335 | return NOTIFY_DONE; | 347 | return NOTIFY_DONE; |
@@ -1134,6 +1146,33 @@ nfattr_failure: | |||
1134 | } | 1146 | } |
1135 | 1147 | ||
1136 | static inline int | 1148 | static inline int |
1149 | ctnetlink_exp_dump_mask(struct sk_buff *skb, | ||
1150 | const struct ip_conntrack_tuple *tuple, | ||
1151 | const struct ip_conntrack_tuple *mask) | ||
1152 | { | ||
1153 | int ret; | ||
1154 | struct ip_conntrack_protocol *proto; | ||
1155 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_EXPECT_MASK); | ||
1156 | |||
1157 | ret = ctnetlink_dump_tuples_ip(skb, mask); | ||
1158 | if (unlikely(ret < 0)) | ||
1159 | goto nfattr_failure; | ||
1160 | |||
1161 | proto = ip_conntrack_proto_find_get(tuple->dst.protonum); | ||
1162 | ret = ctnetlink_dump_tuples_proto(skb, mask, proto); | ||
1163 | ip_conntrack_proto_put(proto); | ||
1164 | if (unlikely(ret < 0)) | ||
1165 | goto nfattr_failure; | ||
1166 | |||
1167 | NFA_NEST_END(skb, nest_parms); | ||
1168 | |||
1169 | return 0; | ||
1170 | |||
1171 | nfattr_failure: | ||
1172 | return -1; | ||
1173 | } | ||
1174 | |||
1175 | static inline int | ||
1137 | ctnetlink_exp_dump_expect(struct sk_buff *skb, | 1176 | ctnetlink_exp_dump_expect(struct sk_buff *skb, |
1138 | const struct ip_conntrack_expect *exp) | 1177 | const struct ip_conntrack_expect *exp) |
1139 | { | 1178 | { |
@@ -1143,7 +1182,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, | |||
1143 | 1182 | ||
1144 | if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) | 1183 | if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) |
1145 | goto nfattr_failure; | 1184 | goto nfattr_failure; |
1146 | if (ctnetlink_exp_dump_tuple(skb, &exp->mask, CTA_EXPECT_MASK) < 0) | 1185 | if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0) |
1147 | goto nfattr_failure; | 1186 | goto nfattr_failure; |
1148 | if (ctnetlink_exp_dump_tuple(skb, | 1187 | if (ctnetlink_exp_dump_tuple(skb, |
1149 | &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | 1188 | &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
diff --git a/net/ipv4/netfilter/ip_nat_helper_h323.c b/net/ipv4/netfilter/ip_nat_helper_h323.c new file mode 100644 index 000000000000..a0bc883928c0 --- /dev/null +++ b/net/ipv4/netfilter/ip_nat_helper_h323.c | |||
@@ -0,0 +1,605 @@ | |||
1 | /* | ||
2 | * H.323 extension for NAT alteration. | ||
3 | * | ||
4 | * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net> | ||
5 | * | ||
6 | * This source code is licensed under General Public License version 2. | ||
7 | * | ||
8 | * Based on the 'brute force' H.323 NAT module by | ||
9 | * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | ||
10 | * | ||
11 | * Changes: | ||
12 | * 2006-02-01 - initial version 0.1 | ||
13 | * | ||
14 | * 2006-02-20 - version 0.2 | ||
15 | * 1. Changed source format to follow kernel conventions | ||
16 | * 2. Deleted some unnecessary structures | ||
17 | * 3. Minor fixes | ||
18 | * | ||
19 | * 2006-03-10 - version 0.3 | ||
20 | * 1. Added support for multiple TPKTs in one packet (suggested by | ||
21 | * Patrick McHardy) | ||
22 | * 2. Added support for non-linear skb (based on Patrick McHardy's patch) | ||
23 | * 3. Eliminated unnecessary return code | ||
24 | * | ||
25 | * 2006-03-15 - version 0.4 | ||
26 | * 1. Added support for T.120 channels | ||
27 | * 2. Added parameter gkrouted_only (suggested by Patrick McHardy) | ||
28 | */ | ||
29 | |||
30 | #include <linux/module.h> | ||
31 | #include <linux/netfilter_ipv4.h> | ||
32 | #include <linux/netfilter.h> | ||
33 | #include <linux/ip.h> | ||
34 | #include <linux/tcp.h> | ||
35 | #include <linux/moduleparam.h> | ||
36 | #include <net/tcp.h> | ||
37 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
38 | #include <linux/netfilter_ipv4/ip_nat_helper.h> | ||
39 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
40 | #include <linux/netfilter_ipv4/ip_conntrack_tuple.h> | ||
41 | #include <linux/netfilter_ipv4/ip_conntrack_h323.h> | ||
42 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
43 | |||
44 | #include "ip_conntrack_helper_h323_asn1.h" | ||
45 | |||
46 | #if 0 | ||
47 | #define DEBUGP printk | ||
48 | #else | ||
49 | #define DEBUGP(format, args...) | ||
50 | #endif | ||
51 | |||
52 | extern int get_h245_addr(unsigned char *data, H245_TransportAddress * addr, | ||
53 | u_int32_t * ip, u_int16_t * port); | ||
54 | extern int get_h225_addr(unsigned char *data, TransportAddress * addr, | ||
55 | u_int32_t * ip, u_int16_t * port); | ||
56 | extern void ip_conntrack_h245_expect(struct ip_conntrack *new, | ||
57 | struct ip_conntrack_expect *this); | ||
58 | extern void ip_conntrack_q931_expect(struct ip_conntrack *new, | ||
59 | struct ip_conntrack_expect *this); | ||
60 | extern int (*set_h245_addr_hook) (struct sk_buff ** pskb, | ||
61 | unsigned char **data, int dataoff, | ||
62 | H245_TransportAddress * addr, | ||
63 | u_int32_t ip, u_int16_t port); | ||
64 | extern int (*set_h225_addr_hook) (struct sk_buff ** pskb, | ||
65 | unsigned char **data, int dataoff, | ||
66 | TransportAddress * addr, | ||
67 | u_int32_t ip, u_int16_t port); | ||
68 | extern int (*set_sig_addr_hook) (struct sk_buff ** pskb, | ||
69 | struct ip_conntrack * ct, | ||
70 | enum ip_conntrack_info ctinfo, | ||
71 | unsigned char **data, | ||
72 | TransportAddress * addr, int count); | ||
73 | extern int (*set_ras_addr_hook) (struct sk_buff ** pskb, | ||
74 | struct ip_conntrack * ct, | ||
75 | enum ip_conntrack_info ctinfo, | ||
76 | unsigned char **data, | ||
77 | TransportAddress * addr, int count); | ||
78 | extern int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb, | ||
79 | struct ip_conntrack * ct, | ||
80 | enum ip_conntrack_info ctinfo, | ||
81 | unsigned char **data, int dataoff, | ||
82 | H245_TransportAddress * addr, | ||
83 | u_int16_t port, u_int16_t rtp_port, | ||
84 | struct ip_conntrack_expect * rtp_exp, | ||
85 | struct ip_conntrack_expect * rtcp_exp); | ||
86 | extern int (*nat_t120_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, | ||
87 | enum ip_conntrack_info ctinfo, | ||
88 | unsigned char **data, int dataoff, | ||
89 | H245_TransportAddress * addr, u_int16_t port, | ||
90 | struct ip_conntrack_expect * exp); | ||
91 | extern int (*nat_h245_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, | ||
92 | enum ip_conntrack_info ctinfo, | ||
93 | unsigned char **data, int dataoff, | ||
94 | TransportAddress * addr, u_int16_t port, | ||
95 | struct ip_conntrack_expect * exp); | ||
96 | extern int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, | ||
97 | enum ip_conntrack_info ctinfo, | ||
98 | unsigned char **data, TransportAddress * addr, | ||
99 | int idx, u_int16_t port, | ||
100 | struct ip_conntrack_expect * exp); | ||
101 | |||
102 | |||
103 | /****************************************************************************/ | ||
104 | static int set_addr(struct sk_buff **pskb, | ||
105 | unsigned char **data, int dataoff, | ||
106 | unsigned int addroff, u_int32_t ip, u_int16_t port) | ||
107 | { | ||
108 | enum ip_conntrack_info ctinfo; | ||
109 | struct ip_conntrack *ct = ip_conntrack_get(*pskb, &ctinfo); | ||
110 | struct { | ||
111 | u_int32_t ip; | ||
112 | u_int16_t port; | ||
113 | } __attribute__ ((__packed__)) buf; | ||
114 | struct tcphdr _tcph, *th; | ||
115 | |||
116 | buf.ip = ip; | ||
117 | buf.port = htons(port); | ||
118 | addroff += dataoff; | ||
119 | |||
120 | if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) { | ||
121 | if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, | ||
122 | addroff, sizeof(buf), | ||
123 | (char *) &buf, sizeof(buf))) { | ||
124 | if (net_ratelimit()) | ||
125 | printk("ip_nat_h323: ip_nat_mangle_tcp_packet" | ||
126 | " error\n"); | ||
127 | return -1; | ||
128 | } | ||
129 | |||
130 | /* Relocate data pointer */ | ||
131 | th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4, | ||
132 | sizeof(_tcph), &_tcph); | ||
133 | if (th == NULL) | ||
134 | return -1; | ||
135 | *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 + | ||
136 | th->doff * 4 + dataoff; | ||
137 | } else { | ||
138 | if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, | ||
139 | addroff, sizeof(buf), | ||
140 | (char *) &buf, sizeof(buf))) { | ||
141 | if (net_ratelimit()) | ||
142 | printk("ip_nat_h323: ip_nat_mangle_udp_packet" | ||
143 | " error\n"); | ||
144 | return -1; | ||
145 | } | ||
146 | /* ip_nat_mangle_udp_packet uses skb_make_writable() to copy | ||
147 | * or pull everything in a linear buffer, so we can safely | ||
148 | * use the skb pointers now */ | ||
149 | *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 + | ||
150 | sizeof(struct udphdr); | ||
151 | } | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | /****************************************************************************/ | ||
157 | static int set_h225_addr(struct sk_buff **pskb, | ||
158 | unsigned char **data, int dataoff, | ||
159 | TransportAddress * addr, | ||
160 | u_int32_t ip, u_int16_t port) | ||
161 | { | ||
162 | return set_addr(pskb, data, dataoff, addr->ipAddress.ip, ip, port); | ||
163 | } | ||
164 | |||
165 | /****************************************************************************/ | ||
166 | static int set_h245_addr(struct sk_buff **pskb, | ||
167 | unsigned char **data, int dataoff, | ||
168 | H245_TransportAddress * addr, | ||
169 | u_int32_t ip, u_int16_t port) | ||
170 | { | ||
171 | return set_addr(pskb, data, dataoff, | ||
172 | addr->unicastAddress.iPAddress.network, ip, port); | ||
173 | } | ||
174 | |||
175 | /****************************************************************************/ | ||
176 | static int set_sig_addr(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
177 | enum ip_conntrack_info ctinfo, | ||
178 | unsigned char **data, | ||
179 | TransportAddress * addr, int count) | ||
180 | { | ||
181 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
182 | int dir = CTINFO2DIR(ctinfo); | ||
183 | int i; | ||
184 | u_int32_t ip; | ||
185 | u_int16_t port; | ||
186 | |||
187 | for (i = 0; i < count; i++) { | ||
188 | if (get_h225_addr(*data, &addr[i], &ip, &port)) { | ||
189 | if (ip == ct->tuplehash[dir].tuple.src.ip && | ||
190 | port == info->sig_port[dir]) { | ||
191 | /* GW->GK */ | ||
192 | |||
193 | /* Fix for Gnomemeeting */ | ||
194 | if (i > 0 && | ||
195 | get_h225_addr(*data, &addr[0], | ||
196 | &ip, &port) && | ||
197 | (ntohl(ip) & 0xff000000) == 0x7f000000) | ||
198 | i = 0; | ||
199 | |||
200 | DEBUGP | ||
201 | ("ip_nat_ras: set signal address " | ||
202 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
203 | NIPQUAD(ip), port, | ||
204 | NIPQUAD(ct->tuplehash[!dir].tuple.dst. | ||
205 | ip), info->sig_port[!dir]); | ||
206 | return set_h225_addr(pskb, data, 0, &addr[i], | ||
207 | ct->tuplehash[!dir]. | ||
208 | tuple.dst.ip, | ||
209 | info->sig_port[!dir]); | ||
210 | } else if (ip == ct->tuplehash[dir].tuple.dst.ip && | ||
211 | port == info->sig_port[dir]) { | ||
212 | /* GK->GW */ | ||
213 | DEBUGP | ||
214 | ("ip_nat_ras: set signal address " | ||
215 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
216 | NIPQUAD(ip), port, | ||
217 | NIPQUAD(ct->tuplehash[!dir].tuple.src. | ||
218 | ip), info->sig_port[!dir]); | ||
219 | return set_h225_addr(pskb, data, 0, &addr[i], | ||
220 | ct->tuplehash[!dir]. | ||
221 | tuple.src.ip, | ||
222 | info->sig_port[!dir]); | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | /****************************************************************************/ | ||
231 | static int set_ras_addr(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
232 | enum ip_conntrack_info ctinfo, | ||
233 | unsigned char **data, | ||
234 | TransportAddress * addr, int count) | ||
235 | { | ||
236 | int dir = CTINFO2DIR(ctinfo); | ||
237 | int i; | ||
238 | u_int32_t ip; | ||
239 | u_int16_t port; | ||
240 | |||
241 | for (i = 0; i < count; i++) { | ||
242 | if (get_h225_addr(*data, &addr[i], &ip, &port) && | ||
243 | ip == ct->tuplehash[dir].tuple.src.ip && | ||
244 | port == ntohs(ct->tuplehash[dir].tuple.src.u.udp.port)) { | ||
245 | DEBUGP("ip_nat_ras: set rasAddress " | ||
246 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
247 | NIPQUAD(ip), port, | ||
248 | NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip), | ||
249 | ntohs(ct->tuplehash[!dir].tuple.dst.u.udp. | ||
250 | port)); | ||
251 | return set_h225_addr(pskb, data, 0, &addr[i], | ||
252 | ct->tuplehash[!dir].tuple.dst.ip, | ||
253 | ntohs(ct->tuplehash[!dir].tuple. | ||
254 | dst.u.udp.port)); | ||
255 | } | ||
256 | } | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | /****************************************************************************/ | ||
262 | static int nat_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
263 | enum ip_conntrack_info ctinfo, | ||
264 | unsigned char **data, int dataoff, | ||
265 | H245_TransportAddress * addr, | ||
266 | u_int16_t port, u_int16_t rtp_port, | ||
267 | struct ip_conntrack_expect *rtp_exp, | ||
268 | struct ip_conntrack_expect *rtcp_exp) | ||
269 | { | ||
270 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
271 | int dir = CTINFO2DIR(ctinfo); | ||
272 | int i; | ||
273 | u_int16_t nated_port; | ||
274 | |||
275 | /* Set expectations for NAT */ | ||
276 | rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; | ||
277 | rtp_exp->expectfn = ip_nat_follow_master; | ||
278 | rtp_exp->dir = !dir; | ||
279 | rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; | ||
280 | rtcp_exp->expectfn = ip_nat_follow_master; | ||
281 | rtcp_exp->dir = !dir; | ||
282 | |||
283 | /* Lookup existing expects */ | ||
284 | for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) { | ||
285 | if (info->rtp_port[i][dir] == rtp_port) { | ||
286 | /* Expected */ | ||
287 | |||
288 | /* Use allocated ports first. This will refresh | ||
289 | * the expects */ | ||
290 | rtp_exp->tuple.dst.u.udp.port = | ||
291 | htons(info->rtp_port[i][dir]); | ||
292 | rtcp_exp->tuple.dst.u.udp.port = | ||
293 | htons(info->rtp_port[i][dir] + 1); | ||
294 | break; | ||
295 | } else if (info->rtp_port[i][dir] == 0) { | ||
296 | /* Not expected */ | ||
297 | break; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | /* Run out of expectations */ | ||
302 | if (i >= H323_RTP_CHANNEL_MAX) { | ||
303 | if (net_ratelimit()) | ||
304 | printk("ip_nat_h323: out of expectations\n"); | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | /* Try to get a pair of ports. */ | ||
309 | for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port); | ||
310 | nated_port != 0; nated_port += 2) { | ||
311 | rtp_exp->tuple.dst.u.udp.port = htons(nated_port); | ||
312 | if (ip_conntrack_expect_related(rtp_exp) == 0) { | ||
313 | rtcp_exp->tuple.dst.u.udp.port = | ||
314 | htons(nated_port + 1); | ||
315 | if (ip_conntrack_expect_related(rtcp_exp) == 0) | ||
316 | break; | ||
317 | ip_conntrack_unexpect_related(rtp_exp); | ||
318 | } | ||
319 | } | ||
320 | |||
321 | if (nated_port == 0) { /* No port available */ | ||
322 | if (net_ratelimit()) | ||
323 | printk("ip_nat_h323: out of RTP ports\n"); | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | /* Modify signal */ | ||
328 | if (set_h245_addr(pskb, data, dataoff, addr, | ||
329 | ct->tuplehash[!dir].tuple.dst.ip, | ||
330 | (port & 1) ? nated_port + 1 : nated_port) == 0) { | ||
331 | /* Save ports */ | ||
332 | info->rtp_port[i][dir] = rtp_port; | ||
333 | info->rtp_port[i][!dir] = nated_port; | ||
334 | } else { | ||
335 | ip_conntrack_unexpect_related(rtp_exp); | ||
336 | ip_conntrack_unexpect_related(rtcp_exp); | ||
337 | return -1; | ||
338 | } | ||
339 | |||
340 | /* Success */ | ||
341 | DEBUGP("ip_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
342 | NIPQUAD(rtp_exp->tuple.src.ip), | ||
343 | ntohs(rtp_exp->tuple.src.u.udp.port), | ||
344 | NIPQUAD(rtp_exp->tuple.dst.ip), | ||
345 | ntohs(rtp_exp->tuple.dst.u.udp.port)); | ||
346 | DEBUGP("ip_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
347 | NIPQUAD(rtcp_exp->tuple.src.ip), | ||
348 | ntohs(rtcp_exp->tuple.src.u.udp.port), | ||
349 | NIPQUAD(rtcp_exp->tuple.dst.ip), | ||
350 | ntohs(rtcp_exp->tuple.dst.u.udp.port)); | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | /****************************************************************************/ | ||
356 | static int nat_t120(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
357 | enum ip_conntrack_info ctinfo, | ||
358 | unsigned char **data, int dataoff, | ||
359 | H245_TransportAddress * addr, u_int16_t port, | ||
360 | struct ip_conntrack_expect *exp) | ||
361 | { | ||
362 | int dir = CTINFO2DIR(ctinfo); | ||
363 | u_int16_t nated_port = port; | ||
364 | |||
365 | /* Set expectations for NAT */ | ||
366 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
367 | exp->expectfn = ip_nat_follow_master; | ||
368 | exp->dir = !dir; | ||
369 | |||
370 | /* Try to get same port: if not, try to change it. */ | ||
371 | for (; nated_port != 0; nated_port++) { | ||
372 | exp->tuple.dst.u.tcp.port = htons(nated_port); | ||
373 | if (ip_conntrack_expect_related(exp) == 0) | ||
374 | break; | ||
375 | } | ||
376 | |||
377 | if (nated_port == 0) { /* No port available */ | ||
378 | if (net_ratelimit()) | ||
379 | printk("ip_nat_h323: out of TCP ports\n"); | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | /* Modify signal */ | ||
384 | if (set_h245_addr(pskb, data, dataoff, addr, | ||
385 | ct->tuplehash[!dir].tuple.dst.ip, nated_port) < 0) { | ||
386 | ip_conntrack_unexpect_related(exp); | ||
387 | return -1; | ||
388 | } | ||
389 | |||
390 | DEBUGP("ip_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
391 | NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), | ||
392 | NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | /**************************************************************************** | ||
398 | * This conntrack expect function replaces ip_conntrack_h245_expect() | ||
399 | * which was set by ip_conntrack_helper_h323.c. It calls both | ||
400 | * ip_nat_follow_master() and ip_conntrack_h245_expect() | ||
401 | ****************************************************************************/ | ||
402 | static void ip_nat_h245_expect(struct ip_conntrack *new, | ||
403 | struct ip_conntrack_expect *this) | ||
404 | { | ||
405 | ip_nat_follow_master(new, this); | ||
406 | ip_conntrack_h245_expect(new, this); | ||
407 | } | ||
408 | |||
409 | /****************************************************************************/ | ||
410 | static int nat_h245(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
411 | enum ip_conntrack_info ctinfo, | ||
412 | unsigned char **data, int dataoff, | ||
413 | TransportAddress * addr, u_int16_t port, | ||
414 | struct ip_conntrack_expect *exp) | ||
415 | { | ||
416 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
417 | int dir = CTINFO2DIR(ctinfo); | ||
418 | u_int16_t nated_port = port; | ||
419 | |||
420 | /* Set expectations for NAT */ | ||
421 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
422 | exp->expectfn = ip_nat_h245_expect; | ||
423 | exp->dir = !dir; | ||
424 | |||
425 | /* Check existing expects */ | ||
426 | if (info->sig_port[dir] == port) | ||
427 | nated_port = info->sig_port[!dir]; | ||
428 | |||
429 | /* Try to get same port: if not, try to change it. */ | ||
430 | for (; nated_port != 0; nated_port++) { | ||
431 | exp->tuple.dst.u.tcp.port = htons(nated_port); | ||
432 | if (ip_conntrack_expect_related(exp) == 0) | ||
433 | break; | ||
434 | } | ||
435 | |||
436 | if (nated_port == 0) { /* No port available */ | ||
437 | if (net_ratelimit()) | ||
438 | printk("ip_nat_q931: out of TCP ports\n"); | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | /* Modify signal */ | ||
443 | if (set_h225_addr(pskb, data, dataoff, addr, | ||
444 | ct->tuplehash[!dir].tuple.dst.ip, | ||
445 | nated_port) == 0) { | ||
446 | /* Save ports */ | ||
447 | info->sig_port[dir] = port; | ||
448 | info->sig_port[!dir] = nated_port; | ||
449 | } else { | ||
450 | ip_conntrack_unexpect_related(exp); | ||
451 | return -1; | ||
452 | } | ||
453 | |||
454 | DEBUGP("ip_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
455 | NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), | ||
456 | NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); | ||
457 | |||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | /**************************************************************************** | ||
462 | * This conntrack expect function replaces ip_conntrack_q931_expect() | ||
463 | * which was set by ip_conntrack_helper_h323.c. | ||
464 | ****************************************************************************/ | ||
465 | static void ip_nat_q931_expect(struct ip_conntrack *new, | ||
466 | struct ip_conntrack_expect *this) | ||
467 | { | ||
468 | struct ip_nat_range range; | ||
469 | |||
470 | if (this->tuple.src.ip != 0) { /* Only accept calls from GK */ | ||
471 | ip_nat_follow_master(new, this); | ||
472 | goto out; | ||
473 | } | ||
474 | |||
475 | /* This must be a fresh one. */ | ||
476 | BUG_ON(new->status & IPS_NAT_DONE_MASK); | ||
477 | |||
478 | /* Change src to where master sends to */ | ||
479 | range.flags = IP_NAT_RANGE_MAP_IPS; | ||
480 | range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.ip; | ||
481 | |||
482 | /* hook doesn't matter, but it has to do source manip */ | ||
483 | ip_nat_setup_info(new, &range, NF_IP_POST_ROUTING); | ||
484 | |||
485 | /* For DST manip, map port here to where it's expected. */ | ||
486 | range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); | ||
487 | range.min = range.max = this->saved_proto; | ||
488 | range.min_ip = range.max_ip = | ||
489 | new->master->tuplehash[!this->dir].tuple.src.ip; | ||
490 | |||
491 | /* hook doesn't matter, but it has to do destination manip */ | ||
492 | ip_nat_setup_info(new, &range, NF_IP_PRE_ROUTING); | ||
493 | |||
494 | out: | ||
495 | ip_conntrack_q931_expect(new, this); | ||
496 | } | ||
497 | |||
498 | /****************************************************************************/ | ||
499 | static int nat_q931(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
500 | enum ip_conntrack_info ctinfo, | ||
501 | unsigned char **data, TransportAddress * addr, int idx, | ||
502 | u_int16_t port, struct ip_conntrack_expect *exp) | ||
503 | { | ||
504 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
505 | int dir = CTINFO2DIR(ctinfo); | ||
506 | u_int16_t nated_port = port; | ||
507 | u_int32_t ip; | ||
508 | |||
509 | /* Set expectations for NAT */ | ||
510 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
511 | exp->expectfn = ip_nat_q931_expect; | ||
512 | exp->dir = !dir; | ||
513 | |||
514 | /* Check existing expects */ | ||
515 | if (info->sig_port[dir] == port) | ||
516 | nated_port = info->sig_port[!dir]; | ||
517 | |||
518 | /* Try to get same port: if not, try to change it. */ | ||
519 | for (; nated_port != 0; nated_port++) { | ||
520 | exp->tuple.dst.u.tcp.port = htons(nated_port); | ||
521 | if (ip_conntrack_expect_related(exp) == 0) | ||
522 | break; | ||
523 | } | ||
524 | |||
525 | if (nated_port == 0) { /* No port available */ | ||
526 | if (net_ratelimit()) | ||
527 | printk("ip_nat_ras: out of TCP ports\n"); | ||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | /* Modify signal */ | ||
532 | if (set_h225_addr(pskb, data, 0, &addr[idx], | ||
533 | ct->tuplehash[!dir].tuple.dst.ip, | ||
534 | nated_port) == 0) { | ||
535 | /* Save ports */ | ||
536 | info->sig_port[dir] = port; | ||
537 | info->sig_port[!dir] = nated_port; | ||
538 | |||
539 | /* Fix for Gnomemeeting */ | ||
540 | if (idx > 0 && | ||
541 | get_h225_addr(*data, &addr[0], &ip, &port) && | ||
542 | (ntohl(ip) & 0xff000000) == 0x7f000000) { | ||
543 | set_h225_addr_hook(pskb, data, 0, &addr[0], | ||
544 | ct->tuplehash[!dir].tuple.dst.ip, | ||
545 | info->sig_port[!dir]); | ||
546 | } | ||
547 | } else { | ||
548 | ip_conntrack_unexpect_related(exp); | ||
549 | return -1; | ||
550 | } | ||
551 | |||
552 | /* Success */ | ||
553 | DEBUGP("ip_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
554 | NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), | ||
555 | NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | /****************************************************************************/ | ||
561 | static int __init init(void) | ||
562 | { | ||
563 | BUG_ON(set_h245_addr_hook != NULL); | ||
564 | BUG_ON(set_h225_addr_hook != NULL); | ||
565 | BUG_ON(set_sig_addr_hook != NULL); | ||
566 | BUG_ON(set_ras_addr_hook != NULL); | ||
567 | BUG_ON(nat_rtp_rtcp_hook != NULL); | ||
568 | BUG_ON(nat_t120_hook != NULL); | ||
569 | BUG_ON(nat_h245_hook != NULL); | ||
570 | BUG_ON(nat_q931_hook != NULL); | ||
571 | |||
572 | set_h245_addr_hook = set_h245_addr; | ||
573 | set_h225_addr_hook = set_h225_addr; | ||
574 | set_sig_addr_hook = set_sig_addr; | ||
575 | set_ras_addr_hook = set_ras_addr; | ||
576 | nat_rtp_rtcp_hook = nat_rtp_rtcp; | ||
577 | nat_t120_hook = nat_t120; | ||
578 | nat_h245_hook = nat_h245; | ||
579 | nat_q931_hook = nat_q931; | ||
580 | |||
581 | DEBUGP("ip_nat_h323: init success\n"); | ||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | /****************************************************************************/ | ||
586 | static void __exit fini(void) | ||
587 | { | ||
588 | set_h245_addr_hook = NULL; | ||
589 | set_h225_addr_hook = NULL; | ||
590 | set_sig_addr_hook = NULL; | ||
591 | set_ras_addr_hook = NULL; | ||
592 | nat_rtp_rtcp_hook = NULL; | ||
593 | nat_t120_hook = NULL; | ||
594 | nat_h245_hook = NULL; | ||
595 | nat_q931_hook = NULL; | ||
596 | synchronize_net(); | ||
597 | } | ||
598 | |||
599 | /****************************************************************************/ | ||
600 | module_init(init); | ||
601 | module_exit(fini); | ||
602 | |||
603 | MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>"); | ||
604 | MODULE_DESCRIPTION("H.323 NAT helper"); | ||
605 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c index ac004895781a..b9c016c063b8 100644 --- a/net/ipv4/netfilter/ip_nat_helper_pptp.c +++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c | |||
@@ -52,6 +52,8 @@ | |||
52 | 52 | ||
53 | #define IP_NAT_PPTP_VERSION "3.0" | 53 | #define IP_NAT_PPTP_VERSION "3.0" |
54 | 54 | ||
55 | #define REQ_CID(req, off) (*(u_int16_t *)((char *)(req) + (off))) | ||
56 | |||
55 | MODULE_LICENSE("GPL"); | 57 | MODULE_LICENSE("GPL"); |
56 | MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); | 58 | MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); |
57 | MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); | 59 | MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); |
@@ -198,7 +200,7 @@ pptp_outbound_pkt(struct sk_buff **pskb, | |||
198 | /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass | 200 | /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass |
199 | * down to here */ | 201 | * down to here */ |
200 | DEBUGP("altering call id from 0x%04x to 0x%04x\n", | 202 | DEBUGP("altering call id from 0x%04x to 0x%04x\n", |
201 | ntohs(*(u_int16_t *)pptpReq + cid_off), ntohs(new_callid)); | 203 | ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid)); |
202 | 204 | ||
203 | /* mangle packet */ | 205 | /* mangle packet */ |
204 | if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, | 206 | if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, |
@@ -342,7 +344,7 @@ pptp_inbound_pkt(struct sk_buff **pskb, | |||
342 | 344 | ||
343 | /* mangle packet */ | 345 | /* mangle packet */ |
344 | DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", | 346 | DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", |
345 | ntohs(*(u_int16_t *)pptpReq + pcid_off), ntohs(new_pcid)); | 347 | ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid)); |
346 | 348 | ||
347 | if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, | 349 | if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, |
348 | pcid_off + sizeof(struct pptp_pkt_hdr) + | 350 | pcid_off + sizeof(struct pptp_pkt_hdr) + |
@@ -353,7 +355,7 @@ pptp_inbound_pkt(struct sk_buff **pskb, | |||
353 | 355 | ||
354 | if (new_cid) { | 356 | if (new_cid) { |
355 | DEBUGP("altering call id from 0x%04x to 0x%04x\n", | 357 | DEBUGP("altering call id from 0x%04x to 0x%04x\n", |
356 | ntohs(*(u_int16_t *)pptpReq + cid_off), ntohs(new_cid)); | 358 | ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_cid)); |
357 | if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, | 359 | if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, |
358 | cid_off + sizeof(struct pptp_pkt_hdr) + | 360 | cid_off + sizeof(struct pptp_pkt_hdr) + |
359 | sizeof(struct PptpControlHeader), | 361 | sizeof(struct PptpControlHeader), |
diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c index 1de86282d232..efba8c4e42e0 100644 --- a/net/ipv4/netfilter/ip_nat_rule.c +++ b/net/ipv4/netfilter/ip_nat_rule.c | |||
@@ -103,6 +103,7 @@ static unsigned int ipt_snat_target(struct sk_buff **pskb, | |||
103 | const struct net_device *in, | 103 | const struct net_device *in, |
104 | const struct net_device *out, | 104 | const struct net_device *out, |
105 | unsigned int hooknum, | 105 | unsigned int hooknum, |
106 | const struct ipt_target *target, | ||
106 | const void *targinfo, | 107 | const void *targinfo, |
107 | void *userinfo) | 108 | void *userinfo) |
108 | { | 109 | { |
@@ -145,6 +146,7 @@ static unsigned int ipt_dnat_target(struct sk_buff **pskb, | |||
145 | const struct net_device *in, | 146 | const struct net_device *in, |
146 | const struct net_device *out, | 147 | const struct net_device *out, |
147 | unsigned int hooknum, | 148 | unsigned int hooknum, |
149 | const struct ipt_target *target, | ||
148 | const void *targinfo, | 150 | const void *targinfo, |
149 | void *userinfo) | 151 | void *userinfo) |
150 | { | 152 | { |
@@ -170,6 +172,7 @@ static unsigned int ipt_dnat_target(struct sk_buff **pskb, | |||
170 | 172 | ||
171 | static int ipt_snat_checkentry(const char *tablename, | 173 | static int ipt_snat_checkentry(const char *tablename, |
172 | const void *entry, | 174 | const void *entry, |
175 | const struct ipt_target *target, | ||
173 | void *targinfo, | 176 | void *targinfo, |
174 | unsigned int targinfosize, | 177 | unsigned int targinfosize, |
175 | unsigned int hook_mask) | 178 | unsigned int hook_mask) |
@@ -181,28 +184,12 @@ static int ipt_snat_checkentry(const char *tablename, | |||
181 | printk("SNAT: multiple ranges no longer supported\n"); | 184 | printk("SNAT: multiple ranges no longer supported\n"); |
182 | return 0; | 185 | return 0; |
183 | } | 186 | } |
184 | |||
185 | if (targinfosize != IPT_ALIGN(sizeof(struct ip_nat_multi_range_compat))) { | ||
186 | DEBUGP("SNAT: Target size %u wrong for %u ranges\n", | ||
187 | targinfosize, mr->rangesize); | ||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | /* Only allow these for NAT. */ | ||
192 | if (strcmp(tablename, "nat") != 0) { | ||
193 | DEBUGP("SNAT: wrong table %s\n", tablename); | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) { | ||
198 | DEBUGP("SNAT: hook mask 0x%x bad\n", hook_mask); | ||
199 | return 0; | ||
200 | } | ||
201 | return 1; | 187 | return 1; |
202 | } | 188 | } |
203 | 189 | ||
204 | static int ipt_dnat_checkentry(const char *tablename, | 190 | static int ipt_dnat_checkentry(const char *tablename, |
205 | const void *entry, | 191 | const void *entry, |
192 | const struct ipt_target *target, | ||
206 | void *targinfo, | 193 | void *targinfo, |
207 | unsigned int targinfosize, | 194 | unsigned int targinfosize, |
208 | unsigned int hook_mask) | 195 | unsigned int hook_mask) |
@@ -214,24 +201,6 @@ static int ipt_dnat_checkentry(const char *tablename, | |||
214 | printk("DNAT: multiple ranges no longer supported\n"); | 201 | printk("DNAT: multiple ranges no longer supported\n"); |
215 | return 0; | 202 | return 0; |
216 | } | 203 | } |
217 | |||
218 | if (targinfosize != IPT_ALIGN(sizeof(struct ip_nat_multi_range_compat))) { | ||
219 | DEBUGP("DNAT: Target size %u wrong for %u ranges\n", | ||
220 | targinfosize, mr->rangesize); | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | /* Only allow these for NAT. */ | ||
225 | if (strcmp(tablename, "nat") != 0) { | ||
226 | DEBUGP("DNAT: wrong table %s\n", tablename); | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))) { | ||
231 | DEBUGP("DNAT: hook mask 0x%x bad\n", hook_mask); | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | return 1; | 204 | return 1; |
236 | } | 205 | } |
237 | 206 | ||
@@ -299,12 +268,18 @@ int ip_nat_rule_find(struct sk_buff **pskb, | |||
299 | static struct ipt_target ipt_snat_reg = { | 268 | static struct ipt_target ipt_snat_reg = { |
300 | .name = "SNAT", | 269 | .name = "SNAT", |
301 | .target = ipt_snat_target, | 270 | .target = ipt_snat_target, |
271 | .targetsize = sizeof(struct ip_nat_multi_range_compat), | ||
272 | .table = "nat", | ||
273 | .hooks = 1 << NF_IP_POST_ROUTING, | ||
302 | .checkentry = ipt_snat_checkentry, | 274 | .checkentry = ipt_snat_checkentry, |
303 | }; | 275 | }; |
304 | 276 | ||
305 | static struct ipt_target ipt_dnat_reg = { | 277 | static struct ipt_target ipt_dnat_reg = { |
306 | .name = "DNAT", | 278 | .name = "DNAT", |
307 | .target = ipt_dnat_target, | 279 | .target = ipt_dnat_target, |
280 | .targetsize = sizeof(struct ip_nat_multi_range_compat), | ||
281 | .table = "nat", | ||
282 | .hooks = 1 << NF_IP_PRE_ROUTING, | ||
308 | .checkentry = ipt_dnat_checkentry, | 283 | .checkentry = ipt_dnat_checkentry, |
309 | }; | 284 | }; |
310 | 285 | ||
diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c index 4f95d477805c..f029da2a60ee 100644 --- a/net/ipv4/netfilter/ip_nat_snmp_basic.c +++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c | |||
@@ -250,6 +250,7 @@ static unsigned char asn1_header_decode(struct asn1_ctx *ctx, | |||
250 | if (!asn1_id_decode(ctx, cls, con, tag)) | 250 | if (!asn1_id_decode(ctx, cls, con, tag)) |
251 | return 0; | 251 | return 0; |
252 | 252 | ||
253 | def = len = 0; | ||
253 | if (!asn1_length_decode(ctx, &def, &len)) | 254 | if (!asn1_length_decode(ctx, &def, &len)) |
254 | return 0; | 255 | return 0; |
255 | 256 | ||
@@ -669,7 +670,7 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx, | |||
669 | unsigned char *eoc, *end, *p; | 670 | unsigned char *eoc, *end, *p; |
670 | unsigned long *lp, *id; | 671 | unsigned long *lp, *id; |
671 | unsigned long ul; | 672 | unsigned long ul; |
672 | long l; | 673 | long l; |
673 | 674 | ||
674 | *obj = NULL; | 675 | *obj = NULL; |
675 | id = NULL; | 676 | id = NULL; |
@@ -699,11 +700,13 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx, | |||
699 | return 0; | 700 | return 0; |
700 | } | 701 | } |
701 | 702 | ||
703 | type = 0; | ||
702 | if (!snmp_tag_cls2syntax(tag, cls, &type)) { | 704 | if (!snmp_tag_cls2syntax(tag, cls, &type)) { |
703 | kfree(id); | 705 | kfree(id); |
704 | return 0; | 706 | return 0; |
705 | } | 707 | } |
706 | 708 | ||
709 | l = 0; | ||
707 | switch (type) { | 710 | switch (type) { |
708 | case SNMP_INTEGER: | 711 | case SNMP_INTEGER: |
709 | len = sizeof(long); | 712 | len = sizeof(long); |
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 08f80e2ea2aa..1655866c55b9 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/sysctl.h> | 35 | #include <linux/sysctl.h> |
36 | #include <linux/proc_fs.h> | 36 | #include <linux/proc_fs.h> |
37 | #include <linux/security.h> | 37 | #include <linux/security.h> |
38 | #include <linux/mutex.h> | ||
38 | #include <net/sock.h> | 39 | #include <net/sock.h> |
39 | #include <net/route.h> | 40 | #include <net/route.h> |
40 | 41 | ||
@@ -61,7 +62,7 @@ static unsigned int queue_dropped = 0; | |||
61 | static unsigned int queue_user_dropped = 0; | 62 | static unsigned int queue_user_dropped = 0; |
62 | static struct sock *ipqnl; | 63 | static struct sock *ipqnl; |
63 | static LIST_HEAD(queue_list); | 64 | static LIST_HEAD(queue_list); |
64 | static DECLARE_MUTEX(ipqnl_sem); | 65 | static DEFINE_MUTEX(ipqnl_mutex); |
65 | 66 | ||
66 | static void | 67 | static void |
67 | ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict) | 68 | ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict) |
@@ -539,7 +540,7 @@ ipq_rcv_sk(struct sock *sk, int len) | |||
539 | struct sk_buff *skb; | 540 | struct sk_buff *skb; |
540 | unsigned int qlen; | 541 | unsigned int qlen; |
541 | 542 | ||
542 | down(&ipqnl_sem); | 543 | mutex_lock(&ipqnl_mutex); |
543 | 544 | ||
544 | for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { | 545 | for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { |
545 | skb = skb_dequeue(&sk->sk_receive_queue); | 546 | skb = skb_dequeue(&sk->sk_receive_queue); |
@@ -547,7 +548,7 @@ ipq_rcv_sk(struct sock *sk, int len) | |||
547 | kfree_skb(skb); | 548 | kfree_skb(skb); |
548 | } | 549 | } |
549 | 550 | ||
550 | up(&ipqnl_sem); | 551 | mutex_unlock(&ipqnl_mutex); |
551 | } | 552 | } |
552 | 553 | ||
553 | static int | 554 | static int |
@@ -708,8 +709,8 @@ cleanup_sysctl: | |||
708 | 709 | ||
709 | cleanup_ipqnl: | 710 | cleanup_ipqnl: |
710 | sock_release(ipqnl->sk_socket); | 711 | sock_release(ipqnl->sk_socket); |
711 | down(&ipqnl_sem); | 712 | mutex_lock(&ipqnl_mutex); |
712 | up(&ipqnl_sem); | 713 | mutex_unlock(&ipqnl_mutex); |
713 | 714 | ||
714 | cleanup_netlink_notifier: | 715 | cleanup_netlink_notifier: |
715 | netlink_unregister_notifier(&ipq_nl_notifier); | 716 | netlink_unregister_notifier(&ipq_nl_notifier); |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 16f47c675fef..a7b194c4d79d 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -25,7 +25,7 @@ | |||
25 | #include <linux/icmp.h> | 25 | #include <linux/icmp.h> |
26 | #include <net/ip.h> | 26 | #include <net/ip.h> |
27 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
28 | #include <asm/semaphore.h> | 28 | #include <linux/mutex.h> |
29 | #include <linux/proc_fs.h> | 29 | #include <linux/proc_fs.h> |
30 | #include <linux/err.h> | 30 | #include <linux/err.h> |
31 | #include <linux/cpumask.h> | 31 | #include <linux/cpumask.h> |
@@ -179,6 +179,7 @@ ipt_error(struct sk_buff **pskb, | |||
179 | const struct net_device *in, | 179 | const struct net_device *in, |
180 | const struct net_device *out, | 180 | const struct net_device *out, |
181 | unsigned int hooknum, | 181 | unsigned int hooknum, |
182 | const struct xt_target *target, | ||
182 | const void *targinfo, | 183 | const void *targinfo, |
183 | void *userinfo) | 184 | void *userinfo) |
184 | { | 185 | { |
@@ -197,8 +198,8 @@ int do_match(struct ipt_entry_match *m, | |||
197 | int *hotdrop) | 198 | int *hotdrop) |
198 | { | 199 | { |
199 | /* Stop iteration if it doesn't match */ | 200 | /* Stop iteration if it doesn't match */ |
200 | if (!m->u.kernel.match->match(skb, in, out, m->data, offset, | 201 | if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data, |
201 | skb->nh.iph->ihl*4, hotdrop)) | 202 | offset, skb->nh.iph->ihl*4, hotdrop)) |
202 | return 1; | 203 | return 1; |
203 | else | 204 | else |
204 | return 0; | 205 | return 0; |
@@ -305,6 +306,7 @@ ipt_do_table(struct sk_buff **pskb, | |||
305 | verdict = t->u.kernel.target->target(pskb, | 306 | verdict = t->u.kernel.target->target(pskb, |
306 | in, out, | 307 | in, out, |
307 | hook, | 308 | hook, |
309 | t->u.kernel.target, | ||
308 | t->data, | 310 | t->data, |
309 | userdata); | 311 | userdata); |
310 | 312 | ||
@@ -464,7 +466,7 @@ cleanup_match(struct ipt_entry_match *m, unsigned int *i) | |||
464 | return 1; | 466 | return 1; |
465 | 467 | ||
466 | if (m->u.kernel.match->destroy) | 468 | if (m->u.kernel.match->destroy) |
467 | m->u.kernel.match->destroy(m->data, | 469 | m->u.kernel.match->destroy(m->u.kernel.match, m->data, |
468 | m->u.match_size - sizeof(*m)); | 470 | m->u.match_size - sizeof(*m)); |
469 | module_put(m->u.kernel.match->me); | 471 | module_put(m->u.kernel.match->me); |
470 | return 0; | 472 | return 0; |
@@ -477,21 +479,12 @@ standard_check(const struct ipt_entry_target *t, | |||
477 | struct ipt_standard_target *targ = (void *)t; | 479 | struct ipt_standard_target *targ = (void *)t; |
478 | 480 | ||
479 | /* Check standard info. */ | 481 | /* Check standard info. */ |
480 | if (t->u.target_size | ||
481 | != IPT_ALIGN(sizeof(struct ipt_standard_target))) { | ||
482 | duprintf("standard_check: target size %u != %u\n", | ||
483 | t->u.target_size, | ||
484 | IPT_ALIGN(sizeof(struct ipt_standard_target))); | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | if (targ->verdict >= 0 | 482 | if (targ->verdict >= 0 |
489 | && targ->verdict > max_offset - sizeof(struct ipt_entry)) { | 483 | && targ->verdict > max_offset - sizeof(struct ipt_entry)) { |
490 | duprintf("ipt_standard_check: bad verdict (%i)\n", | 484 | duprintf("ipt_standard_check: bad verdict (%i)\n", |
491 | targ->verdict); | 485 | targ->verdict); |
492 | return 0; | 486 | return 0; |
493 | } | 487 | } |
494 | |||
495 | if (targ->verdict < -NF_MAX_VERDICT - 1) { | 488 | if (targ->verdict < -NF_MAX_VERDICT - 1) { |
496 | duprintf("ipt_standard_check: bad negative verdict (%i)\n", | 489 | duprintf("ipt_standard_check: bad negative verdict (%i)\n", |
497 | targ->verdict); | 490 | targ->verdict); |
@@ -508,6 +501,7 @@ check_match(struct ipt_entry_match *m, | |||
508 | unsigned int *i) | 501 | unsigned int *i) |
509 | { | 502 | { |
510 | struct ipt_match *match; | 503 | struct ipt_match *match; |
504 | int ret; | ||
511 | 505 | ||
512 | match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name, | 506 | match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name, |
513 | m->u.user.revision), | 507 | m->u.user.revision), |
@@ -518,18 +512,27 @@ check_match(struct ipt_entry_match *m, | |||
518 | } | 512 | } |
519 | m->u.kernel.match = match; | 513 | m->u.kernel.match = match; |
520 | 514 | ||
515 | ret = xt_check_match(match, AF_INET, m->u.match_size - sizeof(*m), | ||
516 | name, hookmask, ip->proto, | ||
517 | ip->invflags & IPT_INV_PROTO); | ||
518 | if (ret) | ||
519 | goto err; | ||
520 | |||
521 | if (m->u.kernel.match->checkentry | 521 | if (m->u.kernel.match->checkentry |
522 | && !m->u.kernel.match->checkentry(name, ip, m->data, | 522 | && !m->u.kernel.match->checkentry(name, ip, match, m->data, |
523 | m->u.match_size - sizeof(*m), | 523 | m->u.match_size - sizeof(*m), |
524 | hookmask)) { | 524 | hookmask)) { |
525 | module_put(m->u.kernel.match->me); | ||
526 | duprintf("ip_tables: check failed for `%s'.\n", | 525 | duprintf("ip_tables: check failed for `%s'.\n", |
527 | m->u.kernel.match->name); | 526 | m->u.kernel.match->name); |
528 | return -EINVAL; | 527 | ret = -EINVAL; |
528 | goto err; | ||
529 | } | 529 | } |
530 | 530 | ||
531 | (*i)++; | 531 | (*i)++; |
532 | return 0; | 532 | return 0; |
533 | err: | ||
534 | module_put(m->u.kernel.match->me); | ||
535 | return ret; | ||
533 | } | 536 | } |
534 | 537 | ||
535 | static struct ipt_target ipt_standard_target; | 538 | static struct ipt_target ipt_standard_target; |
@@ -565,26 +568,32 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size, | |||
565 | } | 568 | } |
566 | t->u.kernel.target = target; | 569 | t->u.kernel.target = target; |
567 | 570 | ||
571 | ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t), | ||
572 | name, e->comefrom, e->ip.proto, | ||
573 | e->ip.invflags & IPT_INV_PROTO); | ||
574 | if (ret) | ||
575 | goto err; | ||
576 | |||
568 | if (t->u.kernel.target == &ipt_standard_target) { | 577 | if (t->u.kernel.target == &ipt_standard_target) { |
569 | if (!standard_check(t, size)) { | 578 | if (!standard_check(t, size)) { |
570 | ret = -EINVAL; | 579 | ret = -EINVAL; |
571 | goto cleanup_matches; | 580 | goto cleanup_matches; |
572 | } | 581 | } |
573 | } else if (t->u.kernel.target->checkentry | 582 | } else if (t->u.kernel.target->checkentry |
574 | && !t->u.kernel.target->checkentry(name, e, t->data, | 583 | && !t->u.kernel.target->checkentry(name, e, target, t->data, |
575 | t->u.target_size | 584 | t->u.target_size |
576 | - sizeof(*t), | 585 | - sizeof(*t), |
577 | e->comefrom)) { | 586 | e->comefrom)) { |
578 | module_put(t->u.kernel.target->me); | ||
579 | duprintf("ip_tables: check failed for `%s'.\n", | 587 | duprintf("ip_tables: check failed for `%s'.\n", |
580 | t->u.kernel.target->name); | 588 | t->u.kernel.target->name); |
581 | ret = -EINVAL; | 589 | ret = -EINVAL; |
582 | goto cleanup_matches; | 590 | goto err; |
583 | } | 591 | } |
584 | 592 | ||
585 | (*i)++; | 593 | (*i)++; |
586 | return 0; | 594 | return 0; |
587 | 595 | err: | |
596 | module_put(t->u.kernel.target->me); | ||
588 | cleanup_matches: | 597 | cleanup_matches: |
589 | IPT_MATCH_ITERATE(e, cleanup_match, &j); | 598 | IPT_MATCH_ITERATE(e, cleanup_match, &j); |
590 | return ret; | 599 | return ret; |
@@ -645,7 +654,7 @@ cleanup_entry(struct ipt_entry *e, unsigned int *i) | |||
645 | IPT_MATCH_ITERATE(e, cleanup_match, NULL); | 654 | IPT_MATCH_ITERATE(e, cleanup_match, NULL); |
646 | t = ipt_get_target(e); | 655 | t = ipt_get_target(e); |
647 | if (t->u.kernel.target->destroy) | 656 | if (t->u.kernel.target->destroy) |
648 | t->u.kernel.target->destroy(t->data, | 657 | t->u.kernel.target->destroy(t->u.kernel.target, t->data, |
649 | t->u.target_size - sizeof(*t)); | 658 | t->u.target_size - sizeof(*t)); |
650 | module_put(t->u.kernel.target->me); | 659 | module_put(t->u.kernel.target->me); |
651 | return 0; | 660 | return 0; |
@@ -1277,6 +1286,7 @@ static int | |||
1277 | icmp_match(const struct sk_buff *skb, | 1286 | icmp_match(const struct sk_buff *skb, |
1278 | const struct net_device *in, | 1287 | const struct net_device *in, |
1279 | const struct net_device *out, | 1288 | const struct net_device *out, |
1289 | const struct xt_match *match, | ||
1280 | const void *matchinfo, | 1290 | const void *matchinfo, |
1281 | int offset, | 1291 | int offset, |
1282 | unsigned int protoff, | 1292 | unsigned int protoff, |
@@ -1310,28 +1320,29 @@ icmp_match(const struct sk_buff *skb, | |||
1310 | static int | 1320 | static int |
1311 | icmp_checkentry(const char *tablename, | 1321 | icmp_checkentry(const char *tablename, |
1312 | const void *info, | 1322 | const void *info, |
1323 | const struct xt_match *match, | ||
1313 | void *matchinfo, | 1324 | void *matchinfo, |
1314 | unsigned int matchsize, | 1325 | unsigned int matchsize, |
1315 | unsigned int hook_mask) | 1326 | unsigned int hook_mask) |
1316 | { | 1327 | { |
1317 | const struct ipt_ip *ip = info; | ||
1318 | const struct ipt_icmp *icmpinfo = matchinfo; | 1328 | const struct ipt_icmp *icmpinfo = matchinfo; |
1319 | 1329 | ||
1320 | /* Must specify proto == ICMP, and no unknown invflags */ | 1330 | /* Must specify no unknown invflags */ |
1321 | return ip->proto == IPPROTO_ICMP | 1331 | return !(icmpinfo->invflags & ~IPT_ICMP_INV); |
1322 | && !(ip->invflags & IPT_INV_PROTO) | ||
1323 | && matchsize == IPT_ALIGN(sizeof(struct ipt_icmp)) | ||
1324 | && !(icmpinfo->invflags & ~IPT_ICMP_INV); | ||
1325 | } | 1332 | } |
1326 | 1333 | ||
1327 | /* The built-in targets: standard (NULL) and error. */ | 1334 | /* The built-in targets: standard (NULL) and error. */ |
1328 | static struct ipt_target ipt_standard_target = { | 1335 | static struct ipt_target ipt_standard_target = { |
1329 | .name = IPT_STANDARD_TARGET, | 1336 | .name = IPT_STANDARD_TARGET, |
1337 | .targetsize = sizeof(int), | ||
1338 | .family = AF_INET, | ||
1330 | }; | 1339 | }; |
1331 | 1340 | ||
1332 | static struct ipt_target ipt_error_target = { | 1341 | static struct ipt_target ipt_error_target = { |
1333 | .name = IPT_ERROR_TARGET, | 1342 | .name = IPT_ERROR_TARGET, |
1334 | .target = ipt_error, | 1343 | .target = ipt_error, |
1344 | .targetsize = IPT_FUNCTION_MAXNAMELEN, | ||
1345 | .family = AF_INET, | ||
1335 | }; | 1346 | }; |
1336 | 1347 | ||
1337 | static struct nf_sockopt_ops ipt_sockopts = { | 1348 | static struct nf_sockopt_ops ipt_sockopts = { |
@@ -1346,8 +1357,11 @@ static struct nf_sockopt_ops ipt_sockopts = { | |||
1346 | 1357 | ||
1347 | static struct ipt_match icmp_matchstruct = { | 1358 | static struct ipt_match icmp_matchstruct = { |
1348 | .name = "icmp", | 1359 | .name = "icmp", |
1349 | .match = &icmp_match, | 1360 | .match = icmp_match, |
1350 | .checkentry = &icmp_checkentry, | 1361 | .matchsize = sizeof(struct ipt_icmp), |
1362 | .proto = IPPROTO_ICMP, | ||
1363 | .family = AF_INET, | ||
1364 | .checkentry = icmp_checkentry, | ||
1351 | }; | 1365 | }; |
1352 | 1366 | ||
1353 | static int __init init(void) | 1367 | static int __init init(void) |
@@ -1357,9 +1371,9 @@ static int __init init(void) | |||
1357 | xt_proto_init(AF_INET); | 1371 | xt_proto_init(AF_INET); |
1358 | 1372 | ||
1359 | /* Noone else will be downing sem now, so we won't sleep */ | 1373 | /* Noone else will be downing sem now, so we won't sleep */ |
1360 | xt_register_target(AF_INET, &ipt_standard_target); | 1374 | xt_register_target(&ipt_standard_target); |
1361 | xt_register_target(AF_INET, &ipt_error_target); | 1375 | xt_register_target(&ipt_error_target); |
1362 | xt_register_match(AF_INET, &icmp_matchstruct); | 1376 | xt_register_match(&icmp_matchstruct); |
1363 | 1377 | ||
1364 | /* Register setsockopt */ | 1378 | /* Register setsockopt */ |
1365 | ret = nf_register_sockopt(&ipt_sockopts); | 1379 | ret = nf_register_sockopt(&ipt_sockopts); |
@@ -1376,9 +1390,9 @@ static void __exit fini(void) | |||
1376 | { | 1390 | { |
1377 | nf_unregister_sockopt(&ipt_sockopts); | 1391 | nf_unregister_sockopt(&ipt_sockopts); |
1378 | 1392 | ||
1379 | xt_unregister_match(AF_INET, &icmp_matchstruct); | 1393 | xt_unregister_match(&icmp_matchstruct); |
1380 | xt_unregister_target(AF_INET, &ipt_error_target); | 1394 | xt_unregister_target(&ipt_error_target); |
1381 | xt_unregister_target(AF_INET, &ipt_standard_target); | 1395 | xt_unregister_target(&ipt_standard_target); |
1382 | 1396 | ||
1383 | xt_proto_fini(AF_INET); | 1397 | xt_proto_fini(AF_INET); |
1384 | } | 1398 | } |
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index d9bc971f03af..61e11edcd6af 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c | |||
@@ -311,6 +311,7 @@ target(struct sk_buff **pskb, | |||
311 | const struct net_device *in, | 311 | const struct net_device *in, |
312 | const struct net_device *out, | 312 | const struct net_device *out, |
313 | unsigned int hooknum, | 313 | unsigned int hooknum, |
314 | const struct xt_target *target, | ||
314 | const void *targinfo, | 315 | const void *targinfo, |
315 | void *userinfo) | 316 | void *userinfo) |
316 | { | 317 | { |
@@ -380,6 +381,7 @@ target(struct sk_buff **pskb, | |||
380 | static int | 381 | static int |
381 | checkentry(const char *tablename, | 382 | checkentry(const char *tablename, |
382 | const void *e_void, | 383 | const void *e_void, |
384 | const struct xt_target *target, | ||
383 | void *targinfo, | 385 | void *targinfo, |
384 | unsigned int targinfosize, | 386 | unsigned int targinfosize, |
385 | unsigned int hook_mask) | 387 | unsigned int hook_mask) |
@@ -389,13 +391,6 @@ checkentry(const char *tablename, | |||
389 | 391 | ||
390 | struct clusterip_config *config; | 392 | struct clusterip_config *config; |
391 | 393 | ||
392 | if (targinfosize != IPT_ALIGN(sizeof(struct ipt_clusterip_tgt_info))) { | ||
393 | printk(KERN_WARNING "CLUSTERIP: targinfosize %u != %Zu\n", | ||
394 | targinfosize, | ||
395 | IPT_ALIGN(sizeof(struct ipt_clusterip_tgt_info))); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP && | 394 | if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP && |
400 | cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT && | 395 | cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT && |
401 | cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT_DPT) { | 396 | cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT_DPT) { |
@@ -465,9 +460,10 @@ checkentry(const char *tablename, | |||
465 | } | 460 | } |
466 | 461 | ||
467 | /* drop reference count of cluster config when rule is deleted */ | 462 | /* drop reference count of cluster config when rule is deleted */ |
468 | static void destroy(void *matchinfo, unsigned int matchinfosize) | 463 | static void destroy(const struct xt_target *target, void *targinfo, |
464 | unsigned int targinfosize) | ||
469 | { | 465 | { |
470 | struct ipt_clusterip_tgt_info *cipinfo = matchinfo; | 466 | struct ipt_clusterip_tgt_info *cipinfo = targinfo; |
471 | 467 | ||
472 | /* if no more entries are referencing the config, remove it | 468 | /* if no more entries are referencing the config, remove it |
473 | * from the list and destroy the proc entry */ | 469 | * from the list and destroy the proc entry */ |
@@ -476,12 +472,13 @@ static void destroy(void *matchinfo, unsigned int matchinfosize) | |||
476 | clusterip_config_put(cipinfo->config); | 472 | clusterip_config_put(cipinfo->config); |
477 | } | 473 | } |
478 | 474 | ||
479 | static struct ipt_target clusterip_tgt = { | 475 | static struct ipt_target clusterip_tgt = { |
480 | .name = "CLUSTERIP", | 476 | .name = "CLUSTERIP", |
481 | .target = &target, | 477 | .target = target, |
482 | .checkentry = &checkentry, | 478 | .targetsize = sizeof(struct ipt_clusterip_tgt_info), |
483 | .destroy = &destroy, | 479 | .checkentry = checkentry, |
484 | .me = THIS_MODULE | 480 | .destroy = destroy, |
481 | .me = THIS_MODULE | ||
485 | }; | 482 | }; |
486 | 483 | ||
487 | 484 | ||
diff --git a/net/ipv4/netfilter/ipt_DSCP.c b/net/ipv4/netfilter/ipt_DSCP.c index 898cdf79ce18..cfb0b90e598a 100644 --- a/net/ipv4/netfilter/ipt_DSCP.c +++ b/net/ipv4/netfilter/ipt_DSCP.c | |||
@@ -29,6 +29,7 @@ target(struct sk_buff **pskb, | |||
29 | const struct net_device *in, | 29 | const struct net_device *in, |
30 | const struct net_device *out, | 30 | const struct net_device *out, |
31 | unsigned int hooknum, | 31 | unsigned int hooknum, |
32 | const struct xt_target *target, | ||
32 | const void *targinfo, | 33 | const void *targinfo, |
33 | void *userinfo) | 34 | void *userinfo) |
34 | { | 35 | { |
@@ -58,35 +59,25 @@ target(struct sk_buff **pskb, | |||
58 | static int | 59 | static int |
59 | checkentry(const char *tablename, | 60 | checkentry(const char *tablename, |
60 | const void *e_void, | 61 | const void *e_void, |
62 | const struct xt_target *target, | ||
61 | void *targinfo, | 63 | void *targinfo, |
62 | unsigned int targinfosize, | 64 | unsigned int targinfosize, |
63 | unsigned int hook_mask) | 65 | unsigned int hook_mask) |
64 | { | 66 | { |
65 | const u_int8_t dscp = ((struct ipt_DSCP_info *)targinfo)->dscp; | 67 | const u_int8_t dscp = ((struct ipt_DSCP_info *)targinfo)->dscp; |
66 | 68 | ||
67 | if (targinfosize != IPT_ALIGN(sizeof(struct ipt_DSCP_info))) { | ||
68 | printk(KERN_WARNING "DSCP: targinfosize %u != %Zu\n", | ||
69 | targinfosize, | ||
70 | IPT_ALIGN(sizeof(struct ipt_DSCP_info))); | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | if (strcmp(tablename, "mangle") != 0) { | ||
75 | printk(KERN_WARNING "DSCP: can only be called from \"mangle\" table, not \"%s\"\n", tablename); | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | if ((dscp > IPT_DSCP_MAX)) { | 69 | if ((dscp > IPT_DSCP_MAX)) { |
80 | printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp); | 70 | printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp); |
81 | return 0; | 71 | return 0; |
82 | } | 72 | } |
83 | |||
84 | return 1; | 73 | return 1; |
85 | } | 74 | } |
86 | 75 | ||
87 | static struct ipt_target ipt_dscp_reg = { | 76 | static struct ipt_target ipt_dscp_reg = { |
88 | .name = "DSCP", | 77 | .name = "DSCP", |
89 | .target = target, | 78 | .target = target, |
79 | .targetsize = sizeof(struct ipt_DSCP_info), | ||
80 | .table = "mangle", | ||
90 | .checkentry = checkentry, | 81 | .checkentry = checkentry, |
91 | .me = THIS_MODULE, | 82 | .me = THIS_MODULE, |
92 | }; | 83 | }; |
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index 706445426a6d..b9b80f90c84e 100644 --- a/net/ipv4/netfilter/ipt_ECN.c +++ b/net/ipv4/netfilter/ipt_ECN.c | |||
@@ -94,6 +94,7 @@ target(struct sk_buff **pskb, | |||
94 | const struct net_device *in, | 94 | const struct net_device *in, |
95 | const struct net_device *out, | 95 | const struct net_device *out, |
96 | unsigned int hooknum, | 96 | unsigned int hooknum, |
97 | const struct xt_target *target, | ||
97 | const void *targinfo, | 98 | const void *targinfo, |
98 | void *userinfo) | 99 | void *userinfo) |
99 | { | 100 | { |
@@ -114,6 +115,7 @@ target(struct sk_buff **pskb, | |||
114 | static int | 115 | static int |
115 | checkentry(const char *tablename, | 116 | checkentry(const char *tablename, |
116 | const void *e_void, | 117 | const void *e_void, |
118 | const struct xt_target *target, | ||
117 | void *targinfo, | 119 | void *targinfo, |
118 | unsigned int targinfosize, | 120 | unsigned int targinfosize, |
119 | unsigned int hook_mask) | 121 | unsigned int hook_mask) |
@@ -121,18 +123,6 @@ checkentry(const char *tablename, | |||
121 | const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo; | 123 | const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo; |
122 | const struct ipt_entry *e = e_void; | 124 | const struct ipt_entry *e = e_void; |
123 | 125 | ||
124 | if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ECN_info))) { | ||
125 | printk(KERN_WARNING "ECN: targinfosize %u != %Zu\n", | ||
126 | targinfosize, | ||
127 | IPT_ALIGN(sizeof(struct ipt_ECN_info))); | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | if (strcmp(tablename, "mangle") != 0) { | ||
132 | printk(KERN_WARNING "ECN: can only be called from \"mangle\" table, not \"%s\"\n", tablename); | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | if (einfo->operation & IPT_ECN_OP_MASK) { | 126 | if (einfo->operation & IPT_ECN_OP_MASK) { |
137 | printk(KERN_WARNING "ECN: unsupported ECN operation %x\n", | 127 | printk(KERN_WARNING "ECN: unsupported ECN operation %x\n", |
138 | einfo->operation); | 128 | einfo->operation); |
@@ -143,20 +133,20 @@ checkentry(const char *tablename, | |||
143 | einfo->ip_ect); | 133 | einfo->ip_ect); |
144 | return 0; | 134 | return 0; |
145 | } | 135 | } |
146 | |||
147 | if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)) | 136 | if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)) |
148 | && (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO))) { | 137 | && (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO))) { |
149 | printk(KERN_WARNING "ECN: cannot use TCP operations on a " | 138 | printk(KERN_WARNING "ECN: cannot use TCP operations on a " |
150 | "non-tcp rule\n"); | 139 | "non-tcp rule\n"); |
151 | return 0; | 140 | return 0; |
152 | } | 141 | } |
153 | |||
154 | return 1; | 142 | return 1; |
155 | } | 143 | } |
156 | 144 | ||
157 | static struct ipt_target ipt_ecn_reg = { | 145 | static struct ipt_target ipt_ecn_reg = { |
158 | .name = "ECN", | 146 | .name = "ECN", |
159 | .target = target, | 147 | .target = target, |
148 | .targetsize = sizeof(struct ipt_ECN_info), | ||
149 | .table = "mangle", | ||
160 | .checkentry = checkentry, | 150 | .checkentry = checkentry, |
161 | .me = THIS_MODULE, | 151 | .me = THIS_MODULE, |
162 | }; | 152 | }; |
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index cc27545ff97f..750d3221b280 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c | |||
@@ -415,6 +415,7 @@ ipt_log_target(struct sk_buff **pskb, | |||
415 | const struct net_device *in, | 415 | const struct net_device *in, |
416 | const struct net_device *out, | 416 | const struct net_device *out, |
417 | unsigned int hooknum, | 417 | unsigned int hooknum, |
418 | const struct xt_target *target, | ||
418 | const void *targinfo, | 419 | const void *targinfo, |
419 | void *userinfo) | 420 | void *userinfo) |
420 | { | 421 | { |
@@ -437,35 +438,29 @@ ipt_log_target(struct sk_buff **pskb, | |||
437 | 438 | ||
438 | static int ipt_log_checkentry(const char *tablename, | 439 | static int ipt_log_checkentry(const char *tablename, |
439 | const void *e, | 440 | const void *e, |
441 | const struct xt_target *target, | ||
440 | void *targinfo, | 442 | void *targinfo, |
441 | unsigned int targinfosize, | 443 | unsigned int targinfosize, |
442 | unsigned int hook_mask) | 444 | unsigned int hook_mask) |
443 | { | 445 | { |
444 | const struct ipt_log_info *loginfo = targinfo; | 446 | const struct ipt_log_info *loginfo = targinfo; |
445 | 447 | ||
446 | if (targinfosize != IPT_ALIGN(sizeof(struct ipt_log_info))) { | ||
447 | DEBUGP("LOG: targinfosize %u != %u\n", | ||
448 | targinfosize, IPT_ALIGN(sizeof(struct ipt_log_info))); | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | if (loginfo->level >= 8) { | 448 | if (loginfo->level >= 8) { |
453 | DEBUGP("LOG: level %u >= 8\n", loginfo->level); | 449 | DEBUGP("LOG: level %u >= 8\n", loginfo->level); |
454 | return 0; | 450 | return 0; |
455 | } | 451 | } |
456 | |||
457 | if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { | 452 | if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { |
458 | DEBUGP("LOG: prefix term %i\n", | 453 | DEBUGP("LOG: prefix term %i\n", |
459 | loginfo->prefix[sizeof(loginfo->prefix)-1]); | 454 | loginfo->prefix[sizeof(loginfo->prefix)-1]); |
460 | return 0; | 455 | return 0; |
461 | } | 456 | } |
462 | |||
463 | return 1; | 457 | return 1; |
464 | } | 458 | } |
465 | 459 | ||
466 | static struct ipt_target ipt_log_reg = { | 460 | static struct ipt_target ipt_log_reg = { |
467 | .name = "LOG", | 461 | .name = "LOG", |
468 | .target = ipt_log_target, | 462 | .target = ipt_log_target, |
463 | .targetsize = sizeof(struct ipt_log_info), | ||
469 | .checkentry = ipt_log_checkentry, | 464 | .checkentry = ipt_log_checkentry, |
470 | .me = THIS_MODULE, | 465 | .me = THIS_MODULE, |
471 | }; | 466 | }; |
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index 12c56d3343ca..e0c321c3bae5 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c | |||
@@ -41,25 +41,13 @@ static DEFINE_RWLOCK(masq_lock); | |||
41 | static int | 41 | static int |
42 | masquerade_check(const char *tablename, | 42 | masquerade_check(const char *tablename, |
43 | const void *e, | 43 | const void *e, |
44 | const struct xt_target *target, | ||
44 | void *targinfo, | 45 | void *targinfo, |
45 | unsigned int targinfosize, | 46 | unsigned int targinfosize, |
46 | unsigned int hook_mask) | 47 | unsigned int hook_mask) |
47 | { | 48 | { |
48 | const struct ip_nat_multi_range_compat *mr = targinfo; | 49 | const struct ip_nat_multi_range_compat *mr = targinfo; |
49 | 50 | ||
50 | if (strcmp(tablename, "nat") != 0) { | ||
51 | DEBUGP("masquerade_check: bad table `%s'.\n", tablename); | ||
52 | return 0; | ||
53 | } | ||
54 | if (targinfosize != IPT_ALIGN(sizeof(*mr))) { | ||
55 | DEBUGP("masquerade_check: size %u != %u.\n", | ||
56 | targinfosize, sizeof(*mr)); | ||
57 | return 0; | ||
58 | } | ||
59 | if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) { | ||
60 | DEBUGP("masquerade_check: bad hooks %x.\n", hook_mask); | ||
61 | return 0; | ||
62 | } | ||
63 | if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) { | 51 | if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) { |
64 | DEBUGP("masquerade_check: bad MAP_IPS.\n"); | 52 | DEBUGP("masquerade_check: bad MAP_IPS.\n"); |
65 | return 0; | 53 | return 0; |
@@ -76,6 +64,7 @@ masquerade_target(struct sk_buff **pskb, | |||
76 | const struct net_device *in, | 64 | const struct net_device *in, |
77 | const struct net_device *out, | 65 | const struct net_device *out, |
78 | unsigned int hooknum, | 66 | unsigned int hooknum, |
67 | const struct xt_target *target, | ||
79 | const void *targinfo, | 68 | const void *targinfo, |
80 | void *userinfo) | 69 | void *userinfo) |
81 | { | 70 | { |
@@ -179,6 +168,9 @@ static struct notifier_block masq_inet_notifier = { | |||
179 | static struct ipt_target masquerade = { | 168 | static struct ipt_target masquerade = { |
180 | .name = "MASQUERADE", | 169 | .name = "MASQUERADE", |
181 | .target = masquerade_target, | 170 | .target = masquerade_target, |
171 | .targetsize = sizeof(struct ip_nat_multi_range_compat), | ||
172 | .table = "nat", | ||
173 | .hooks = 1 << NF_IP_POST_ROUTING, | ||
182 | .checkentry = masquerade_check, | 174 | .checkentry = masquerade_check, |
183 | .me = THIS_MODULE, | 175 | .me = THIS_MODULE, |
184 | }; | 176 | }; |
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c index b074467fe67b..fba181c2a426 100644 --- a/net/ipv4/netfilter/ipt_NETMAP.c +++ b/net/ipv4/netfilter/ipt_NETMAP.c | |||
@@ -32,25 +32,13 @@ MODULE_DESCRIPTION("iptables 1:1 NAT mapping of IP networks target"); | |||
32 | static int | 32 | static int |
33 | check(const char *tablename, | 33 | check(const char *tablename, |
34 | const void *e, | 34 | const void *e, |
35 | const struct xt_target *target, | ||
35 | void *targinfo, | 36 | void *targinfo, |
36 | unsigned int targinfosize, | 37 | unsigned int targinfosize, |
37 | unsigned int hook_mask) | 38 | unsigned int hook_mask) |
38 | { | 39 | { |
39 | const struct ip_nat_multi_range_compat *mr = targinfo; | 40 | const struct ip_nat_multi_range_compat *mr = targinfo; |
40 | 41 | ||
41 | if (strcmp(tablename, "nat") != 0) { | ||
42 | DEBUGP(MODULENAME":check: bad table `%s'.\n", tablename); | ||
43 | return 0; | ||
44 | } | ||
45 | if (targinfosize != IPT_ALIGN(sizeof(*mr))) { | ||
46 | DEBUGP(MODULENAME":check: size %u.\n", targinfosize); | ||
47 | return 0; | ||
48 | } | ||
49 | if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING) | | ||
50 | (1 << NF_IP_LOCAL_OUT))) { | ||
51 | DEBUGP(MODULENAME":check: bad hooks %x.\n", hook_mask); | ||
52 | return 0; | ||
53 | } | ||
54 | if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) { | 42 | if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) { |
55 | DEBUGP(MODULENAME":check: bad MAP_IPS.\n"); | 43 | DEBUGP(MODULENAME":check: bad MAP_IPS.\n"); |
56 | return 0; | 44 | return 0; |
@@ -67,6 +55,7 @@ target(struct sk_buff **pskb, | |||
67 | const struct net_device *in, | 55 | const struct net_device *in, |
68 | const struct net_device *out, | 56 | const struct net_device *out, |
69 | unsigned int hooknum, | 57 | unsigned int hooknum, |
58 | const struct xt_target *target, | ||
70 | const void *targinfo, | 59 | const void *targinfo, |
71 | void *userinfo) | 60 | void *userinfo) |
72 | { | 61 | { |
@@ -101,6 +90,10 @@ target(struct sk_buff **pskb, | |||
101 | static struct ipt_target target_module = { | 90 | static struct ipt_target target_module = { |
102 | .name = MODULENAME, | 91 | .name = MODULENAME, |
103 | .target = target, | 92 | .target = target, |
93 | .targetsize = sizeof(struct ip_nat_multi_range_compat), | ||
94 | .table = "nat", | ||
95 | .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING) | | ||
96 | (1 << NF_IP_LOCAL_OUT), | ||
104 | .checkentry = check, | 97 | .checkentry = check, |
105 | .me = THIS_MODULE | 98 | .me = THIS_MODULE |
106 | }; | 99 | }; |
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c index 140be51f2f01..be3da7c4b871 100644 --- a/net/ipv4/netfilter/ipt_REDIRECT.c +++ b/net/ipv4/netfilter/ipt_REDIRECT.c | |||
@@ -34,24 +34,13 @@ MODULE_DESCRIPTION("iptables REDIRECT target module"); | |||
34 | static int | 34 | static int |
35 | redirect_check(const char *tablename, | 35 | redirect_check(const char *tablename, |
36 | const void *e, | 36 | const void *e, |
37 | const struct xt_target *target, | ||
37 | void *targinfo, | 38 | void *targinfo, |
38 | unsigned int targinfosize, | 39 | unsigned int targinfosize, |
39 | unsigned int hook_mask) | 40 | unsigned int hook_mask) |
40 | { | 41 | { |
41 | const struct ip_nat_multi_range_compat *mr = targinfo; | 42 | const struct ip_nat_multi_range_compat *mr = targinfo; |
42 | 43 | ||
43 | if (strcmp(tablename, "nat") != 0) { | ||
44 | DEBUGP("redirect_check: bad table `%s'.\n", table); | ||
45 | return 0; | ||
46 | } | ||
47 | if (targinfosize != IPT_ALIGN(sizeof(*mr))) { | ||
48 | DEBUGP("redirect_check: size %u.\n", targinfosize); | ||
49 | return 0; | ||
50 | } | ||
51 | if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))) { | ||
52 | DEBUGP("redirect_check: bad hooks %x.\n", hook_mask); | ||
53 | return 0; | ||
54 | } | ||
55 | if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) { | 44 | if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) { |
56 | DEBUGP("redirect_check: bad MAP_IPS.\n"); | 45 | DEBUGP("redirect_check: bad MAP_IPS.\n"); |
57 | return 0; | 46 | return 0; |
@@ -68,6 +57,7 @@ redirect_target(struct sk_buff **pskb, | |||
68 | const struct net_device *in, | 57 | const struct net_device *in, |
69 | const struct net_device *out, | 58 | const struct net_device *out, |
70 | unsigned int hooknum, | 59 | unsigned int hooknum, |
60 | const struct xt_target *target, | ||
71 | const void *targinfo, | 61 | const void *targinfo, |
72 | void *userinfo) | 62 | void *userinfo) |
73 | { | 63 | { |
@@ -115,6 +105,9 @@ redirect_target(struct sk_buff **pskb, | |||
115 | static struct ipt_target redirect_reg = { | 105 | static struct ipt_target redirect_reg = { |
116 | .name = "REDIRECT", | 106 | .name = "REDIRECT", |
117 | .target = redirect_target, | 107 | .target = redirect_target, |
108 | .targetsize = sizeof(struct ip_nat_multi_range_compat), | ||
109 | .table = "nat", | ||
110 | .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT), | ||
118 | .checkentry = redirect_check, | 111 | .checkentry = redirect_check, |
119 | .me = THIS_MODULE, | 112 | .me = THIS_MODULE, |
120 | }; | 113 | }; |
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 3eb47aae78c5..9d3b3579f27c 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c | |||
@@ -154,10 +154,6 @@ static void send_reset(struct sk_buff *oldskb, int hook) | |||
154 | /* This packet will not be the same as the other: clear nf fields */ | 154 | /* This packet will not be the same as the other: clear nf fields */ |
155 | nf_reset(nskb); | 155 | nf_reset(nskb); |
156 | nskb->nfmark = 0; | 156 | nskb->nfmark = 0; |
157 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
158 | nf_bridge_put(nskb->nf_bridge); | ||
159 | nskb->nf_bridge = NULL; | ||
160 | #endif | ||
161 | 157 | ||
162 | tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); | 158 | tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); |
163 | 159 | ||
@@ -236,6 +232,7 @@ static unsigned int reject(struct sk_buff **pskb, | |||
236 | const struct net_device *in, | 232 | const struct net_device *in, |
237 | const struct net_device *out, | 233 | const struct net_device *out, |
238 | unsigned int hooknum, | 234 | unsigned int hooknum, |
235 | const struct xt_target *target, | ||
239 | const void *targinfo, | 236 | const void *targinfo, |
240 | void *userinfo) | 237 | void *userinfo) |
241 | { | 238 | { |
@@ -283,6 +280,7 @@ static unsigned int reject(struct sk_buff **pskb, | |||
283 | 280 | ||
284 | static int check(const char *tablename, | 281 | static int check(const char *tablename, |
285 | const void *e_void, | 282 | const void *e_void, |
283 | const struct xt_target *target, | ||
286 | void *targinfo, | 284 | void *targinfo, |
287 | unsigned int targinfosize, | 285 | unsigned int targinfosize, |
288 | unsigned int hook_mask) | 286 | unsigned int hook_mask) |
@@ -290,23 +288,6 @@ static int check(const char *tablename, | |||
290 | const struct ipt_reject_info *rejinfo = targinfo; | 288 | const struct ipt_reject_info *rejinfo = targinfo; |
291 | const struct ipt_entry *e = e_void; | 289 | const struct ipt_entry *e = e_void; |
292 | 290 | ||
293 | if (targinfosize != IPT_ALIGN(sizeof(struct ipt_reject_info))) { | ||
294 | DEBUGP("REJECT: targinfosize %u != 0\n", targinfosize); | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | /* Only allow these for packet filtering. */ | ||
299 | if (strcmp(tablename, "filter") != 0) { | ||
300 | DEBUGP("REJECT: bad table `%s'.\n", tablename); | ||
301 | return 0; | ||
302 | } | ||
303 | if ((hook_mask & ~((1 << NF_IP_LOCAL_IN) | ||
304 | | (1 << NF_IP_FORWARD) | ||
305 | | (1 << NF_IP_LOCAL_OUT))) != 0) { | ||
306 | DEBUGP("REJECT: bad hook mask %X\n", hook_mask); | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | if (rejinfo->with == IPT_ICMP_ECHOREPLY) { | 291 | if (rejinfo->with == IPT_ICMP_ECHOREPLY) { |
311 | printk("REJECT: ECHOREPLY no longer supported.\n"); | 292 | printk("REJECT: ECHOREPLY no longer supported.\n"); |
312 | return 0; | 293 | return 0; |
@@ -318,13 +299,16 @@ static int check(const char *tablename, | |||
318 | return 0; | 299 | return 0; |
319 | } | 300 | } |
320 | } | 301 | } |
321 | |||
322 | return 1; | 302 | return 1; |
323 | } | 303 | } |
324 | 304 | ||
325 | static struct ipt_target ipt_reject_reg = { | 305 | static struct ipt_target ipt_reject_reg = { |
326 | .name = "REJECT", | 306 | .name = "REJECT", |
327 | .target = reject, | 307 | .target = reject, |
308 | .targetsize = sizeof(struct ipt_reject_info), | ||
309 | .table = "filter", | ||
310 | .hooks = (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | | ||
311 | (1 << NF_IP_LOCAL_OUT), | ||
328 | .checkentry = check, | 312 | .checkentry = check, |
329 | .me = THIS_MODULE, | 313 | .me = THIS_MODULE, |
330 | }; | 314 | }; |
diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c index a22de59bba0e..7e2ebc9d945e 100644 --- a/net/ipv4/netfilter/ipt_SAME.c +++ b/net/ipv4/netfilter/ipt_SAME.c | |||
@@ -50,6 +50,7 @@ MODULE_DESCRIPTION("iptables special SNAT module for consistent sourceip"); | |||
50 | static int | 50 | static int |
51 | same_check(const char *tablename, | 51 | same_check(const char *tablename, |
52 | const void *e, | 52 | const void *e, |
53 | const struct xt_target *target, | ||
53 | void *targinfo, | 54 | void *targinfo, |
54 | unsigned int targinfosize, | 55 | unsigned int targinfosize, |
55 | unsigned int hook_mask) | 56 | unsigned int hook_mask) |
@@ -59,18 +60,6 @@ same_check(const char *tablename, | |||
59 | 60 | ||
60 | mr->ipnum = 0; | 61 | mr->ipnum = 0; |
61 | 62 | ||
62 | if (strcmp(tablename, "nat") != 0) { | ||
63 | DEBUGP("same_check: bad table `%s'.\n", tablename); | ||
64 | return 0; | ||
65 | } | ||
66 | if (targinfosize != IPT_ALIGN(sizeof(*mr))) { | ||
67 | DEBUGP("same_check: size %u.\n", targinfosize); | ||
68 | return 0; | ||
69 | } | ||
70 | if (hook_mask & ~(1 << NF_IP_PRE_ROUTING | 1 << NF_IP_POST_ROUTING)) { | ||
71 | DEBUGP("same_check: bad hooks %x.\n", hook_mask); | ||
72 | return 0; | ||
73 | } | ||
74 | if (mr->rangesize < 1) { | 63 | if (mr->rangesize < 1) { |
75 | DEBUGP("same_check: need at least one dest range.\n"); | 64 | DEBUGP("same_check: need at least one dest range.\n"); |
76 | return 0; | 65 | return 0; |
@@ -127,7 +116,7 @@ same_check(const char *tablename, | |||
127 | } | 116 | } |
128 | 117 | ||
129 | static void | 118 | static void |
130 | same_destroy(void *targinfo, | 119 | same_destroy(const struct xt_target *target, void *targinfo, |
131 | unsigned int targinfosize) | 120 | unsigned int targinfosize) |
132 | { | 121 | { |
133 | struct ipt_same_info *mr = targinfo; | 122 | struct ipt_same_info *mr = targinfo; |
@@ -143,6 +132,7 @@ same_target(struct sk_buff **pskb, | |||
143 | const struct net_device *in, | 132 | const struct net_device *in, |
144 | const struct net_device *out, | 133 | const struct net_device *out, |
145 | unsigned int hooknum, | 134 | unsigned int hooknum, |
135 | const struct xt_target *target, | ||
146 | const void *targinfo, | 136 | const void *targinfo, |
147 | void *userinfo) | 137 | void *userinfo) |
148 | { | 138 | { |
@@ -191,6 +181,9 @@ same_target(struct sk_buff **pskb, | |||
191 | static struct ipt_target same_reg = { | 181 | static struct ipt_target same_reg = { |
192 | .name = "SAME", | 182 | .name = "SAME", |
193 | .target = same_target, | 183 | .target = same_target, |
184 | .targetsize = sizeof(struct ipt_same_info), | ||
185 | .table = "nat", | ||
186 | .hooks = (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_POST_ROUTING), | ||
194 | .checkentry = same_check, | 187 | .checkentry = same_check, |
195 | .destroy = same_destroy, | 188 | .destroy = same_destroy, |
196 | .me = THIS_MODULE, | 189 | .me = THIS_MODULE, |
diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c index c122841e182c..c4fc50ec2ddb 100644 --- a/net/ipv4/netfilter/ipt_TCPMSS.c +++ b/net/ipv4/netfilter/ipt_TCPMSS.c | |||
@@ -48,6 +48,7 @@ ipt_tcpmss_target(struct sk_buff **pskb, | |||
48 | const struct net_device *in, | 48 | const struct net_device *in, |
49 | const struct net_device *out, | 49 | const struct net_device *out, |
50 | unsigned int hooknum, | 50 | unsigned int hooknum, |
51 | const struct xt_target *target, | ||
51 | const void *targinfo, | 52 | const void *targinfo, |
52 | void *userinfo) | 53 | void *userinfo) |
53 | { | 54 | { |
@@ -211,6 +212,7 @@ static inline int find_syn_match(const struct ipt_entry_match *m) | |||
211 | static int | 212 | static int |
212 | ipt_tcpmss_checkentry(const char *tablename, | 213 | ipt_tcpmss_checkentry(const char *tablename, |
213 | const void *e_void, | 214 | const void *e_void, |
215 | const struct xt_target *target, | ||
214 | void *targinfo, | 216 | void *targinfo, |
215 | unsigned int targinfosize, | 217 | unsigned int targinfosize, |
216 | unsigned int hook_mask) | 218 | unsigned int hook_mask) |
@@ -218,13 +220,6 @@ ipt_tcpmss_checkentry(const char *tablename, | |||
218 | const struct ipt_tcpmss_info *tcpmssinfo = targinfo; | 220 | const struct ipt_tcpmss_info *tcpmssinfo = targinfo; |
219 | const struct ipt_entry *e = e_void; | 221 | const struct ipt_entry *e = e_void; |
220 | 222 | ||
221 | if (targinfosize != IPT_ALIGN(sizeof(struct ipt_tcpmss_info))) { | ||
222 | DEBUGP("ipt_tcpmss_checkentry: targinfosize %u != %u\n", | ||
223 | targinfosize, IPT_ALIGN(sizeof(struct ipt_tcpmss_info))); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | |||
228 | if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) && | 223 | if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) && |
229 | ((hook_mask & ~((1 << NF_IP_FORWARD) | 224 | ((hook_mask & ~((1 << NF_IP_FORWARD) |
230 | | (1 << NF_IP_LOCAL_OUT) | 225 | | (1 << NF_IP_LOCAL_OUT) |
@@ -233,11 +228,8 @@ ipt_tcpmss_checkentry(const char *tablename, | |||
233 | return 0; | 228 | return 0; |
234 | } | 229 | } |
235 | 230 | ||
236 | if (e->ip.proto == IPPROTO_TCP | 231 | if (IPT_MATCH_ITERATE(e, find_syn_match)) |
237 | && !(e->ip.invflags & IPT_INV_PROTO) | ||
238 | && IPT_MATCH_ITERATE(e, find_syn_match)) | ||
239 | return 1; | 232 | return 1; |
240 | |||
241 | printk("TCPMSS: Only works on TCP SYN packets\n"); | 233 | printk("TCPMSS: Only works on TCP SYN packets\n"); |
242 | return 0; | 234 | return 0; |
243 | } | 235 | } |
@@ -245,6 +237,8 @@ ipt_tcpmss_checkentry(const char *tablename, | |||
245 | static struct ipt_target ipt_tcpmss_reg = { | 237 | static struct ipt_target ipt_tcpmss_reg = { |
246 | .name = "TCPMSS", | 238 | .name = "TCPMSS", |
247 | .target = ipt_tcpmss_target, | 239 | .target = ipt_tcpmss_target, |
240 | .targetsize = sizeof(struct ipt_tcpmss_info), | ||
241 | .proto = IPPROTO_TCP, | ||
248 | .checkentry = ipt_tcpmss_checkentry, | 242 | .checkentry = ipt_tcpmss_checkentry, |
249 | .me = THIS_MODULE, | 243 | .me = THIS_MODULE, |
250 | }; | 244 | }; |
diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c index 3a44a56db239..9aa7817657f0 100644 --- a/net/ipv4/netfilter/ipt_TOS.c +++ b/net/ipv4/netfilter/ipt_TOS.c | |||
@@ -25,6 +25,7 @@ target(struct sk_buff **pskb, | |||
25 | const struct net_device *in, | 25 | const struct net_device *in, |
26 | const struct net_device *out, | 26 | const struct net_device *out, |
27 | unsigned int hooknum, | 27 | unsigned int hooknum, |
28 | const struct xt_target *target, | ||
28 | const void *targinfo, | 29 | const void *targinfo, |
29 | void *userinfo) | 30 | void *userinfo) |
30 | { | 31 | { |
@@ -53,24 +54,13 @@ target(struct sk_buff **pskb, | |||
53 | static int | 54 | static int |
54 | checkentry(const char *tablename, | 55 | checkentry(const char *tablename, |
55 | const void *e_void, | 56 | const void *e_void, |
57 | const struct xt_target *target, | ||
56 | void *targinfo, | 58 | void *targinfo, |
57 | unsigned int targinfosize, | 59 | unsigned int targinfosize, |
58 | unsigned int hook_mask) | 60 | unsigned int hook_mask) |
59 | { | 61 | { |
60 | const u_int8_t tos = ((struct ipt_tos_target_info *)targinfo)->tos; | 62 | const u_int8_t tos = ((struct ipt_tos_target_info *)targinfo)->tos; |
61 | 63 | ||
62 | if (targinfosize != IPT_ALIGN(sizeof(struct ipt_tos_target_info))) { | ||
63 | printk(KERN_WARNING "TOS: targinfosize %u != %Zu\n", | ||
64 | targinfosize, | ||
65 | IPT_ALIGN(sizeof(struct ipt_tos_target_info))); | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | if (strcmp(tablename, "mangle") != 0) { | ||
70 | printk(KERN_WARNING "TOS: can only be called from \"mangle\" table, not \"%s\"\n", tablename); | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | if (tos != IPTOS_LOWDELAY | 64 | if (tos != IPTOS_LOWDELAY |
75 | && tos != IPTOS_THROUGHPUT | 65 | && tos != IPTOS_THROUGHPUT |
76 | && tos != IPTOS_RELIABILITY | 66 | && tos != IPTOS_RELIABILITY |
@@ -79,13 +69,14 @@ checkentry(const char *tablename, | |||
79 | printk(KERN_WARNING "TOS: bad tos value %#x\n", tos); | 69 | printk(KERN_WARNING "TOS: bad tos value %#x\n", tos); |
80 | return 0; | 70 | return 0; |
81 | } | 71 | } |
82 | |||
83 | return 1; | 72 | return 1; |
84 | } | 73 | } |
85 | 74 | ||
86 | static struct ipt_target ipt_tos_reg = { | 75 | static struct ipt_target ipt_tos_reg = { |
87 | .name = "TOS", | 76 | .name = "TOS", |
88 | .target = target, | 77 | .target = target, |
78 | .targetsize = sizeof(struct ipt_tos_target_info), | ||
79 | .table = "mangle", | ||
89 | .checkentry = checkentry, | 80 | .checkentry = checkentry, |
90 | .me = THIS_MODULE, | 81 | .me = THIS_MODULE, |
91 | }; | 82 | }; |
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c index b769eb231970..5009a003d578 100644 --- a/net/ipv4/netfilter/ipt_TTL.c +++ b/net/ipv4/netfilter/ipt_TTL.c | |||
@@ -20,9 +20,10 @@ MODULE_DESCRIPTION("IP tables TTL modification module"); | |||
20 | MODULE_LICENSE("GPL"); | 20 | MODULE_LICENSE("GPL"); |
21 | 21 | ||
22 | static unsigned int | 22 | static unsigned int |
23 | ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in, | 23 | ipt_ttl_target(struct sk_buff **pskb, |
24 | const struct net_device *out, unsigned int hooknum, | 24 | const struct net_device *in, const struct net_device *out, |
25 | const void *targinfo, void *userinfo) | 25 | unsigned int hooknum, const struct xt_target *target, |
26 | const void *targinfo, void *userinfo) | ||
26 | { | 27 | { |
27 | struct iphdr *iph; | 28 | struct iphdr *iph; |
28 | const struct ipt_TTL_info *info = targinfo; | 29 | const struct ipt_TTL_info *info = targinfo; |
@@ -67,40 +68,28 @@ ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in, | |||
67 | 68 | ||
68 | static int ipt_ttl_checkentry(const char *tablename, | 69 | static int ipt_ttl_checkentry(const char *tablename, |
69 | const void *e, | 70 | const void *e, |
71 | const struct xt_target *target, | ||
70 | void *targinfo, | 72 | void *targinfo, |
71 | unsigned int targinfosize, | 73 | unsigned int targinfosize, |
72 | unsigned int hook_mask) | 74 | unsigned int hook_mask) |
73 | { | 75 | { |
74 | struct ipt_TTL_info *info = targinfo; | 76 | struct ipt_TTL_info *info = targinfo; |
75 | 77 | ||
76 | if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) { | ||
77 | printk(KERN_WARNING "ipt_TTL: targinfosize %u != %Zu\n", | ||
78 | targinfosize, | ||
79 | IPT_ALIGN(sizeof(struct ipt_TTL_info))); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | if (strcmp(tablename, "mangle")) { | ||
84 | printk(KERN_WARNING "ipt_TTL: can only be called from " | ||
85 | "\"mangle\" table, not \"%s\"\n", tablename); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | if (info->mode > IPT_TTL_MAXMODE) { | 78 | if (info->mode > IPT_TTL_MAXMODE) { |
90 | printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n", | 79 | printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n", |
91 | info->mode); | 80 | info->mode); |
92 | return 0; | 81 | return 0; |
93 | } | 82 | } |
94 | |||
95 | if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) | 83 | if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) |
96 | return 0; | 84 | return 0; |
97 | |||
98 | return 1; | 85 | return 1; |
99 | } | 86 | } |
100 | 87 | ||
101 | static struct ipt_target ipt_TTL = { | 88 | static struct ipt_target ipt_TTL = { |
102 | .name = "TTL", | 89 | .name = "TTL", |
103 | .target = ipt_ttl_target, | 90 | .target = ipt_ttl_target, |
91 | .targetsize = sizeof(struct ipt_TTL_info), | ||
92 | .table = "mangle", | ||
104 | .checkentry = ipt_ttl_checkentry, | 93 | .checkentry = ipt_ttl_checkentry, |
105 | .me = THIS_MODULE, | 94 | .me = THIS_MODULE, |
106 | }; | 95 | }; |
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index 180a9ea57b69..a82a32ed0e2f 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c | |||
@@ -303,6 +303,7 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb, | |||
303 | const struct net_device *in, | 303 | const struct net_device *in, |
304 | const struct net_device *out, | 304 | const struct net_device *out, |
305 | unsigned int hooknum, | 305 | unsigned int hooknum, |
306 | const struct xt_target *target, | ||
306 | const void *targinfo, void *userinfo) | 307 | const void *targinfo, void *userinfo) |
307 | { | 308 | { |
308 | struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo; | 309 | struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo; |
@@ -339,42 +340,37 @@ static void ipt_logfn(unsigned int pf, | |||
339 | 340 | ||
340 | static int ipt_ulog_checkentry(const char *tablename, | 341 | static int ipt_ulog_checkentry(const char *tablename, |
341 | const void *e, | 342 | const void *e, |
343 | const struct xt_target *target, | ||
342 | void *targinfo, | 344 | void *targinfo, |
343 | unsigned int targinfosize, | 345 | unsigned int targinfosize, |
344 | unsigned int hookmask) | 346 | unsigned int hookmask) |
345 | { | 347 | { |
346 | struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo; | 348 | struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo; |
347 | 349 | ||
348 | if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ulog_info))) { | ||
349 | DEBUGP("ipt_ULOG: targinfosize %u != 0\n", targinfosize); | ||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') { | 350 | if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') { |
354 | DEBUGP("ipt_ULOG: prefix term %i\n", | 351 | DEBUGP("ipt_ULOG: prefix term %i\n", |
355 | loginfo->prefix[sizeof(loginfo->prefix) - 1]); | 352 | loginfo->prefix[sizeof(loginfo->prefix) - 1]); |
356 | return 0; | 353 | return 0; |
357 | } | 354 | } |
358 | |||
359 | if (loginfo->qthreshold > ULOG_MAX_QLEN) { | 355 | if (loginfo->qthreshold > ULOG_MAX_QLEN) { |
360 | DEBUGP("ipt_ULOG: queue threshold %i > MAX_QLEN\n", | 356 | DEBUGP("ipt_ULOG: queue threshold %i > MAX_QLEN\n", |
361 | loginfo->qthreshold); | 357 | loginfo->qthreshold); |
362 | return 0; | 358 | return 0; |
363 | } | 359 | } |
364 | |||
365 | return 1; | 360 | return 1; |
366 | } | 361 | } |
367 | 362 | ||
368 | static struct ipt_target ipt_ulog_reg = { | 363 | static struct ipt_target ipt_ulog_reg = { |
369 | .name = "ULOG", | 364 | .name = "ULOG", |
370 | .target = ipt_ulog_target, | 365 | .target = ipt_ulog_target, |
366 | .targetsize = sizeof(struct ipt_ulog_info), | ||
371 | .checkentry = ipt_ulog_checkentry, | 367 | .checkentry = ipt_ulog_checkentry, |
372 | .me = THIS_MODULE, | 368 | .me = THIS_MODULE, |
373 | }; | 369 | }; |
374 | 370 | ||
375 | static struct nf_logger ipt_ulog_logger = { | 371 | static struct nf_logger ipt_ulog_logger = { |
376 | .name = "ipt_ULOG", | 372 | .name = "ipt_ULOG", |
377 | .logfn = &ipt_logfn, | 373 | .logfn = ipt_logfn, |
378 | .me = THIS_MODULE, | 374 | .me = THIS_MODULE, |
379 | }; | 375 | }; |
380 | 376 | ||
diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c index d6b83a976518..5fdf85d0efcf 100644 --- a/net/ipv4/netfilter/ipt_addrtype.c +++ b/net/ipv4/netfilter/ipt_addrtype.c | |||
@@ -27,8 +27,9 @@ static inline int match_type(u_int32_t addr, u_int16_t mask) | |||
27 | return !!(mask & (1 << inet_addr_type(addr))); | 27 | return !!(mask & (1 << inet_addr_type(addr))); |
28 | } | 28 | } |
29 | 29 | ||
30 | static int match(const struct sk_buff *skb, const struct net_device *in, | 30 | static int match(const struct sk_buff *skb, |
31 | const struct net_device *out, const void *matchinfo, | 31 | const struct net_device *in, const struct net_device *out, |
32 | const struct xt_match *match, const void *matchinfo, | ||
32 | int offset, unsigned int protoff, int *hotdrop) | 33 | int offset, unsigned int protoff, int *hotdrop) |
33 | { | 34 | { |
34 | const struct ipt_addrtype_info *info = matchinfo; | 35 | const struct ipt_addrtype_info *info = matchinfo; |
@@ -43,23 +44,10 @@ static int match(const struct sk_buff *skb, const struct net_device *in, | |||
43 | return ret; | 44 | return ret; |
44 | } | 45 | } |
45 | 46 | ||
46 | static int checkentry(const char *tablename, const void *ip, | ||
47 | void *matchinfo, unsigned int matchsize, | ||
48 | unsigned int hook_mask) | ||
49 | { | ||
50 | if (matchsize != IPT_ALIGN(sizeof(struct ipt_addrtype_info))) { | ||
51 | printk(KERN_ERR "ipt_addrtype: invalid size (%u != %Zu)\n", | ||
52 | matchsize, IPT_ALIGN(sizeof(struct ipt_addrtype_info))); | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | return 1; | ||
57 | } | ||
58 | |||
59 | static struct ipt_match addrtype_match = { | 47 | static struct ipt_match addrtype_match = { |
60 | .name = "addrtype", | 48 | .name = "addrtype", |
61 | .match = match, | 49 | .match = match, |
62 | .checkentry = checkentry, | 50 | .matchsize = sizeof(struct ipt_addrtype_info), |
63 | .me = THIS_MODULE | 51 | .me = THIS_MODULE |
64 | }; | 52 | }; |
65 | 53 | ||
diff --git a/net/ipv4/netfilter/ipt_ah.c b/net/ipv4/netfilter/ipt_ah.c index 144adfec13cc..35a21fb1f8e0 100644 --- a/net/ipv4/netfilter/ipt_ah.c +++ b/net/ipv4/netfilter/ipt_ah.c | |||
@@ -39,6 +39,7 @@ static int | |||
39 | match(const struct sk_buff *skb, | 39 | match(const struct sk_buff *skb, |
40 | const struct net_device *in, | 40 | const struct net_device *in, |
41 | const struct net_device *out, | 41 | const struct net_device *out, |
42 | const struct xt_match *match, | ||
42 | const void *matchinfo, | 43 | const void *matchinfo, |
43 | int offset, | 44 | int offset, |
44 | unsigned int protoff, | 45 | unsigned int protoff, |
@@ -71,37 +72,27 @@ match(const struct sk_buff *skb, | |||
71 | static int | 72 | static int |
72 | checkentry(const char *tablename, | 73 | checkentry(const char *tablename, |
73 | const void *ip_void, | 74 | const void *ip_void, |
75 | const struct xt_match *match, | ||
74 | void *matchinfo, | 76 | void *matchinfo, |
75 | unsigned int matchinfosize, | 77 | unsigned int matchinfosize, |
76 | unsigned int hook_mask) | 78 | unsigned int hook_mask) |
77 | { | 79 | { |
78 | const struct ipt_ah *ahinfo = matchinfo; | 80 | const struct ipt_ah *ahinfo = matchinfo; |
79 | const struct ipt_ip *ip = ip_void; | ||
80 | 81 | ||
81 | /* Must specify proto == AH, and no unknown invflags */ | 82 | /* Must specify no unknown invflags */ |
82 | if (ip->proto != IPPROTO_AH || (ip->invflags & IPT_INV_PROTO)) { | ||
83 | duprintf("ipt_ah: Protocol %u != %u\n", ip->proto, | ||
84 | IPPROTO_AH); | ||
85 | return 0; | ||
86 | } | ||
87 | if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_ah))) { | ||
88 | duprintf("ipt_ah: matchsize %u != %u\n", | ||
89 | matchinfosize, IPT_ALIGN(sizeof(struct ipt_ah))); | ||
90 | return 0; | ||
91 | } | ||
92 | if (ahinfo->invflags & ~IPT_AH_INV_MASK) { | 83 | if (ahinfo->invflags & ~IPT_AH_INV_MASK) { |
93 | duprintf("ipt_ah: unknown flags %X\n", | 84 | duprintf("ipt_ah: unknown flags %X\n", ahinfo->invflags); |
94 | ahinfo->invflags); | ||
95 | return 0; | 85 | return 0; |
96 | } | 86 | } |
97 | |||
98 | return 1; | 87 | return 1; |
99 | } | 88 | } |
100 | 89 | ||
101 | static struct ipt_match ah_match = { | 90 | static struct ipt_match ah_match = { |
102 | .name = "ah", | 91 | .name = "ah", |
103 | .match = &match, | 92 | .match = match, |
104 | .checkentry = &checkentry, | 93 | .matchsize = sizeof(struct ipt_ah), |
94 | .proto = IPPROTO_AH, | ||
95 | .checkentry = checkentry, | ||
105 | .me = THIS_MODULE, | 96 | .me = THIS_MODULE, |
106 | }; | 97 | }; |
107 | 98 | ||
diff --git a/net/ipv4/netfilter/ipt_dscp.c b/net/ipv4/netfilter/ipt_dscp.c index 92063b4f8602..11963c385dea 100644 --- a/net/ipv4/netfilter/ipt_dscp.c +++ b/net/ipv4/netfilter/ipt_dscp.c | |||
@@ -19,8 +19,9 @@ MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | |||
19 | MODULE_DESCRIPTION("iptables DSCP matching module"); | 19 | MODULE_DESCRIPTION("iptables DSCP matching module"); |
20 | MODULE_LICENSE("GPL"); | 20 | MODULE_LICENSE("GPL"); |
21 | 21 | ||
22 | static int match(const struct sk_buff *skb, const struct net_device *in, | 22 | static int match(const struct sk_buff *skb, |
23 | const struct net_device *out, const void *matchinfo, | 23 | const struct net_device *in, const struct net_device *out, |
24 | const struct xt_match *match, const void *matchinfo, | ||
24 | int offset, unsigned int protoff, int *hotdrop) | 25 | int offset, unsigned int protoff, int *hotdrop) |
25 | { | 26 | { |
26 | const struct ipt_dscp_info *info = matchinfo; | 27 | const struct ipt_dscp_info *info = matchinfo; |
@@ -31,20 +32,10 @@ static int match(const struct sk_buff *skb, const struct net_device *in, | |||
31 | return ((iph->tos&IPT_DSCP_MASK) == sh_dscp) ^ info->invert; | 32 | return ((iph->tos&IPT_DSCP_MASK) == sh_dscp) ^ info->invert; |
32 | } | 33 | } |
33 | 34 | ||
34 | static int checkentry(const char *tablename, const void *ip, | ||
35 | void *matchinfo, unsigned int matchsize, | ||
36 | unsigned int hook_mask) | ||
37 | { | ||
38 | if (matchsize != IPT_ALIGN(sizeof(struct ipt_dscp_info))) | ||
39 | return 0; | ||
40 | |||
41 | return 1; | ||
42 | } | ||
43 | |||
44 | static struct ipt_match dscp_match = { | 35 | static struct ipt_match dscp_match = { |
45 | .name = "dscp", | 36 | .name = "dscp", |
46 | .match = &match, | 37 | .match = match, |
47 | .checkentry = &checkentry, | 38 | .matchsize = sizeof(struct ipt_dscp_info), |
48 | .me = THIS_MODULE, | 39 | .me = THIS_MODULE, |
49 | }; | 40 | }; |
50 | 41 | ||
diff --git a/net/ipv4/netfilter/ipt_ecn.c b/net/ipv4/netfilter/ipt_ecn.c index e68b0c7981f0..d7e29f6a38d8 100644 --- a/net/ipv4/netfilter/ipt_ecn.c +++ b/net/ipv4/netfilter/ipt_ecn.c | |||
@@ -65,8 +65,9 @@ static inline int match_tcp(const struct sk_buff *skb, | |||
65 | return 1; | 65 | return 1; |
66 | } | 66 | } |
67 | 67 | ||
68 | static int match(const struct sk_buff *skb, const struct net_device *in, | 68 | static int match(const struct sk_buff *skb, |
69 | const struct net_device *out, const void *matchinfo, | 69 | const struct net_device *in, const struct net_device *out, |
70 | const struct xt_match *match, const void *matchinfo, | ||
70 | int offset, unsigned int protoff, int *hotdrop) | 71 | int offset, unsigned int protoff, int *hotdrop) |
71 | { | 72 | { |
72 | const struct ipt_ecn_info *info = matchinfo; | 73 | const struct ipt_ecn_info *info = matchinfo; |
@@ -86,15 +87,13 @@ static int match(const struct sk_buff *skb, const struct net_device *in, | |||
86 | } | 87 | } |
87 | 88 | ||
88 | static int checkentry(const char *tablename, const void *ip_void, | 89 | static int checkentry(const char *tablename, const void *ip_void, |
90 | const struct xt_match *match, | ||
89 | void *matchinfo, unsigned int matchsize, | 91 | void *matchinfo, unsigned int matchsize, |
90 | unsigned int hook_mask) | 92 | unsigned int hook_mask) |
91 | { | 93 | { |
92 | const struct ipt_ecn_info *info = matchinfo; | 94 | const struct ipt_ecn_info *info = matchinfo; |
93 | const struct ipt_ip *ip = ip_void; | 95 | const struct ipt_ip *ip = ip_void; |
94 | 96 | ||
95 | if (matchsize != IPT_ALIGN(sizeof(struct ipt_ecn_info))) | ||
96 | return 0; | ||
97 | |||
98 | if (info->operation & IPT_ECN_OP_MATCH_MASK) | 97 | if (info->operation & IPT_ECN_OP_MATCH_MASK) |
99 | return 0; | 98 | return 0; |
100 | 99 | ||
@@ -113,8 +112,9 @@ static int checkentry(const char *tablename, const void *ip_void, | |||
113 | 112 | ||
114 | static struct ipt_match ecn_match = { | 113 | static struct ipt_match ecn_match = { |
115 | .name = "ecn", | 114 | .name = "ecn", |
116 | .match = &match, | 115 | .match = match, |
117 | .checkentry = &checkentry, | 116 | .matchsize = sizeof(struct ipt_ecn_info), |
117 | .checkentry = checkentry, | ||
118 | .me = THIS_MODULE, | 118 | .me = THIS_MODULE, |
119 | }; | 119 | }; |
120 | 120 | ||
diff --git a/net/ipv4/netfilter/ipt_esp.c b/net/ipv4/netfilter/ipt_esp.c index 9de191a8162d..af0d5ec79cb5 100644 --- a/net/ipv4/netfilter/ipt_esp.c +++ b/net/ipv4/netfilter/ipt_esp.c | |||
@@ -40,6 +40,7 @@ static int | |||
40 | match(const struct sk_buff *skb, | 40 | match(const struct sk_buff *skb, |
41 | const struct net_device *in, | 41 | const struct net_device *in, |
42 | const struct net_device *out, | 42 | const struct net_device *out, |
43 | const struct xt_match *match, | ||
43 | const void *matchinfo, | 44 | const void *matchinfo, |
44 | int offset, | 45 | int offset, |
45 | unsigned int protoff, | 46 | unsigned int protoff, |
@@ -72,37 +73,27 @@ match(const struct sk_buff *skb, | |||
72 | static int | 73 | static int |
73 | checkentry(const char *tablename, | 74 | checkentry(const char *tablename, |
74 | const void *ip_void, | 75 | const void *ip_void, |
76 | const struct xt_match *match, | ||
75 | void *matchinfo, | 77 | void *matchinfo, |
76 | unsigned int matchinfosize, | 78 | unsigned int matchinfosize, |
77 | unsigned int hook_mask) | 79 | unsigned int hook_mask) |
78 | { | 80 | { |
79 | const struct ipt_esp *espinfo = matchinfo; | 81 | const struct ipt_esp *espinfo = matchinfo; |
80 | const struct ipt_ip *ip = ip_void; | ||
81 | 82 | ||
82 | /* Must specify proto == ESP, and no unknown invflags */ | 83 | /* Must specify no unknown invflags */ |
83 | if (ip->proto != IPPROTO_ESP || (ip->invflags & IPT_INV_PROTO)) { | ||
84 | duprintf("ipt_esp: Protocol %u != %u\n", ip->proto, | ||
85 | IPPROTO_ESP); | ||
86 | return 0; | ||
87 | } | ||
88 | if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_esp))) { | ||
89 | duprintf("ipt_esp: matchsize %u != %u\n", | ||
90 | matchinfosize, IPT_ALIGN(sizeof(struct ipt_esp))); | ||
91 | return 0; | ||
92 | } | ||
93 | if (espinfo->invflags & ~IPT_ESP_INV_MASK) { | 84 | if (espinfo->invflags & ~IPT_ESP_INV_MASK) { |
94 | duprintf("ipt_esp: unknown flags %X\n", | 85 | duprintf("ipt_esp: unknown flags %X\n", espinfo->invflags); |
95 | espinfo->invflags); | ||
96 | return 0; | 86 | return 0; |
97 | } | 87 | } |
98 | |||
99 | return 1; | 88 | return 1; |
100 | } | 89 | } |
101 | 90 | ||
102 | static struct ipt_match esp_match = { | 91 | static struct ipt_match esp_match = { |
103 | .name = "esp", | 92 | .name = "esp", |
104 | .match = &match, | 93 | .match = match, |
105 | .checkentry = &checkentry, | 94 | .matchsize = sizeof(struct ipt_esp), |
95 | .proto = IPPROTO_ESP, | ||
96 | .checkentry = checkentry, | ||
106 | .me = THIS_MODULE, | 97 | .me = THIS_MODULE, |
107 | }; | 98 | }; |
108 | 99 | ||
diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c index 4fe48c1bd5f3..dc1521c5aa81 100644 --- a/net/ipv4/netfilter/ipt_hashlimit.c +++ b/net/ipv4/netfilter/ipt_hashlimit.c | |||
@@ -427,6 +427,7 @@ static int | |||
427 | hashlimit_match(const struct sk_buff *skb, | 427 | hashlimit_match(const struct sk_buff *skb, |
428 | const struct net_device *in, | 428 | const struct net_device *in, |
429 | const struct net_device *out, | 429 | const struct net_device *out, |
430 | const struct xt_match *match, | ||
430 | const void *matchinfo, | 431 | const void *matchinfo, |
431 | int offset, | 432 | int offset, |
432 | unsigned int protoff, | 433 | unsigned int protoff, |
@@ -506,15 +507,13 @@ hashlimit_match(const struct sk_buff *skb, | |||
506 | static int | 507 | static int |
507 | hashlimit_checkentry(const char *tablename, | 508 | hashlimit_checkentry(const char *tablename, |
508 | const void *inf, | 509 | const void *inf, |
510 | const struct xt_match *match, | ||
509 | void *matchinfo, | 511 | void *matchinfo, |
510 | unsigned int matchsize, | 512 | unsigned int matchsize, |
511 | unsigned int hook_mask) | 513 | unsigned int hook_mask) |
512 | { | 514 | { |
513 | struct ipt_hashlimit_info *r = matchinfo; | 515 | struct ipt_hashlimit_info *r = matchinfo; |
514 | 516 | ||
515 | if (matchsize != IPT_ALIGN(sizeof(struct ipt_hashlimit_info))) | ||
516 | return 0; | ||
517 | |||
518 | /* Check for overflow. */ | 517 | /* Check for overflow. */ |
519 | if (r->cfg.burst == 0 | 518 | if (r->cfg.burst == 0 |
520 | || user2credits(r->cfg.avg * r->cfg.burst) < | 519 | || user2credits(r->cfg.avg * r->cfg.burst) < |
@@ -558,19 +557,21 @@ hashlimit_checkentry(const char *tablename, | |||
558 | } | 557 | } |
559 | 558 | ||
560 | static void | 559 | static void |
561 | hashlimit_destroy(void *matchinfo, unsigned int matchsize) | 560 | hashlimit_destroy(const struct xt_match *match, void *matchinfo, |
561 | unsigned int matchsize) | ||
562 | { | 562 | { |
563 | struct ipt_hashlimit_info *r = (struct ipt_hashlimit_info *) matchinfo; | 563 | struct ipt_hashlimit_info *r = (struct ipt_hashlimit_info *) matchinfo; |
564 | 564 | ||
565 | htable_put(r->hinfo); | 565 | htable_put(r->hinfo); |
566 | } | 566 | } |
567 | 567 | ||
568 | static struct ipt_match ipt_hashlimit = { | 568 | static struct ipt_match ipt_hashlimit = { |
569 | .name = "hashlimit", | 569 | .name = "hashlimit", |
570 | .match = hashlimit_match, | 570 | .match = hashlimit_match, |
571 | .checkentry = hashlimit_checkentry, | 571 | .matchsize = sizeof(struct ipt_hashlimit_info), |
572 | .destroy = hashlimit_destroy, | 572 | .checkentry = hashlimit_checkentry, |
573 | .me = THIS_MODULE | 573 | .destroy = hashlimit_destroy, |
574 | .me = THIS_MODULE | ||
574 | }; | 575 | }; |
575 | 576 | ||
576 | /* PROC stuff */ | 577 | /* PROC stuff */ |
diff --git a/net/ipv4/netfilter/ipt_iprange.c b/net/ipv4/netfilter/ipt_iprange.c index 13fb16fb7892..ae70112f5e06 100644 --- a/net/ipv4/netfilter/ipt_iprange.c +++ b/net/ipv4/netfilter/ipt_iprange.c | |||
@@ -27,6 +27,7 @@ static int | |||
27 | match(const struct sk_buff *skb, | 27 | match(const struct sk_buff *skb, |
28 | const struct net_device *in, | 28 | const struct net_device *in, |
29 | const struct net_device *out, | 29 | const struct net_device *out, |
30 | const struct xt_match *match, | ||
30 | const void *matchinfo, | 31 | const void *matchinfo, |
31 | int offset, unsigned int protoff, int *hotdrop) | 32 | int offset, unsigned int protoff, int *hotdrop) |
32 | { | 33 | { |
@@ -62,27 +63,12 @@ match(const struct sk_buff *skb, | |||
62 | return 1; | 63 | return 1; |
63 | } | 64 | } |
64 | 65 | ||
65 | static int check(const char *tablename, | 66 | static struct ipt_match iprange_match = { |
66 | const void *inf, | 67 | .name = "iprange", |
67 | void *matchinfo, | 68 | .match = match, |
68 | unsigned int matchsize, | 69 | .matchsize = sizeof(struct ipt_iprange_info), |
69 | unsigned int hook_mask) | 70 | .destroy = NULL, |
70 | { | 71 | .me = THIS_MODULE |
71 | /* verify size */ | ||
72 | if (matchsize != IPT_ALIGN(sizeof(struct ipt_iprange_info))) | ||
73 | return 0; | ||
74 | |||
75 | return 1; | ||
76 | } | ||
77 | |||
78 | static struct ipt_match iprange_match = | ||
79 | { | ||
80 | .list = { NULL, NULL }, | ||
81 | .name = "iprange", | ||
82 | .match = &match, | ||
83 | .checkentry = &check, | ||
84 | .destroy = NULL, | ||
85 | .me = THIS_MODULE | ||
86 | }; | 72 | }; |
87 | 73 | ||
88 | static int __init init(void) | 74 | static int __init init(void) |
diff --git a/net/ipv4/netfilter/ipt_multiport.c b/net/ipv4/netfilter/ipt_multiport.c index 2d52326553f1..bd07f7c53872 100644 --- a/net/ipv4/netfilter/ipt_multiport.c +++ b/net/ipv4/netfilter/ipt_multiport.c | |||
@@ -95,6 +95,7 @@ static int | |||
95 | match(const struct sk_buff *skb, | 95 | match(const struct sk_buff *skb, |
96 | const struct net_device *in, | 96 | const struct net_device *in, |
97 | const struct net_device *out, | 97 | const struct net_device *out, |
98 | const struct xt_match *match, | ||
98 | const void *matchinfo, | 99 | const void *matchinfo, |
99 | int offset, | 100 | int offset, |
100 | unsigned int protoff, | 101 | unsigned int protoff, |
@@ -127,6 +128,7 @@ static int | |||
127 | match_v1(const struct sk_buff *skb, | 128 | match_v1(const struct sk_buff *skb, |
128 | const struct net_device *in, | 129 | const struct net_device *in, |
129 | const struct net_device *out, | 130 | const struct net_device *out, |
131 | const struct xt_match *match, | ||
130 | const void *matchinfo, | 132 | const void *matchinfo, |
131 | int offset, | 133 | int offset, |
132 | unsigned int protoff, | 134 | unsigned int protoff, |
@@ -153,40 +155,19 @@ match_v1(const struct sk_buff *skb, | |||
153 | return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1])); | 155 | return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1])); |
154 | } | 156 | } |
155 | 157 | ||
156 | /* Called when user tries to insert an entry of this type. */ | ||
157 | static int | ||
158 | checkentry(const char *tablename, | ||
159 | const void *ip, | ||
160 | void *matchinfo, | ||
161 | unsigned int matchsize, | ||
162 | unsigned int hook_mask) | ||
163 | { | ||
164 | return (matchsize == IPT_ALIGN(sizeof(struct ipt_multiport))); | ||
165 | } | ||
166 | |||
167 | static int | ||
168 | checkentry_v1(const char *tablename, | ||
169 | const void *ip, | ||
170 | void *matchinfo, | ||
171 | unsigned int matchsize, | ||
172 | unsigned int hook_mask) | ||
173 | { | ||
174 | return (matchsize == IPT_ALIGN(sizeof(struct ipt_multiport_v1))); | ||
175 | } | ||
176 | |||
177 | static struct ipt_match multiport_match = { | 158 | static struct ipt_match multiport_match = { |
178 | .name = "multiport", | 159 | .name = "multiport", |
179 | .revision = 0, | 160 | .revision = 0, |
180 | .match = &match, | 161 | .match = match, |
181 | .checkentry = &checkentry, | 162 | .matchsize = sizeof(struct ipt_multiport), |
182 | .me = THIS_MODULE, | 163 | .me = THIS_MODULE, |
183 | }; | 164 | }; |
184 | 165 | ||
185 | static struct ipt_match multiport_match_v1 = { | 166 | static struct ipt_match multiport_match_v1 = { |
186 | .name = "multiport", | 167 | .name = "multiport", |
187 | .revision = 1, | 168 | .revision = 1, |
188 | .match = &match_v1, | 169 | .match = match_v1, |
189 | .checkentry = &checkentry_v1, | 170 | .matchsize = sizeof(struct ipt_multiport_v1), |
190 | .me = THIS_MODULE, | 171 | .me = THIS_MODULE, |
191 | }; | 172 | }; |
192 | 173 | ||
diff --git a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c index 4843d0c9734f..3900428771f3 100644 --- a/net/ipv4/netfilter/ipt_owner.c +++ b/net/ipv4/netfilter/ipt_owner.c | |||
@@ -25,6 +25,7 @@ static int | |||
25 | match(const struct sk_buff *skb, | 25 | match(const struct sk_buff *skb, |
26 | const struct net_device *in, | 26 | const struct net_device *in, |
27 | const struct net_device *out, | 27 | const struct net_device *out, |
28 | const struct xt_match *match, | ||
28 | const void *matchinfo, | 29 | const void *matchinfo, |
29 | int offset, | 30 | int offset, |
30 | unsigned int protoff, | 31 | unsigned int protoff, |
@@ -53,37 +54,27 @@ match(const struct sk_buff *skb, | |||
53 | static int | 54 | static int |
54 | checkentry(const char *tablename, | 55 | checkentry(const char *tablename, |
55 | const void *ip, | 56 | const void *ip, |
57 | const struct xt_match *match, | ||
56 | void *matchinfo, | 58 | void *matchinfo, |
57 | unsigned int matchsize, | 59 | unsigned int matchsize, |
58 | unsigned int hook_mask) | 60 | unsigned int hook_mask) |
59 | { | 61 | { |
60 | const struct ipt_owner_info *info = matchinfo; | 62 | const struct ipt_owner_info *info = matchinfo; |
61 | 63 | ||
62 | if (hook_mask | ||
63 | & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING))) { | ||
64 | printk("ipt_owner: only valid for LOCAL_OUT or POST_ROUTING.\n"); | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | if (matchsize != IPT_ALIGN(sizeof(struct ipt_owner_info))) { | ||
69 | printk("Matchsize %u != %Zu\n", matchsize, | ||
70 | IPT_ALIGN(sizeof(struct ipt_owner_info))); | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | if (info->match & (IPT_OWNER_PID|IPT_OWNER_SID|IPT_OWNER_COMM)) { | 64 | if (info->match & (IPT_OWNER_PID|IPT_OWNER_SID|IPT_OWNER_COMM)) { |
75 | printk("ipt_owner: pid, sid and command matching " | 65 | printk("ipt_owner: pid, sid and command matching " |
76 | "not supported anymore\n"); | 66 | "not supported anymore\n"); |
77 | return 0; | 67 | return 0; |
78 | } | 68 | } |
79 | |||
80 | return 1; | 69 | return 1; |
81 | } | 70 | } |
82 | 71 | ||
83 | static struct ipt_match owner_match = { | 72 | static struct ipt_match owner_match = { |
84 | .name = "owner", | 73 | .name = "owner", |
85 | .match = &match, | 74 | .match = match, |
86 | .checkentry = &checkentry, | 75 | .matchsize = sizeof(struct ipt_owner_info), |
76 | .hooks = (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING), | ||
77 | .checkentry = checkentry, | ||
87 | .me = THIS_MODULE, | 78 | .me = THIS_MODULE, |
88 | }; | 79 | }; |
89 | 80 | ||
diff --git a/net/ipv4/netfilter/ipt_policy.c b/net/ipv4/netfilter/ipt_policy.c deleted file mode 100644 index 5a7a265280f9..000000000000 --- a/net/ipv4/netfilter/ipt_policy.c +++ /dev/null | |||
@@ -1,176 +0,0 @@ | |||
1 | /* IP tables module for matching IPsec policy | ||
2 | * | ||
3 | * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/skbuff.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <net/xfrm.h> | ||
16 | |||
17 | #include <linux/netfilter_ipv4.h> | ||
18 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
19 | #include <linux/netfilter_ipv4/ipt_policy.h> | ||
20 | |||
21 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
22 | MODULE_DESCRIPTION("IPtables IPsec policy matching module"); | ||
23 | MODULE_LICENSE("GPL"); | ||
24 | |||
25 | |||
26 | static inline int | ||
27 | match_xfrm_state(struct xfrm_state *x, const struct ipt_policy_elem *e) | ||
28 | { | ||
29 | #define MATCH_ADDR(x,y,z) (!e->match.x || \ | ||
30 | ((e->x.a4.s_addr == (e->y.a4.s_addr & (z))) \ | ||
31 | ^ e->invert.x)) | ||
32 | #define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x)) | ||
33 | |||
34 | return MATCH_ADDR(saddr, smask, x->props.saddr.a4) && | ||
35 | MATCH_ADDR(daddr, dmask, x->id.daddr.a4) && | ||
36 | MATCH(proto, x->id.proto) && | ||
37 | MATCH(mode, x->props.mode) && | ||
38 | MATCH(spi, x->id.spi) && | ||
39 | MATCH(reqid, x->props.reqid); | ||
40 | } | ||
41 | |||
42 | static int | ||
43 | match_policy_in(const struct sk_buff *skb, const struct ipt_policy_info *info) | ||
44 | { | ||
45 | const struct ipt_policy_elem *e; | ||
46 | struct sec_path *sp = skb->sp; | ||
47 | int strict = info->flags & IPT_POLICY_MATCH_STRICT; | ||
48 | int i, pos; | ||
49 | |||
50 | if (sp == NULL) | ||
51 | return -1; | ||
52 | if (strict && info->len != sp->len) | ||
53 | return 0; | ||
54 | |||
55 | for (i = sp->len - 1; i >= 0; i--) { | ||
56 | pos = strict ? i - sp->len + 1 : 0; | ||
57 | if (pos >= info->len) | ||
58 | return 0; | ||
59 | e = &info->pol[pos]; | ||
60 | |||
61 | if (match_xfrm_state(sp->x[i].xvec, e)) { | ||
62 | if (!strict) | ||
63 | return 1; | ||
64 | } else if (strict) | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | return strict ? 1 : 0; | ||
69 | } | ||
70 | |||
71 | static int | ||
72 | match_policy_out(const struct sk_buff *skb, const struct ipt_policy_info *info) | ||
73 | { | ||
74 | const struct ipt_policy_elem *e; | ||
75 | struct dst_entry *dst = skb->dst; | ||
76 | int strict = info->flags & IPT_POLICY_MATCH_STRICT; | ||
77 | int i, pos; | ||
78 | |||
79 | if (dst->xfrm == NULL) | ||
80 | return -1; | ||
81 | |||
82 | for (i = 0; dst && dst->xfrm; dst = dst->child, i++) { | ||
83 | pos = strict ? i : 0; | ||
84 | if (pos >= info->len) | ||
85 | return 0; | ||
86 | e = &info->pol[pos]; | ||
87 | |||
88 | if (match_xfrm_state(dst->xfrm, e)) { | ||
89 | if (!strict) | ||
90 | return 1; | ||
91 | } else if (strict) | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | return strict ? i == info->len : 0; | ||
96 | } | ||
97 | |||
98 | static int match(const struct sk_buff *skb, | ||
99 | const struct net_device *in, | ||
100 | const struct net_device *out, | ||
101 | const void *matchinfo, | ||
102 | int offset, | ||
103 | unsigned int protoff, | ||
104 | int *hotdrop) | ||
105 | { | ||
106 | const struct ipt_policy_info *info = matchinfo; | ||
107 | int ret; | ||
108 | |||
109 | if (info->flags & IPT_POLICY_MATCH_IN) | ||
110 | ret = match_policy_in(skb, info); | ||
111 | else | ||
112 | ret = match_policy_out(skb, info); | ||
113 | |||
114 | if (ret < 0) | ||
115 | ret = info->flags & IPT_POLICY_MATCH_NONE ? 1 : 0; | ||
116 | else if (info->flags & IPT_POLICY_MATCH_NONE) | ||
117 | ret = 0; | ||
118 | |||
119 | return ret; | ||
120 | } | ||
121 | |||
122 | static int checkentry(const char *tablename, const void *ip_void, | ||
123 | void *matchinfo, unsigned int matchsize, | ||
124 | unsigned int hook_mask) | ||
125 | { | ||
126 | struct ipt_policy_info *info = matchinfo; | ||
127 | |||
128 | if (matchsize != IPT_ALIGN(sizeof(*info))) { | ||
129 | printk(KERN_ERR "ipt_policy: matchsize %u != %zu\n", | ||
130 | matchsize, IPT_ALIGN(sizeof(*info))); | ||
131 | return 0; | ||
132 | } | ||
133 | if (!(info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT))) { | ||
134 | printk(KERN_ERR "ipt_policy: neither incoming nor " | ||
135 | "outgoing policy selected\n"); | ||
136 | return 0; | ||
137 | } | ||
138 | if (hook_mask & (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN) | ||
139 | && info->flags & IPT_POLICY_MATCH_OUT) { | ||
140 | printk(KERN_ERR "ipt_policy: output policy not valid in " | ||
141 | "PRE_ROUTING and INPUT\n"); | ||
142 | return 0; | ||
143 | } | ||
144 | if (hook_mask & (1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT) | ||
145 | && info->flags & IPT_POLICY_MATCH_IN) { | ||
146 | printk(KERN_ERR "ipt_policy: input policy not valid in " | ||
147 | "POST_ROUTING and OUTPUT\n"); | ||
148 | return 0; | ||
149 | } | ||
150 | if (info->len > IPT_POLICY_MAX_ELEM) { | ||
151 | printk(KERN_ERR "ipt_policy: too many policy elements\n"); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | return 1; | ||
156 | } | ||
157 | |||
158 | static struct ipt_match policy_match = { | ||
159 | .name = "policy", | ||
160 | .match = match, | ||
161 | .checkentry = checkentry, | ||
162 | .me = THIS_MODULE, | ||
163 | }; | ||
164 | |||
165 | static int __init init(void) | ||
166 | { | ||
167 | return ipt_register_match(&policy_match); | ||
168 | } | ||
169 | |||
170 | static void __exit fini(void) | ||
171 | { | ||
172 | ipt_unregister_match(&policy_match); | ||
173 | } | ||
174 | |||
175 | module_init(init); | ||
176 | module_exit(fini); | ||
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c index 44611d6d14f5..06792ead1da4 100644 --- a/net/ipv4/netfilter/ipt_recent.c +++ b/net/ipv4/netfilter/ipt_recent.c | |||
@@ -102,6 +102,7 @@ static int | |||
102 | match(const struct sk_buff *skb, | 102 | match(const struct sk_buff *skb, |
103 | const struct net_device *in, | 103 | const struct net_device *in, |
104 | const struct net_device *out, | 104 | const struct net_device *out, |
105 | const struct xt_match *match, | ||
105 | const void *matchinfo, | 106 | const void *matchinfo, |
106 | int offset, | 107 | int offset, |
107 | unsigned int protoff, | 108 | unsigned int protoff, |
@@ -318,7 +319,7 @@ static int ip_recent_ctrl(struct file *file, const char __user *input, unsigned | |||
318 | skb->nh.iph->daddr = 0; | 319 | skb->nh.iph->daddr = 0; |
319 | /* Clear ttl since we have no way of knowing it */ | 320 | /* Clear ttl since we have no way of knowing it */ |
320 | skb->nh.iph->ttl = 0; | 321 | skb->nh.iph->ttl = 0; |
321 | match(skb,NULL,NULL,info,0,0,NULL); | 322 | match(skb,NULL,NULL,NULL,info,0,0,NULL); |
322 | 323 | ||
323 | kfree(skb->nh.iph); | 324 | kfree(skb->nh.iph); |
324 | out_free_skb: | 325 | out_free_skb: |
@@ -356,6 +357,7 @@ static int | |||
356 | match(const struct sk_buff *skb, | 357 | match(const struct sk_buff *skb, |
357 | const struct net_device *in, | 358 | const struct net_device *in, |
358 | const struct net_device *out, | 359 | const struct net_device *out, |
360 | const struct xt_match *match, | ||
359 | const void *matchinfo, | 361 | const void *matchinfo, |
360 | int offset, | 362 | int offset, |
361 | unsigned int protoff, | 363 | unsigned int protoff, |
@@ -657,6 +659,7 @@ match(const struct sk_buff *skb, | |||
657 | static int | 659 | static int |
658 | checkentry(const char *tablename, | 660 | checkentry(const char *tablename, |
659 | const void *ip, | 661 | const void *ip, |
662 | const struct xt_match *match, | ||
660 | void *matchinfo, | 663 | void *matchinfo, |
661 | unsigned int matchsize, | 664 | unsigned int matchsize, |
662 | unsigned int hook_mask) | 665 | unsigned int hook_mask) |
@@ -670,8 +673,6 @@ checkentry(const char *tablename, | |||
670 | if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() entered.\n"); | 673 | if(debug) printk(KERN_INFO RECENT_NAME ": checkentry() entered.\n"); |
671 | #endif | 674 | #endif |
672 | 675 | ||
673 | if (matchsize != IPT_ALIGN(sizeof(struct ipt_recent_info))) return 0; | ||
674 | |||
675 | /* seconds and hit_count only valid for CHECK/UPDATE */ | 676 | /* seconds and hit_count only valid for CHECK/UPDATE */ |
676 | if(info->check_set & IPT_RECENT_SET) { flag++; if(info->seconds || info->hit_count) return 0; } | 677 | if(info->check_set & IPT_RECENT_SET) { flag++; if(info->seconds || info->hit_count) return 0; } |
677 | if(info->check_set & IPT_RECENT_REMOVE) { flag++; if(info->seconds || info->hit_count) return 0; } | 678 | if(info->check_set & IPT_RECENT_REMOVE) { flag++; if(info->seconds || info->hit_count) return 0; } |
@@ -871,7 +872,7 @@ checkentry(const char *tablename, | |||
871 | * up its memory. | 872 | * up its memory. |
872 | */ | 873 | */ |
873 | static void | 874 | static void |
874 | destroy(void *matchinfo, unsigned int matchsize) | 875 | destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize) |
875 | { | 876 | { |
876 | const struct ipt_recent_info *info = matchinfo; | 877 | const struct ipt_recent_info *info = matchinfo; |
877 | struct recent_ip_tables *curr_table, *last_table; | 878 | struct recent_ip_tables *curr_table, *last_table; |
@@ -951,12 +952,13 @@ destroy(void *matchinfo, unsigned int matchsize) | |||
951 | /* This is the structure we pass to ipt_register to register our | 952 | /* This is the structure we pass to ipt_register to register our |
952 | * module with iptables. | 953 | * module with iptables. |
953 | */ | 954 | */ |
954 | static struct ipt_match recent_match = { | 955 | static struct ipt_match recent_match = { |
955 | .name = "recent", | 956 | .name = "recent", |
956 | .match = &match, | 957 | .match = match, |
957 | .checkentry = &checkentry, | 958 | .matchsize = sizeof(struct ipt_recent_info), |
958 | .destroy = &destroy, | 959 | .checkentry = checkentry, |
959 | .me = THIS_MODULE | 960 | .destroy = destroy, |
961 | .me = THIS_MODULE | ||
960 | }; | 962 | }; |
961 | 963 | ||
962 | /* Kernel module initialization. */ | 964 | /* Kernel module initialization. */ |
diff --git a/net/ipv4/netfilter/ipt_tos.c b/net/ipv4/netfilter/ipt_tos.c index 9ab765e126f2..e404e92ddd01 100644 --- a/net/ipv4/netfilter/ipt_tos.c +++ b/net/ipv4/netfilter/ipt_tos.c | |||
@@ -21,6 +21,7 @@ static int | |||
21 | match(const struct sk_buff *skb, | 21 | match(const struct sk_buff *skb, |
22 | const struct net_device *in, | 22 | const struct net_device *in, |
23 | const struct net_device *out, | 23 | const struct net_device *out, |
24 | const struct xt_match *match, | ||
24 | const void *matchinfo, | 25 | const void *matchinfo, |
25 | int offset, | 26 | int offset, |
26 | unsigned int protoff, | 27 | unsigned int protoff, |
@@ -31,23 +32,10 @@ match(const struct sk_buff *skb, | |||
31 | return (skb->nh.iph->tos == info->tos) ^ info->invert; | 32 | return (skb->nh.iph->tos == info->tos) ^ info->invert; |
32 | } | 33 | } |
33 | 34 | ||
34 | static int | ||
35 | checkentry(const char *tablename, | ||
36 | const void *ip, | ||
37 | void *matchinfo, | ||
38 | unsigned int matchsize, | ||
39 | unsigned int hook_mask) | ||
40 | { | ||
41 | if (matchsize != IPT_ALIGN(sizeof(struct ipt_tos_info))) | ||
42 | return 0; | ||
43 | |||
44 | return 1; | ||
45 | } | ||
46 | |||
47 | static struct ipt_match tos_match = { | 35 | static struct ipt_match tos_match = { |
48 | .name = "tos", | 36 | .name = "tos", |
49 | .match = &match, | 37 | .match = match, |
50 | .checkentry = &checkentry, | 38 | .matchsize = sizeof(struct ipt_tos_info), |
51 | .me = THIS_MODULE, | 39 | .me = THIS_MODULE, |
52 | }; | 40 | }; |
53 | 41 | ||
diff --git a/net/ipv4/netfilter/ipt_ttl.c b/net/ipv4/netfilter/ipt_ttl.c index 82da53f430ab..ae7ce4d8d90e 100644 --- a/net/ipv4/netfilter/ipt_ttl.c +++ b/net/ipv4/netfilter/ipt_ttl.c | |||
@@ -19,8 +19,9 @@ MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | |||
19 | MODULE_DESCRIPTION("IP tables TTL matching module"); | 19 | MODULE_DESCRIPTION("IP tables TTL matching module"); |
20 | MODULE_LICENSE("GPL"); | 20 | MODULE_LICENSE("GPL"); |
21 | 21 | ||
22 | static int match(const struct sk_buff *skb, const struct net_device *in, | 22 | static int match(const struct sk_buff *skb, |
23 | const struct net_device *out, const void *matchinfo, | 23 | const struct net_device *in, const struct net_device *out, |
24 | const struct xt_match *match, const void *matchinfo, | ||
24 | int offset, unsigned int protoff, int *hotdrop) | 25 | int offset, unsigned int protoff, int *hotdrop) |
25 | { | 26 | { |
26 | const struct ipt_ttl_info *info = matchinfo; | 27 | const struct ipt_ttl_info *info = matchinfo; |
@@ -47,20 +48,10 @@ static int match(const struct sk_buff *skb, const struct net_device *in, | |||
47 | return 0; | 48 | return 0; |
48 | } | 49 | } |
49 | 50 | ||
50 | static int checkentry(const char *tablename, const void *ip, | ||
51 | void *matchinfo, unsigned int matchsize, | ||
52 | unsigned int hook_mask) | ||
53 | { | ||
54 | if (matchsize != IPT_ALIGN(sizeof(struct ipt_ttl_info))) | ||
55 | return 0; | ||
56 | |||
57 | return 1; | ||
58 | } | ||
59 | |||
60 | static struct ipt_match ttl_match = { | 51 | static struct ipt_match ttl_match = { |
61 | .name = "ttl", | 52 | .name = "ttl", |
62 | .match = &match, | 53 | .match = match, |
63 | .checkentry = &checkentry, | 54 | .matchsize = sizeof(struct ipt_ttl_info), |
64 | .me = THIS_MODULE, | 55 | .me = THIS_MODULE, |
65 | }; | 56 | }; |
66 | 57 | ||
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 6c8624a54933..c8abc9d859b9 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | |||
@@ -141,19 +141,21 @@ static unsigned int ipv4_conntrack_help(unsigned int hooknum, | |||
141 | { | 141 | { |
142 | struct nf_conn *ct; | 142 | struct nf_conn *ct; |
143 | enum ip_conntrack_info ctinfo; | 143 | enum ip_conntrack_info ctinfo; |
144 | struct nf_conn_help *help; | ||
144 | 145 | ||
145 | /* This is where we call the helper: as the packet goes out. */ | 146 | /* This is where we call the helper: as the packet goes out. */ |
146 | ct = nf_ct_get(*pskb, &ctinfo); | 147 | ct = nf_ct_get(*pskb, &ctinfo); |
147 | if (ct && ct->helper) { | 148 | if (!ct) |
148 | unsigned int ret; | 149 | return NF_ACCEPT; |
149 | ret = ct->helper->help(pskb, | 150 | |
150 | (*pskb)->nh.raw - (*pskb)->data | 151 | help = nfct_help(ct); |
151 | + (*pskb)->nh.iph->ihl*4, | 152 | if (!help || !help->helper) |
152 | ct, ctinfo); | 153 | return NF_ACCEPT; |
153 | if (ret != NF_ACCEPT) | 154 | |
154 | return ret; | 155 | return help->helper->help(pskb, |
155 | } | 156 | (*pskb)->nh.raw - (*pskb)->data |
156 | return NF_ACCEPT; | 157 | + (*pskb)->nh.iph->ihl*4, |
158 | ct, ctinfo); | ||
157 | } | 159 | } |
158 | 160 | ||
159 | static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, | 161 | static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, |
@@ -566,6 +568,7 @@ static int init_or_cleanup(int init) | |||
566 | return ret; | 568 | return ret; |
567 | } | 569 | } |
568 | 570 | ||
571 | MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET)); | ||
569 | MODULE_LICENSE("GPL"); | 572 | MODULE_LICENSE("GPL"); |
570 | 573 | ||
571 | static int __init init(void) | 574 | static int __init init(void) |
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index f29a12da5109..fc2562415555 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
@@ -660,12 +660,9 @@ static int raw_geticmpfilter(struct sock *sk, char __user *optval, int __user *o | |||
660 | out: return ret; | 660 | out: return ret; |
661 | } | 661 | } |
662 | 662 | ||
663 | static int raw_setsockopt(struct sock *sk, int level, int optname, | 663 | static int do_raw_setsockopt(struct sock *sk, int level, int optname, |
664 | char __user *optval, int optlen) | 664 | char __user *optval, int optlen) |
665 | { | 665 | { |
666 | if (level != SOL_RAW) | ||
667 | return ip_setsockopt(sk, level, optname, optval, optlen); | ||
668 | |||
669 | if (optname == ICMP_FILTER) { | 666 | if (optname == ICMP_FILTER) { |
670 | if (inet_sk(sk)->num != IPPROTO_ICMP) | 667 | if (inet_sk(sk)->num != IPPROTO_ICMP) |
671 | return -EOPNOTSUPP; | 668 | return -EOPNOTSUPP; |
@@ -675,12 +672,27 @@ static int raw_setsockopt(struct sock *sk, int level, int optname, | |||
675 | return -ENOPROTOOPT; | 672 | return -ENOPROTOOPT; |
676 | } | 673 | } |
677 | 674 | ||
678 | static int raw_getsockopt(struct sock *sk, int level, int optname, | 675 | static int raw_setsockopt(struct sock *sk, int level, int optname, |
679 | char __user *optval, int __user *optlen) | 676 | char __user *optval, int optlen) |
680 | { | 677 | { |
681 | if (level != SOL_RAW) | 678 | if (level != SOL_RAW) |
682 | return ip_getsockopt(sk, level, optname, optval, optlen); | 679 | return ip_setsockopt(sk, level, optname, optval, optlen); |
680 | return do_raw_setsockopt(sk, level, optname, optval, optlen); | ||
681 | } | ||
683 | 682 | ||
683 | #ifdef CONFIG_COMPAT | ||
684 | static int compat_raw_setsockopt(struct sock *sk, int level, int optname, | ||
685 | char __user *optval, int optlen) | ||
686 | { | ||
687 | if (level != SOL_RAW) | ||
688 | return compat_ip_setsockopt(sk, level, optname, optval, optlen); | ||
689 | return do_raw_setsockopt(sk, level, optname, optval, optlen); | ||
690 | } | ||
691 | #endif | ||
692 | |||
693 | static int do_raw_getsockopt(struct sock *sk, int level, int optname, | ||
694 | char __user *optval, int __user *optlen) | ||
695 | { | ||
684 | if (optname == ICMP_FILTER) { | 696 | if (optname == ICMP_FILTER) { |
685 | if (inet_sk(sk)->num != IPPROTO_ICMP) | 697 | if (inet_sk(sk)->num != IPPROTO_ICMP) |
686 | return -EOPNOTSUPP; | 698 | return -EOPNOTSUPP; |
@@ -690,6 +702,24 @@ static int raw_getsockopt(struct sock *sk, int level, int optname, | |||
690 | return -ENOPROTOOPT; | 702 | return -ENOPROTOOPT; |
691 | } | 703 | } |
692 | 704 | ||
705 | static int raw_getsockopt(struct sock *sk, int level, int optname, | ||
706 | char __user *optval, int __user *optlen) | ||
707 | { | ||
708 | if (level != SOL_RAW) | ||
709 | return ip_getsockopt(sk, level, optname, optval, optlen); | ||
710 | return do_raw_getsockopt(sk, level, optname, optval, optlen); | ||
711 | } | ||
712 | |||
713 | #ifdef CONFIG_COMPAT | ||
714 | static int compat_raw_getsockopt(struct sock *sk, int level, int optname, | ||
715 | char __user *optval, int __user *optlen) | ||
716 | { | ||
717 | if (level != SOL_RAW) | ||
718 | return compat_ip_getsockopt(sk, level, optname, optval, optlen); | ||
719 | return do_raw_getsockopt(sk, level, optname, optval, optlen); | ||
720 | } | ||
721 | #endif | ||
722 | |||
693 | static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) | 723 | static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) |
694 | { | 724 | { |
695 | switch (cmd) { | 725 | switch (cmd) { |
@@ -719,22 +749,26 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
719 | } | 749 | } |
720 | 750 | ||
721 | struct proto raw_prot = { | 751 | struct proto raw_prot = { |
722 | .name = "RAW", | 752 | .name = "RAW", |
723 | .owner = THIS_MODULE, | 753 | .owner = THIS_MODULE, |
724 | .close = raw_close, | 754 | .close = raw_close, |
725 | .connect = ip4_datagram_connect, | 755 | .connect = ip4_datagram_connect, |
726 | .disconnect = udp_disconnect, | 756 | .disconnect = udp_disconnect, |
727 | .ioctl = raw_ioctl, | 757 | .ioctl = raw_ioctl, |
728 | .init = raw_init, | 758 | .init = raw_init, |
729 | .setsockopt = raw_setsockopt, | 759 | .setsockopt = raw_setsockopt, |
730 | .getsockopt = raw_getsockopt, | 760 | .getsockopt = raw_getsockopt, |
731 | .sendmsg = raw_sendmsg, | 761 | .sendmsg = raw_sendmsg, |
732 | .recvmsg = raw_recvmsg, | 762 | .recvmsg = raw_recvmsg, |
733 | .bind = raw_bind, | 763 | .bind = raw_bind, |
734 | .backlog_rcv = raw_rcv_skb, | 764 | .backlog_rcv = raw_rcv_skb, |
735 | .hash = raw_v4_hash, | 765 | .hash = raw_v4_hash, |
736 | .unhash = raw_v4_unhash, | 766 | .unhash = raw_v4_unhash, |
737 | .obj_size = sizeof(struct raw_sock), | 767 | .obj_size = sizeof(struct raw_sock), |
768 | #ifdef CONFIG_COMPAT | ||
769 | .compat_setsockopt = compat_raw_setsockopt, | ||
770 | .compat_getsockopt = compat_raw_getsockopt, | ||
771 | #endif | ||
738 | }; | 772 | }; |
739 | 773 | ||
740 | #ifdef CONFIG_PROC_FS | 774 | #ifdef CONFIG_PROC_FS |
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 16984d4a8a06..6b6c3adfcf00 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c | |||
@@ -664,7 +664,30 @@ ctl_table ipv4_table[] = { | |||
664 | .mode = 0644, | 664 | .mode = 0644, |
665 | .proc_handler = &proc_dointvec, | 665 | .proc_handler = &proc_dointvec, |
666 | }, | 666 | }, |
667 | 667 | { | |
668 | .ctl_name = NET_TCP_MTU_PROBING, | ||
669 | .procname = "tcp_mtu_probing", | ||
670 | .data = &sysctl_tcp_mtu_probing, | ||
671 | .maxlen = sizeof(int), | ||
672 | .mode = 0644, | ||
673 | .proc_handler = &proc_dointvec, | ||
674 | }, | ||
675 | { | ||
676 | .ctl_name = NET_TCP_BASE_MSS, | ||
677 | .procname = "tcp_base_mss", | ||
678 | .data = &sysctl_tcp_base_mss, | ||
679 | .maxlen = sizeof(int), | ||
680 | .mode = 0644, | ||
681 | .proc_handler = &proc_dointvec, | ||
682 | }, | ||
683 | { | ||
684 | .ctl_name = NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS, | ||
685 | .procname = "tcp_workaround_signed_windows", | ||
686 | .data = &sysctl_tcp_workaround_signed_windows, | ||
687 | .maxlen = sizeof(int), | ||
688 | .mode = 0644, | ||
689 | .proc_handler = &proc_dointvec | ||
690 | }, | ||
668 | { .ctl_name = 0 } | 691 | { .ctl_name = 0 } |
669 | }; | 692 | }; |
670 | 693 | ||
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 00aa80e93243..4b0272c92d66 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -1687,18 +1687,14 @@ int tcp_disconnect(struct sock *sk, int flags) | |||
1687 | /* | 1687 | /* |
1688 | * Socket option code for TCP. | 1688 | * Socket option code for TCP. |
1689 | */ | 1689 | */ |
1690 | int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, | 1690 | static int do_tcp_setsockopt(struct sock *sk, int level, |
1691 | int optlen) | 1691 | int optname, char __user *optval, int optlen) |
1692 | { | 1692 | { |
1693 | struct tcp_sock *tp = tcp_sk(sk); | 1693 | struct tcp_sock *tp = tcp_sk(sk); |
1694 | struct inet_connection_sock *icsk = inet_csk(sk); | 1694 | struct inet_connection_sock *icsk = inet_csk(sk); |
1695 | int val; | 1695 | int val; |
1696 | int err = 0; | 1696 | int err = 0; |
1697 | 1697 | ||
1698 | if (level != SOL_TCP) | ||
1699 | return icsk->icsk_af_ops->setsockopt(sk, level, optname, | ||
1700 | optval, optlen); | ||
1701 | |||
1702 | /* This is a string value all the others are int's */ | 1698 | /* This is a string value all the others are int's */ |
1703 | if (optname == TCP_CONGESTION) { | 1699 | if (optname == TCP_CONGESTION) { |
1704 | char name[TCP_CA_NAME_MAX]; | 1700 | char name[TCP_CA_NAME_MAX]; |
@@ -1871,6 +1867,30 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
1871 | return err; | 1867 | return err; |
1872 | } | 1868 | } |
1873 | 1869 | ||
1870 | int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, | ||
1871 | int optlen) | ||
1872 | { | ||
1873 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
1874 | |||
1875 | if (level != SOL_TCP) | ||
1876 | return icsk->icsk_af_ops->setsockopt(sk, level, optname, | ||
1877 | optval, optlen); | ||
1878 | return do_tcp_setsockopt(sk, level, optname, optval, optlen); | ||
1879 | } | ||
1880 | |||
1881 | #ifdef CONFIG_COMPAT | ||
1882 | int compat_tcp_setsockopt(struct sock *sk, int level, int optname, | ||
1883 | char __user *optval, int optlen) | ||
1884 | { | ||
1885 | if (level != SOL_TCP) | ||
1886 | return inet_csk_compat_setsockopt(sk, level, optname, | ||
1887 | optval, optlen); | ||
1888 | return do_tcp_setsockopt(sk, level, optname, optval, optlen); | ||
1889 | } | ||
1890 | |||
1891 | EXPORT_SYMBOL(compat_tcp_setsockopt); | ||
1892 | #endif | ||
1893 | |||
1874 | /* Return information about state of tcp endpoint in API format. */ | 1894 | /* Return information about state of tcp endpoint in API format. */ |
1875 | void tcp_get_info(struct sock *sk, struct tcp_info *info) | 1895 | void tcp_get_info(struct sock *sk, struct tcp_info *info) |
1876 | { | 1896 | { |
@@ -1931,17 +1951,13 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) | |||
1931 | 1951 | ||
1932 | EXPORT_SYMBOL_GPL(tcp_get_info); | 1952 | EXPORT_SYMBOL_GPL(tcp_get_info); |
1933 | 1953 | ||
1934 | int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | 1954 | static int do_tcp_getsockopt(struct sock *sk, int level, |
1935 | int __user *optlen) | 1955 | int optname, char __user *optval, int __user *optlen) |
1936 | { | 1956 | { |
1937 | struct inet_connection_sock *icsk = inet_csk(sk); | 1957 | struct inet_connection_sock *icsk = inet_csk(sk); |
1938 | struct tcp_sock *tp = tcp_sk(sk); | 1958 | struct tcp_sock *tp = tcp_sk(sk); |
1939 | int val, len; | 1959 | int val, len; |
1940 | 1960 | ||
1941 | if (level != SOL_TCP) | ||
1942 | return icsk->icsk_af_ops->getsockopt(sk, level, optname, | ||
1943 | optval, optlen); | ||
1944 | |||
1945 | if (get_user(len, optlen)) | 1961 | if (get_user(len, optlen)) |
1946 | return -EFAULT; | 1962 | return -EFAULT; |
1947 | 1963 | ||
@@ -2025,6 +2041,29 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
2025 | return 0; | 2041 | return 0; |
2026 | } | 2042 | } |
2027 | 2043 | ||
2044 | int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | ||
2045 | int __user *optlen) | ||
2046 | { | ||
2047 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
2048 | |||
2049 | if (level != SOL_TCP) | ||
2050 | return icsk->icsk_af_ops->getsockopt(sk, level, optname, | ||
2051 | optval, optlen); | ||
2052 | return do_tcp_getsockopt(sk, level, optname, optval, optlen); | ||
2053 | } | ||
2054 | |||
2055 | #ifdef CONFIG_COMPAT | ||
2056 | int compat_tcp_getsockopt(struct sock *sk, int level, int optname, | ||
2057 | char __user *optval, int __user *optlen) | ||
2058 | { | ||
2059 | if (level != SOL_TCP) | ||
2060 | return inet_csk_compat_getsockopt(sk, level, optname, | ||
2061 | optval, optlen); | ||
2062 | return do_tcp_getsockopt(sk, level, optname, optval, optlen); | ||
2063 | } | ||
2064 | |||
2065 | EXPORT_SYMBOL(compat_tcp_getsockopt); | ||
2066 | #endif | ||
2028 | 2067 | ||
2029 | extern void __skb_cb_too_small_for_tcp(int, int); | 2068 | extern void __skb_cb_too_small_for_tcp(int, int); |
2030 | extern struct tcp_congestion_ops tcp_reno; | 2069 | extern struct tcp_congestion_ops tcp_reno; |
diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c index 128de4d7c0b7..1b2ff53f98ed 100644 --- a/net/ipv4/tcp_htcp.c +++ b/net/ipv4/tcp_htcp.c | |||
@@ -27,12 +27,12 @@ struct htcp { | |||
27 | u16 alpha; /* Fixed point arith, << 7 */ | 27 | u16 alpha; /* Fixed point arith, << 7 */ |
28 | u8 beta; /* Fixed point arith, << 7 */ | 28 | u8 beta; /* Fixed point arith, << 7 */ |
29 | u8 modeswitch; /* Delay modeswitch until we had at least one congestion event */ | 29 | u8 modeswitch; /* Delay modeswitch until we had at least one congestion event */ |
30 | u8 ccount; /* Number of RTTs since last congestion event */ | 30 | u32 last_cong; /* Time since last congestion event end */ |
31 | u8 undo_ccount; | 31 | u32 undo_last_cong; |
32 | u16 packetcount; | 32 | u16 pkts_acked; |
33 | u32 packetcount; | ||
33 | u32 minRTT; | 34 | u32 minRTT; |
34 | u32 maxRTT; | 35 | u32 maxRTT; |
35 | u32 snd_cwnd_cnt2; | ||
36 | 36 | ||
37 | u32 undo_maxRTT; | 37 | u32 undo_maxRTT; |
38 | u32 undo_old_maxB; | 38 | u32 undo_old_maxB; |
@@ -45,21 +45,30 @@ struct htcp { | |||
45 | u32 lasttime; | 45 | u32 lasttime; |
46 | }; | 46 | }; |
47 | 47 | ||
48 | static inline u32 htcp_cong_time(struct htcp *ca) | ||
49 | { | ||
50 | return jiffies - ca->last_cong; | ||
51 | } | ||
52 | |||
53 | static inline u32 htcp_ccount(struct htcp *ca) | ||
54 | { | ||
55 | return htcp_cong_time(ca)/ca->minRTT; | ||
56 | } | ||
57 | |||
48 | static inline void htcp_reset(struct htcp *ca) | 58 | static inline void htcp_reset(struct htcp *ca) |
49 | { | 59 | { |
50 | ca->undo_ccount = ca->ccount; | 60 | ca->undo_last_cong = ca->last_cong; |
51 | ca->undo_maxRTT = ca->maxRTT; | 61 | ca->undo_maxRTT = ca->maxRTT; |
52 | ca->undo_old_maxB = ca->old_maxB; | 62 | ca->undo_old_maxB = ca->old_maxB; |
53 | 63 | ||
54 | ca->ccount = 0; | 64 | ca->last_cong = jiffies; |
55 | ca->snd_cwnd_cnt2 = 0; | ||
56 | } | 65 | } |
57 | 66 | ||
58 | static u32 htcp_cwnd_undo(struct sock *sk) | 67 | static u32 htcp_cwnd_undo(struct sock *sk) |
59 | { | 68 | { |
60 | const struct tcp_sock *tp = tcp_sk(sk); | 69 | const struct tcp_sock *tp = tcp_sk(sk); |
61 | struct htcp *ca = inet_csk_ca(sk); | 70 | struct htcp *ca = inet_csk_ca(sk); |
62 | ca->ccount = ca->undo_ccount; | 71 | ca->last_cong = ca->undo_last_cong; |
63 | ca->maxRTT = ca->undo_maxRTT; | 72 | ca->maxRTT = ca->undo_maxRTT; |
64 | ca->old_maxB = ca->undo_old_maxB; | 73 | ca->old_maxB = ca->undo_old_maxB; |
65 | return max(tp->snd_cwnd, (tp->snd_ssthresh<<7)/ca->beta); | 74 | return max(tp->snd_cwnd, (tp->snd_ssthresh<<7)/ca->beta); |
@@ -77,10 +86,10 @@ static inline void measure_rtt(struct sock *sk) | |||
77 | ca->minRTT = srtt; | 86 | ca->minRTT = srtt; |
78 | 87 | ||
79 | /* max RTT */ | 88 | /* max RTT */ |
80 | if (icsk->icsk_ca_state == TCP_CA_Open && tp->snd_ssthresh < 0xFFFF && ca->ccount > 3) { | 89 | if (icsk->icsk_ca_state == TCP_CA_Open && tp->snd_ssthresh < 0xFFFF && htcp_ccount(ca) > 3) { |
81 | if (ca->maxRTT < ca->minRTT) | 90 | if (ca->maxRTT < ca->minRTT) |
82 | ca->maxRTT = ca->minRTT; | 91 | ca->maxRTT = ca->minRTT; |
83 | if (ca->maxRTT < srtt && srtt <= ca->maxRTT+HZ/50) | 92 | if (ca->maxRTT < srtt && srtt <= ca->maxRTT+msecs_to_jiffies(20)) |
84 | ca->maxRTT = srtt; | 93 | ca->maxRTT = srtt; |
85 | } | 94 | } |
86 | } | 95 | } |
@@ -92,6 +101,12 @@ static void measure_achieved_throughput(struct sock *sk, u32 pkts_acked) | |||
92 | struct htcp *ca = inet_csk_ca(sk); | 101 | struct htcp *ca = inet_csk_ca(sk); |
93 | u32 now = tcp_time_stamp; | 102 | u32 now = tcp_time_stamp; |
94 | 103 | ||
104 | if (icsk->icsk_ca_state == TCP_CA_Open) | ||
105 | ca->pkts_acked = pkts_acked; | ||
106 | |||
107 | if (!use_bandwidth_switch) | ||
108 | return; | ||
109 | |||
95 | /* achieved throughput calculations */ | 110 | /* achieved throughput calculations */ |
96 | if (icsk->icsk_ca_state != TCP_CA_Open && | 111 | if (icsk->icsk_ca_state != TCP_CA_Open && |
97 | icsk->icsk_ca_state != TCP_CA_Disorder) { | 112 | icsk->icsk_ca_state != TCP_CA_Disorder) { |
@@ -106,7 +121,7 @@ static void measure_achieved_throughput(struct sock *sk, u32 pkts_acked) | |||
106 | && now - ca->lasttime >= ca->minRTT | 121 | && now - ca->lasttime >= ca->minRTT |
107 | && ca->minRTT > 0) { | 122 | && ca->minRTT > 0) { |
108 | __u32 cur_Bi = ca->packetcount*HZ/(now - ca->lasttime); | 123 | __u32 cur_Bi = ca->packetcount*HZ/(now - ca->lasttime); |
109 | if (ca->ccount <= 3) { | 124 | if (htcp_ccount(ca) <= 3) { |
110 | /* just after backoff */ | 125 | /* just after backoff */ |
111 | ca->minB = ca->maxB = ca->Bi = cur_Bi; | 126 | ca->minB = ca->maxB = ca->Bi = cur_Bi; |
112 | } else { | 127 | } else { |
@@ -135,7 +150,7 @@ static inline void htcp_beta_update(struct htcp *ca, u32 minRTT, u32 maxRTT) | |||
135 | } | 150 | } |
136 | } | 151 | } |
137 | 152 | ||
138 | if (ca->modeswitch && minRTT > max(HZ/100, 1) && maxRTT) { | 153 | if (ca->modeswitch && minRTT > msecs_to_jiffies(10) && maxRTT) { |
139 | ca->beta = (minRTT<<7)/maxRTT; | 154 | ca->beta = (minRTT<<7)/maxRTT; |
140 | if (ca->beta < BETA_MIN) | 155 | if (ca->beta < BETA_MIN) |
141 | ca->beta = BETA_MIN; | 156 | ca->beta = BETA_MIN; |
@@ -151,7 +166,7 @@ static inline void htcp_alpha_update(struct htcp *ca) | |||
151 | { | 166 | { |
152 | u32 minRTT = ca->minRTT; | 167 | u32 minRTT = ca->minRTT; |
153 | u32 factor = 1; | 168 | u32 factor = 1; |
154 | u32 diff = ca->ccount * minRTT; /* time since last backoff */ | 169 | u32 diff = htcp_cong_time(ca); |
155 | 170 | ||
156 | if (diff > HZ) { | 171 | if (diff > HZ) { |
157 | diff -= HZ; | 172 | diff -= HZ; |
@@ -216,21 +231,18 @@ static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt, | |||
216 | 231 | ||
217 | measure_rtt(sk); | 232 | measure_rtt(sk); |
218 | 233 | ||
219 | /* keep track of number of round-trip times since last backoff event */ | ||
220 | if (ca->snd_cwnd_cnt2++ > tp->snd_cwnd) { | ||
221 | ca->ccount++; | ||
222 | ca->snd_cwnd_cnt2 = 0; | ||
223 | htcp_alpha_update(ca); | ||
224 | } | ||
225 | |||
226 | /* In dangerous area, increase slowly. | 234 | /* In dangerous area, increase slowly. |
227 | * In theory this is tp->snd_cwnd += alpha / tp->snd_cwnd | 235 | * In theory this is tp->snd_cwnd += alpha / tp->snd_cwnd |
228 | */ | 236 | */ |
229 | if ((tp->snd_cwnd_cnt++ * ca->alpha)>>7 >= tp->snd_cwnd) { | 237 | if ((tp->snd_cwnd_cnt * ca->alpha)>>7 >= tp->snd_cwnd) { |
230 | if (tp->snd_cwnd < tp->snd_cwnd_clamp) | 238 | if (tp->snd_cwnd < tp->snd_cwnd_clamp) |
231 | tp->snd_cwnd++; | 239 | tp->snd_cwnd++; |
232 | tp->snd_cwnd_cnt = 0; | 240 | tp->snd_cwnd_cnt = 0; |
233 | } | 241 | htcp_alpha_update(ca); |
242 | } else | ||
243 | tp->snd_cwnd_cnt += ca->pkts_acked; | ||
244 | |||
245 | ca->pkts_acked = 1; | ||
234 | } | 246 | } |
235 | } | 247 | } |
236 | 248 | ||
@@ -249,11 +261,19 @@ static void htcp_init(struct sock *sk) | |||
249 | memset(ca, 0, sizeof(struct htcp)); | 261 | memset(ca, 0, sizeof(struct htcp)); |
250 | ca->alpha = ALPHA_BASE; | 262 | ca->alpha = ALPHA_BASE; |
251 | ca->beta = BETA_MIN; | 263 | ca->beta = BETA_MIN; |
264 | ca->pkts_acked = 1; | ||
265 | ca->last_cong = jiffies; | ||
252 | } | 266 | } |
253 | 267 | ||
254 | static void htcp_state(struct sock *sk, u8 new_state) | 268 | static void htcp_state(struct sock *sk, u8 new_state) |
255 | { | 269 | { |
256 | switch (new_state) { | 270 | switch (new_state) { |
271 | case TCP_CA_Open: | ||
272 | { | ||
273 | struct htcp *ca = inet_csk_ca(sk); | ||
274 | ca->last_cong = jiffies; | ||
275 | } | ||
276 | break; | ||
257 | case TCP_CA_CWR: | 277 | case TCP_CA_CWR: |
258 | case TCP_CA_Recovery: | 278 | case TCP_CA_Recovery: |
259 | case TCP_CA_Loss: | 279 | case TCP_CA_Loss: |
@@ -278,8 +298,6 @@ static int __init htcp_register(void) | |||
278 | { | 298 | { |
279 | BUG_ON(sizeof(struct htcp) > ICSK_CA_PRIV_SIZE); | 299 | BUG_ON(sizeof(struct htcp) > ICSK_CA_PRIV_SIZE); |
280 | BUILD_BUG_ON(BETA_MIN >= BETA_MAX); | 300 | BUILD_BUG_ON(BETA_MIN >= BETA_MAX); |
281 | if (!use_bandwidth_switch) | ||
282 | htcp.pkts_acked = NULL; | ||
283 | return tcp_register_congestion_control(&htcp); | 301 | return tcp_register_congestion_control(&htcp); |
284 | } | 302 | } |
285 | 303 | ||
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e9a54ae7d690..195d83584558 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -1891,6 +1891,34 @@ static void tcp_try_to_open(struct sock *sk, struct tcp_sock *tp, int flag) | |||
1891 | } | 1891 | } |
1892 | } | 1892 | } |
1893 | 1893 | ||
1894 | static void tcp_mtup_probe_failed(struct sock *sk) | ||
1895 | { | ||
1896 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
1897 | |||
1898 | icsk->icsk_mtup.search_high = icsk->icsk_mtup.probe_size - 1; | ||
1899 | icsk->icsk_mtup.probe_size = 0; | ||
1900 | } | ||
1901 | |||
1902 | static void tcp_mtup_probe_success(struct sock *sk, struct sk_buff *skb) | ||
1903 | { | ||
1904 | struct tcp_sock *tp = tcp_sk(sk); | ||
1905 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
1906 | |||
1907 | /* FIXME: breaks with very large cwnd */ | ||
1908 | tp->prior_ssthresh = tcp_current_ssthresh(sk); | ||
1909 | tp->snd_cwnd = tp->snd_cwnd * | ||
1910 | tcp_mss_to_mtu(sk, tp->mss_cache) / | ||
1911 | icsk->icsk_mtup.probe_size; | ||
1912 | tp->snd_cwnd_cnt = 0; | ||
1913 | tp->snd_cwnd_stamp = tcp_time_stamp; | ||
1914 | tp->rcv_ssthresh = tcp_current_ssthresh(sk); | ||
1915 | |||
1916 | icsk->icsk_mtup.search_low = icsk->icsk_mtup.probe_size; | ||
1917 | icsk->icsk_mtup.probe_size = 0; | ||
1918 | tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); | ||
1919 | } | ||
1920 | |||
1921 | |||
1894 | /* Process an event, which can update packets-in-flight not trivially. | 1922 | /* Process an event, which can update packets-in-flight not trivially. |
1895 | * Main goal of this function is to calculate new estimate for left_out, | 1923 | * Main goal of this function is to calculate new estimate for left_out, |
1896 | * taking into account both packets sitting in receiver's buffer and | 1924 | * taking into account both packets sitting in receiver's buffer and |
@@ -2023,6 +2051,17 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una, | |||
2023 | return; | 2051 | return; |
2024 | } | 2052 | } |
2025 | 2053 | ||
2054 | /* MTU probe failure: don't reduce cwnd */ | ||
2055 | if (icsk->icsk_ca_state < TCP_CA_CWR && | ||
2056 | icsk->icsk_mtup.probe_size && | ||
2057 | tp->snd_una == tp->mtu_probe.probe_seq_start) { | ||
2058 | tcp_mtup_probe_failed(sk); | ||
2059 | /* Restores the reduction we did in tcp_mtup_probe() */ | ||
2060 | tp->snd_cwnd++; | ||
2061 | tcp_simple_retransmit(sk); | ||
2062 | return; | ||
2063 | } | ||
2064 | |||
2026 | /* Otherwise enter Recovery state */ | 2065 | /* Otherwise enter Recovery state */ |
2027 | 2066 | ||
2028 | if (IsReno(tp)) | 2067 | if (IsReno(tp)) |
@@ -2243,6 +2282,13 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) | |||
2243 | tp->retrans_stamp = 0; | 2282 | tp->retrans_stamp = 0; |
2244 | } | 2283 | } |
2245 | 2284 | ||
2285 | /* MTU probing checks */ | ||
2286 | if (icsk->icsk_mtup.probe_size) { | ||
2287 | if (!after(tp->mtu_probe.probe_seq_end, TCP_SKB_CB(skb)->end_seq)) { | ||
2288 | tcp_mtup_probe_success(sk, skb); | ||
2289 | } | ||
2290 | } | ||
2291 | |||
2246 | if (sacked) { | 2292 | if (sacked) { |
2247 | if (sacked & TCPCB_RETRANS) { | 2293 | if (sacked & TCPCB_RETRANS) { |
2248 | if(sacked & TCPCB_SACKED_RETRANS) | 2294 | if(sacked & TCPCB_SACKED_RETRANS) |
@@ -4101,6 +4147,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, | |||
4101 | if (tp->rx_opt.sack_ok && sysctl_tcp_fack) | 4147 | if (tp->rx_opt.sack_ok && sysctl_tcp_fack) |
4102 | tp->rx_opt.sack_ok |= 2; | 4148 | tp->rx_opt.sack_ok |= 2; |
4103 | 4149 | ||
4150 | tcp_mtup_init(sk); | ||
4104 | tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); | 4151 | tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); |
4105 | tcp_initialize_rcv_mss(sk); | 4152 | tcp_initialize_rcv_mss(sk); |
4106 | 4153 | ||
@@ -4211,6 +4258,7 @@ discard: | |||
4211 | if (tp->ecn_flags&TCP_ECN_OK) | 4258 | if (tp->ecn_flags&TCP_ECN_OK) |
4212 | sock_set_flag(sk, SOCK_NO_LARGESEND); | 4259 | sock_set_flag(sk, SOCK_NO_LARGESEND); |
4213 | 4260 | ||
4261 | tcp_mtup_init(sk); | ||
4214 | tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); | 4262 | tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); |
4215 | tcp_initialize_rcv_mss(sk); | 4263 | tcp_initialize_rcv_mss(sk); |
4216 | 4264 | ||
@@ -4399,6 +4447,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
4399 | */ | 4447 | */ |
4400 | tp->lsndtime = tcp_time_stamp; | 4448 | tp->lsndtime = tcp_time_stamp; |
4401 | 4449 | ||
4450 | tcp_mtup_init(sk); | ||
4402 | tcp_initialize_rcv_mss(sk); | 4451 | tcp_initialize_rcv_mss(sk); |
4403 | tcp_init_buffer_space(sk); | 4452 | tcp_init_buffer_space(sk); |
4404 | tcp_fast_path_on(tp); | 4453 | tcp_fast_path_on(tp); |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 233bdf259965..9e85c0416109 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -900,6 +900,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
900 | inet_csk(newsk)->icsk_ext_hdr_len = newinet->opt->optlen; | 900 | inet_csk(newsk)->icsk_ext_hdr_len = newinet->opt->optlen; |
901 | newinet->id = newtp->write_seq ^ jiffies; | 901 | newinet->id = newtp->write_seq ^ jiffies; |
902 | 902 | ||
903 | tcp_mtup_init(newsk); | ||
903 | tcp_sync_mss(newsk, dst_mtu(dst)); | 904 | tcp_sync_mss(newsk, dst_mtu(dst)); |
904 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); | 905 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); |
905 | tcp_initialize_rcv_mss(newsk); | 906 | tcp_initialize_rcv_mss(newsk); |
@@ -1216,17 +1217,21 @@ int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw) | |||
1216 | } | 1217 | } |
1217 | 1218 | ||
1218 | struct inet_connection_sock_af_ops ipv4_specific = { | 1219 | struct inet_connection_sock_af_ops ipv4_specific = { |
1219 | .queue_xmit = ip_queue_xmit, | 1220 | .queue_xmit = ip_queue_xmit, |
1220 | .send_check = tcp_v4_send_check, | 1221 | .send_check = tcp_v4_send_check, |
1221 | .rebuild_header = inet_sk_rebuild_header, | 1222 | .rebuild_header = inet_sk_rebuild_header, |
1222 | .conn_request = tcp_v4_conn_request, | 1223 | .conn_request = tcp_v4_conn_request, |
1223 | .syn_recv_sock = tcp_v4_syn_recv_sock, | 1224 | .syn_recv_sock = tcp_v4_syn_recv_sock, |
1224 | .remember_stamp = tcp_v4_remember_stamp, | 1225 | .remember_stamp = tcp_v4_remember_stamp, |
1225 | .net_header_len = sizeof(struct iphdr), | 1226 | .net_header_len = sizeof(struct iphdr), |
1226 | .setsockopt = ip_setsockopt, | 1227 | .setsockopt = ip_setsockopt, |
1227 | .getsockopt = ip_getsockopt, | 1228 | .getsockopt = ip_getsockopt, |
1228 | .addr2sockaddr = inet_csk_addr2sockaddr, | 1229 | .addr2sockaddr = inet_csk_addr2sockaddr, |
1229 | .sockaddr_len = sizeof(struct sockaddr_in), | 1230 | .sockaddr_len = sizeof(struct sockaddr_in), |
1231 | #ifdef CONFIG_COMPAT | ||
1232 | .compat_setsockopt = compat_ip_setsockopt, | ||
1233 | .compat_getsockopt = compat_ip_getsockopt, | ||
1234 | #endif | ||
1230 | }; | 1235 | }; |
1231 | 1236 | ||
1232 | /* NOTE: A lot of things set to zero explicitly by call to | 1237 | /* NOTE: A lot of things set to zero explicitly by call to |
@@ -1825,23 +1830,16 @@ struct proto tcp_prot = { | |||
1825 | .obj_size = sizeof(struct tcp_sock), | 1830 | .obj_size = sizeof(struct tcp_sock), |
1826 | .twsk_prot = &tcp_timewait_sock_ops, | 1831 | .twsk_prot = &tcp_timewait_sock_ops, |
1827 | .rsk_prot = &tcp_request_sock_ops, | 1832 | .rsk_prot = &tcp_request_sock_ops, |
1833 | #ifdef CONFIG_COMPAT | ||
1834 | .compat_setsockopt = compat_tcp_setsockopt, | ||
1835 | .compat_getsockopt = compat_tcp_getsockopt, | ||
1836 | #endif | ||
1828 | }; | 1837 | }; |
1829 | 1838 | ||
1830 | |||
1831 | |||
1832 | void __init tcp_v4_init(struct net_proto_family *ops) | 1839 | void __init tcp_v4_init(struct net_proto_family *ops) |
1833 | { | 1840 | { |
1834 | int err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_TCP, &tcp_socket); | 1841 | if (inet_csk_ctl_sock_create(&tcp_socket, PF_INET, SOCK_RAW, IPPROTO_TCP) < 0) |
1835 | if (err < 0) | ||
1836 | panic("Failed to create the TCP control socket.\n"); | 1842 | panic("Failed to create the TCP control socket.\n"); |
1837 | tcp_socket->sk->sk_allocation = GFP_ATOMIC; | ||
1838 | inet_sk(tcp_socket->sk)->uc_ttl = -1; | ||
1839 | |||
1840 | /* Unhash it so that IP input processing does not even | ||
1841 | * see it, we do not wish this socket to see incoming | ||
1842 | * packets. | ||
1843 | */ | ||
1844 | tcp_socket->sk->sk_prot->unhash(tcp_socket->sk); | ||
1845 | } | 1843 | } |
1846 | 1844 | ||
1847 | EXPORT_SYMBOL(ipv4_specific); | 1845 | EXPORT_SYMBOL(ipv4_specific); |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 9f498a6c8895..9d79546d384e 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -45,12 +45,23 @@ | |||
45 | /* People can turn this off for buggy TCP's found in printers etc. */ | 45 | /* People can turn this off for buggy TCP's found in printers etc. */ |
46 | int sysctl_tcp_retrans_collapse = 1; | 46 | int sysctl_tcp_retrans_collapse = 1; |
47 | 47 | ||
48 | /* People can turn this on to work with those rare, broken TCPs that | ||
49 | * interpret the window field as a signed quantity. | ||
50 | */ | ||
51 | int sysctl_tcp_workaround_signed_windows = 0; | ||
52 | |||
48 | /* This limits the percentage of the congestion window which we | 53 | /* This limits the percentage of the congestion window which we |
49 | * will allow a single TSO frame to consume. Building TSO frames | 54 | * will allow a single TSO frame to consume. Building TSO frames |
50 | * which are too large can cause TCP streams to be bursty. | 55 | * which are too large can cause TCP streams to be bursty. |
51 | */ | 56 | */ |
52 | int sysctl_tcp_tso_win_divisor = 3; | 57 | int sysctl_tcp_tso_win_divisor = 3; |
53 | 58 | ||
59 | int sysctl_tcp_mtu_probing = 0; | ||
60 | int sysctl_tcp_base_mss = 512; | ||
61 | |||
62 | EXPORT_SYMBOL(sysctl_tcp_mtu_probing); | ||
63 | EXPORT_SYMBOL(sysctl_tcp_base_mss); | ||
64 | |||
54 | static void update_send_head(struct sock *sk, struct tcp_sock *tp, | 65 | static void update_send_head(struct sock *sk, struct tcp_sock *tp, |
55 | struct sk_buff *skb) | 66 | struct sk_buff *skb) |
56 | { | 67 | { |
@@ -171,12 +182,18 @@ void tcp_select_initial_window(int __space, __u32 mss, | |||
171 | space = (space / mss) * mss; | 182 | space = (space / mss) * mss; |
172 | 183 | ||
173 | /* NOTE: offering an initial window larger than 32767 | 184 | /* NOTE: offering an initial window larger than 32767 |
174 | * will break some buggy TCP stacks. We try to be nice. | 185 | * will break some buggy TCP stacks. If the admin tells us |
175 | * If we are not window scaling, then this truncates | 186 | * it is likely we could be speaking with such a buggy stack |
176 | * our initial window offering to 32k. There should also | 187 | * we will truncate our initial window offering to 32K-1 |
177 | * be a sysctl option to stop being nice. | 188 | * unless the remote has sent us a window scaling option, |
189 | * which we interpret as a sign the remote TCP is not | ||
190 | * misinterpreting the window field as a signed quantity. | ||
178 | */ | 191 | */ |
179 | (*rcv_wnd) = min(space, MAX_TCP_WINDOW); | 192 | if (sysctl_tcp_workaround_signed_windows) |
193 | (*rcv_wnd) = min(space, MAX_TCP_WINDOW); | ||
194 | else | ||
195 | (*rcv_wnd) = space; | ||
196 | |||
180 | (*rcv_wscale) = 0; | 197 | (*rcv_wscale) = 0; |
181 | if (wscale_ok) { | 198 | if (wscale_ok) { |
182 | /* Set window scaling on max possible window | 199 | /* Set window scaling on max possible window |
@@ -235,7 +252,7 @@ static u16 tcp_select_window(struct sock *sk) | |||
235 | /* Make sure we do not exceed the maximum possible | 252 | /* Make sure we do not exceed the maximum possible |
236 | * scaled window. | 253 | * scaled window. |
237 | */ | 254 | */ |
238 | if (!tp->rx_opt.rcv_wscale) | 255 | if (!tp->rx_opt.rcv_wscale && sysctl_tcp_workaround_signed_windows) |
239 | new_win = min(new_win, MAX_TCP_WINDOW); | 256 | new_win = min(new_win, MAX_TCP_WINDOW); |
240 | else | 257 | else |
241 | new_win = min(new_win, (65535U << tp->rx_opt.rcv_wscale)); | 258 | new_win = min(new_win, (65535U << tp->rx_opt.rcv_wscale)); |
@@ -681,6 +698,62 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) | |||
681 | return 0; | 698 | return 0; |
682 | } | 699 | } |
683 | 700 | ||
701 | /* Not accounting for SACKs here. */ | ||
702 | int tcp_mtu_to_mss(struct sock *sk, int pmtu) | ||
703 | { | ||
704 | struct tcp_sock *tp = tcp_sk(sk); | ||
705 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
706 | int mss_now; | ||
707 | |||
708 | /* Calculate base mss without TCP options: | ||
709 | It is MMS_S - sizeof(tcphdr) of rfc1122 | ||
710 | */ | ||
711 | mss_now = pmtu - icsk->icsk_af_ops->net_header_len - sizeof(struct tcphdr); | ||
712 | |||
713 | /* Clamp it (mss_clamp does not include tcp options) */ | ||
714 | if (mss_now > tp->rx_opt.mss_clamp) | ||
715 | mss_now = tp->rx_opt.mss_clamp; | ||
716 | |||
717 | /* Now subtract optional transport overhead */ | ||
718 | mss_now -= icsk->icsk_ext_hdr_len; | ||
719 | |||
720 | /* Then reserve room for full set of TCP options and 8 bytes of data */ | ||
721 | if (mss_now < 48) | ||
722 | mss_now = 48; | ||
723 | |||
724 | /* Now subtract TCP options size, not including SACKs */ | ||
725 | mss_now -= tp->tcp_header_len - sizeof(struct tcphdr); | ||
726 | |||
727 | return mss_now; | ||
728 | } | ||
729 | |||
730 | /* Inverse of above */ | ||
731 | int tcp_mss_to_mtu(struct sock *sk, int mss) | ||
732 | { | ||
733 | struct tcp_sock *tp = tcp_sk(sk); | ||
734 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
735 | int mtu; | ||
736 | |||
737 | mtu = mss + | ||
738 | tp->tcp_header_len + | ||
739 | icsk->icsk_ext_hdr_len + | ||
740 | icsk->icsk_af_ops->net_header_len; | ||
741 | |||
742 | return mtu; | ||
743 | } | ||
744 | |||
745 | void tcp_mtup_init(struct sock *sk) | ||
746 | { | ||
747 | struct tcp_sock *tp = tcp_sk(sk); | ||
748 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
749 | |||
750 | icsk->icsk_mtup.enabled = sysctl_tcp_mtu_probing > 1; | ||
751 | icsk->icsk_mtup.search_high = tp->rx_opt.mss_clamp + sizeof(struct tcphdr) + | ||
752 | icsk->icsk_af_ops->net_header_len; | ||
753 | icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, sysctl_tcp_base_mss); | ||
754 | icsk->icsk_mtup.probe_size = 0; | ||
755 | } | ||
756 | |||
684 | /* This function synchronize snd mss to current pmtu/exthdr set. | 757 | /* This function synchronize snd mss to current pmtu/exthdr set. |
685 | 758 | ||
686 | tp->rx_opt.user_mss is mss set by user by TCP_MAXSEG. It does NOT counts | 759 | tp->rx_opt.user_mss is mss set by user by TCP_MAXSEG. It does NOT counts |
@@ -708,25 +781,12 @@ unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu) | |||
708 | { | 781 | { |
709 | struct tcp_sock *tp = tcp_sk(sk); | 782 | struct tcp_sock *tp = tcp_sk(sk); |
710 | struct inet_connection_sock *icsk = inet_csk(sk); | 783 | struct inet_connection_sock *icsk = inet_csk(sk); |
711 | /* Calculate base mss without TCP options: | 784 | int mss_now; |
712 | It is MMS_S - sizeof(tcphdr) of rfc1122 | ||
713 | */ | ||
714 | int mss_now = (pmtu - icsk->icsk_af_ops->net_header_len - | ||
715 | sizeof(struct tcphdr)); | ||
716 | |||
717 | /* Clamp it (mss_clamp does not include tcp options) */ | ||
718 | if (mss_now > tp->rx_opt.mss_clamp) | ||
719 | mss_now = tp->rx_opt.mss_clamp; | ||
720 | |||
721 | /* Now subtract optional transport overhead */ | ||
722 | mss_now -= icsk->icsk_ext_hdr_len; | ||
723 | 785 | ||
724 | /* Then reserve room for full set of TCP options and 8 bytes of data */ | 786 | if (icsk->icsk_mtup.search_high > pmtu) |
725 | if (mss_now < 48) | 787 | icsk->icsk_mtup.search_high = pmtu; |
726 | mss_now = 48; | ||
727 | 788 | ||
728 | /* Now subtract TCP options size, not including SACKs */ | 789 | mss_now = tcp_mtu_to_mss(sk, pmtu); |
729 | mss_now -= tp->tcp_header_len - sizeof(struct tcphdr); | ||
730 | 790 | ||
731 | /* Bound mss with half of window */ | 791 | /* Bound mss with half of window */ |
732 | if (tp->max_window && mss_now > (tp->max_window>>1)) | 792 | if (tp->max_window && mss_now > (tp->max_window>>1)) |
@@ -734,6 +794,8 @@ unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu) | |||
734 | 794 | ||
735 | /* And store cached results */ | 795 | /* And store cached results */ |
736 | icsk->icsk_pmtu_cookie = pmtu; | 796 | icsk->icsk_pmtu_cookie = pmtu; |
797 | if (icsk->icsk_mtup.enabled) | ||
798 | mss_now = min(mss_now, tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low)); | ||
737 | tp->mss_cache = mss_now; | 799 | tp->mss_cache = mss_now; |
738 | 800 | ||
739 | return mss_now; | 801 | return mss_now; |
@@ -1063,6 +1125,140 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_ | |||
1063 | return 1; | 1125 | return 1; |
1064 | } | 1126 | } |
1065 | 1127 | ||
1128 | /* Create a new MTU probe if we are ready. | ||
1129 | * Returns 0 if we should wait to probe (no cwnd available), | ||
1130 | * 1 if a probe was sent, | ||
1131 | * -1 otherwise */ | ||
1132 | static int tcp_mtu_probe(struct sock *sk) | ||
1133 | { | ||
1134 | struct tcp_sock *tp = tcp_sk(sk); | ||
1135 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
1136 | struct sk_buff *skb, *nskb, *next; | ||
1137 | int len; | ||
1138 | int probe_size; | ||
1139 | unsigned int pif; | ||
1140 | int copy; | ||
1141 | int mss_now; | ||
1142 | |||
1143 | /* Not currently probing/verifying, | ||
1144 | * not in recovery, | ||
1145 | * have enough cwnd, and | ||
1146 | * not SACKing (the variable headers throw things off) */ | ||
1147 | if (!icsk->icsk_mtup.enabled || | ||
1148 | icsk->icsk_mtup.probe_size || | ||
1149 | inet_csk(sk)->icsk_ca_state != TCP_CA_Open || | ||
1150 | tp->snd_cwnd < 11 || | ||
1151 | tp->rx_opt.eff_sacks) | ||
1152 | return -1; | ||
1153 | |||
1154 | /* Very simple search strategy: just double the MSS. */ | ||
1155 | mss_now = tcp_current_mss(sk, 0); | ||
1156 | probe_size = 2*tp->mss_cache; | ||
1157 | if (probe_size > tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_high)) { | ||
1158 | /* TODO: set timer for probe_converge_event */ | ||
1159 | return -1; | ||
1160 | } | ||
1161 | |||
1162 | /* Have enough data in the send queue to probe? */ | ||
1163 | len = 0; | ||
1164 | if ((skb = sk->sk_send_head) == NULL) | ||
1165 | return -1; | ||
1166 | while ((len += skb->len) < probe_size && !tcp_skb_is_last(sk, skb)) | ||
1167 | skb = skb->next; | ||
1168 | if (len < probe_size) | ||
1169 | return -1; | ||
1170 | |||
1171 | /* Receive window check. */ | ||
1172 | if (after(TCP_SKB_CB(skb)->seq + probe_size, tp->snd_una + tp->snd_wnd)) { | ||
1173 | if (tp->snd_wnd < probe_size) | ||
1174 | return -1; | ||
1175 | else | ||
1176 | return 0; | ||
1177 | } | ||
1178 | |||
1179 | /* Do we need to wait to drain cwnd? */ | ||
1180 | pif = tcp_packets_in_flight(tp); | ||
1181 | if (pif + 2 > tp->snd_cwnd) { | ||
1182 | /* With no packets in flight, don't stall. */ | ||
1183 | if (pif == 0) | ||
1184 | return -1; | ||
1185 | else | ||
1186 | return 0; | ||
1187 | } | ||
1188 | |||
1189 | /* We're allowed to probe. Build it now. */ | ||
1190 | if ((nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC)) == NULL) | ||
1191 | return -1; | ||
1192 | sk_charge_skb(sk, nskb); | ||
1193 | |||
1194 | skb = sk->sk_send_head; | ||
1195 | __skb_insert(nskb, skb->prev, skb, &sk->sk_write_queue); | ||
1196 | sk->sk_send_head = nskb; | ||
1197 | |||
1198 | TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(skb)->seq; | ||
1199 | TCP_SKB_CB(nskb)->end_seq = TCP_SKB_CB(skb)->seq + probe_size; | ||
1200 | TCP_SKB_CB(nskb)->flags = TCPCB_FLAG_ACK; | ||
1201 | TCP_SKB_CB(nskb)->sacked = 0; | ||
1202 | nskb->csum = 0; | ||
1203 | if (skb->ip_summed == CHECKSUM_HW) | ||
1204 | nskb->ip_summed = CHECKSUM_HW; | ||
1205 | |||
1206 | len = 0; | ||
1207 | while (len < probe_size) { | ||
1208 | next = skb->next; | ||
1209 | |||
1210 | copy = min_t(int, skb->len, probe_size - len); | ||
1211 | if (nskb->ip_summed) | ||
1212 | skb_copy_bits(skb, 0, skb_put(nskb, copy), copy); | ||
1213 | else | ||
1214 | nskb->csum = skb_copy_and_csum_bits(skb, 0, | ||
1215 | skb_put(nskb, copy), copy, nskb->csum); | ||
1216 | |||
1217 | if (skb->len <= copy) { | ||
1218 | /* We've eaten all the data from this skb. | ||
1219 | * Throw it away. */ | ||
1220 | TCP_SKB_CB(nskb)->flags |= TCP_SKB_CB(skb)->flags; | ||
1221 | __skb_unlink(skb, &sk->sk_write_queue); | ||
1222 | sk_stream_free_skb(sk, skb); | ||
1223 | } else { | ||
1224 | TCP_SKB_CB(nskb)->flags |= TCP_SKB_CB(skb)->flags & | ||
1225 | ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH); | ||
1226 | if (!skb_shinfo(skb)->nr_frags) { | ||
1227 | skb_pull(skb, copy); | ||
1228 | if (skb->ip_summed != CHECKSUM_HW) | ||
1229 | skb->csum = csum_partial(skb->data, skb->len, 0); | ||
1230 | } else { | ||
1231 | __pskb_trim_head(skb, copy); | ||
1232 | tcp_set_skb_tso_segs(sk, skb, mss_now); | ||
1233 | } | ||
1234 | TCP_SKB_CB(skb)->seq += copy; | ||
1235 | } | ||
1236 | |||
1237 | len += copy; | ||
1238 | skb = next; | ||
1239 | } | ||
1240 | tcp_init_tso_segs(sk, nskb, nskb->len); | ||
1241 | |||
1242 | /* We're ready to send. If this fails, the probe will | ||
1243 | * be resegmented into mss-sized pieces by tcp_write_xmit(). */ | ||
1244 | TCP_SKB_CB(nskb)->when = tcp_time_stamp; | ||
1245 | if (!tcp_transmit_skb(sk, nskb, 1, GFP_ATOMIC)) { | ||
1246 | /* Decrement cwnd here because we are sending | ||
1247 | * effectively two packets. */ | ||
1248 | tp->snd_cwnd--; | ||
1249 | update_send_head(sk, tp, nskb); | ||
1250 | |||
1251 | icsk->icsk_mtup.probe_size = tcp_mss_to_mtu(sk, nskb->len); | ||
1252 | tp->mtu_probe.probe_seq_start = TCP_SKB_CB(nskb)->seq; | ||
1253 | tp->mtu_probe.probe_seq_end = TCP_SKB_CB(nskb)->end_seq; | ||
1254 | |||
1255 | return 1; | ||
1256 | } | ||
1257 | |||
1258 | return -1; | ||
1259 | } | ||
1260 | |||
1261 | |||
1066 | /* This routine writes packets to the network. It advances the | 1262 | /* This routine writes packets to the network. It advances the |
1067 | * send_head. This happens as incoming acks open up the remote | 1263 | * send_head. This happens as incoming acks open up the remote |
1068 | * window for us. | 1264 | * window for us. |
@@ -1076,6 +1272,7 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle) | |||
1076 | struct sk_buff *skb; | 1272 | struct sk_buff *skb; |
1077 | unsigned int tso_segs, sent_pkts; | 1273 | unsigned int tso_segs, sent_pkts; |
1078 | int cwnd_quota; | 1274 | int cwnd_quota; |
1275 | int result; | ||
1079 | 1276 | ||
1080 | /* If we are closed, the bytes will have to remain here. | 1277 | /* If we are closed, the bytes will have to remain here. |
1081 | * In time closedown will finish, we empty the write queue and all | 1278 | * In time closedown will finish, we empty the write queue and all |
@@ -1085,6 +1282,14 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle) | |||
1085 | return 0; | 1282 | return 0; |
1086 | 1283 | ||
1087 | sent_pkts = 0; | 1284 | sent_pkts = 0; |
1285 | |||
1286 | /* Do MTU probing. */ | ||
1287 | if ((result = tcp_mtu_probe(sk)) == 0) { | ||
1288 | return 0; | ||
1289 | } else if (result > 0) { | ||
1290 | sent_pkts = 1; | ||
1291 | } | ||
1292 | |||
1088 | while ((skb = sk->sk_send_head)) { | 1293 | while ((skb = sk->sk_send_head)) { |
1089 | unsigned int limit; | 1294 | unsigned int limit; |
1090 | 1295 | ||
@@ -1455,9 +1660,15 @@ void tcp_simple_retransmit(struct sock *sk) | |||
1455 | int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) | 1660 | int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) |
1456 | { | 1661 | { |
1457 | struct tcp_sock *tp = tcp_sk(sk); | 1662 | struct tcp_sock *tp = tcp_sk(sk); |
1663 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
1458 | unsigned int cur_mss = tcp_current_mss(sk, 0); | 1664 | unsigned int cur_mss = tcp_current_mss(sk, 0); |
1459 | int err; | 1665 | int err; |
1460 | 1666 | ||
1667 | /* Inconslusive MTU probe */ | ||
1668 | if (icsk->icsk_mtup.probe_size) { | ||
1669 | icsk->icsk_mtup.probe_size = 0; | ||
1670 | } | ||
1671 | |||
1461 | /* Do not sent more than we queued. 1/4 is reserved for possible | 1672 | /* Do not sent more than we queued. 1/4 is reserved for possible |
1462 | * copying overhead: fragmentation, tunneling, mangling etc. | 1673 | * copying overhead: fragmentation, tunneling, mangling etc. |
1463 | */ | 1674 | */ |
@@ -1883,6 +2094,7 @@ static void tcp_connect_init(struct sock *sk) | |||
1883 | if (tp->rx_opt.user_mss) | 2094 | if (tp->rx_opt.user_mss) |
1884 | tp->rx_opt.mss_clamp = tp->rx_opt.user_mss; | 2095 | tp->rx_opt.mss_clamp = tp->rx_opt.user_mss; |
1885 | tp->max_window = 0; | 2096 | tp->max_window = 0; |
2097 | tcp_mtup_init(sk); | ||
1886 | tcp_sync_mss(sk, dst_mtu(dst)); | 2098 | tcp_sync_mss(sk, dst_mtu(dst)); |
1887 | 2099 | ||
1888 | if (!tp->window_clamp) | 2100 | if (!tp->window_clamp) |
@@ -2180,3 +2392,4 @@ EXPORT_SYMBOL(tcp_make_synack); | |||
2180 | EXPORT_SYMBOL(tcp_simple_retransmit); | 2392 | EXPORT_SYMBOL(tcp_simple_retransmit); |
2181 | EXPORT_SYMBOL(tcp_sync_mss); | 2393 | EXPORT_SYMBOL(tcp_sync_mss); |
2182 | EXPORT_SYMBOL(sysctl_tcp_tso_win_divisor); | 2394 | EXPORT_SYMBOL(sysctl_tcp_tso_win_divisor); |
2395 | EXPORT_SYMBOL(tcp_mtup_init); | ||
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index e1880959614a..7c1bde3cd6cb 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c | |||
@@ -119,8 +119,10 @@ static int tcp_orphan_retries(struct sock *sk, int alive) | |||
119 | /* A write timeout has occurred. Process the after effects. */ | 119 | /* A write timeout has occurred. Process the after effects. */ |
120 | static int tcp_write_timeout(struct sock *sk) | 120 | static int tcp_write_timeout(struct sock *sk) |
121 | { | 121 | { |
122 | const struct inet_connection_sock *icsk = inet_csk(sk); | 122 | struct inet_connection_sock *icsk = inet_csk(sk); |
123 | struct tcp_sock *tp = tcp_sk(sk); | ||
123 | int retry_until; | 124 | int retry_until; |
125 | int mss; | ||
124 | 126 | ||
125 | if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { | 127 | if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { |
126 | if (icsk->icsk_retransmits) | 128 | if (icsk->icsk_retransmits) |
@@ -128,25 +130,19 @@ static int tcp_write_timeout(struct sock *sk) | |||
128 | retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries; | 130 | retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries; |
129 | } else { | 131 | } else { |
130 | if (icsk->icsk_retransmits >= sysctl_tcp_retries1) { | 132 | if (icsk->icsk_retransmits >= sysctl_tcp_retries1) { |
131 | /* NOTE. draft-ietf-tcpimpl-pmtud-01.txt requires pmtu black | 133 | /* Black hole detection */ |
132 | hole detection. :-( | 134 | if (sysctl_tcp_mtu_probing) { |
133 | 135 | if (!icsk->icsk_mtup.enabled) { | |
134 | It is place to make it. It is not made. I do not want | 136 | icsk->icsk_mtup.enabled = 1; |
135 | to make it. It is disgusting. It does not work in any | 137 | tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); |
136 | case. Let me to cite the same draft, which requires for | 138 | } else { |
137 | us to implement this: | 139 | mss = min(sysctl_tcp_base_mss, |
138 | 140 | tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low)/2); | |
139 | "The one security concern raised by this memo is that ICMP black holes | 141 | mss = max(mss, 68 - tp->tcp_header_len); |
140 | are often caused by over-zealous security administrators who block | 142 | icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, mss); |
141 | all ICMP messages. It is vitally important that those who design and | 143 | tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); |
142 | deploy security systems understand the impact of strict filtering on | 144 | } |
143 | upper-layer protocols. The safest web site in the world is worthless | 145 | } |
144 | if most TCP implementations cannot transfer data from it. It would | ||
145 | be far nicer to have all of the black holes fixed rather than fixing | ||
146 | all of the TCP implementations." | ||
147 | |||
148 | Golden words :-). | ||
149 | */ | ||
150 | 146 | ||
151 | dst_negative_advice(&sk->sk_dst_cache); | 147 | dst_negative_advice(&sk->sk_dst_cache); |
152 | } | 148 | } |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 00840474a449..3f93292b0ad8 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -1207,16 +1207,13 @@ static int udp_destroy_sock(struct sock *sk) | |||
1207 | /* | 1207 | /* |
1208 | * Socket option code for UDP | 1208 | * Socket option code for UDP |
1209 | */ | 1209 | */ |
1210 | static int udp_setsockopt(struct sock *sk, int level, int optname, | 1210 | static int do_udp_setsockopt(struct sock *sk, int level, int optname, |
1211 | char __user *optval, int optlen) | 1211 | char __user *optval, int optlen) |
1212 | { | 1212 | { |
1213 | struct udp_sock *up = udp_sk(sk); | 1213 | struct udp_sock *up = udp_sk(sk); |
1214 | int val; | 1214 | int val; |
1215 | int err = 0; | 1215 | int err = 0; |
1216 | 1216 | ||
1217 | if (level != SOL_UDP) | ||
1218 | return ip_setsockopt(sk, level, optname, optval, optlen); | ||
1219 | |||
1220 | if(optlen<sizeof(int)) | 1217 | if(optlen<sizeof(int)) |
1221 | return -EINVAL; | 1218 | return -EINVAL; |
1222 | 1219 | ||
@@ -1256,15 +1253,30 @@ static int udp_setsockopt(struct sock *sk, int level, int optname, | |||
1256 | return err; | 1253 | return err; |
1257 | } | 1254 | } |
1258 | 1255 | ||
1259 | static int udp_getsockopt(struct sock *sk, int level, int optname, | 1256 | static int udp_setsockopt(struct sock *sk, int level, int optname, |
1257 | char __user *optval, int optlen) | ||
1258 | { | ||
1259 | if (level != SOL_UDP) | ||
1260 | return ip_setsockopt(sk, level, optname, optval, optlen); | ||
1261 | return do_udp_setsockopt(sk, level, optname, optval, optlen); | ||
1262 | } | ||
1263 | |||
1264 | #ifdef CONFIG_COMPAT | ||
1265 | static int compat_udp_setsockopt(struct sock *sk, int level, int optname, | ||
1266 | char __user *optval, int optlen) | ||
1267 | { | ||
1268 | if (level != SOL_UDP) | ||
1269 | return compat_ip_setsockopt(sk, level, optname, optval, optlen); | ||
1270 | return do_udp_setsockopt(sk, level, optname, optval, optlen); | ||
1271 | } | ||
1272 | #endif | ||
1273 | |||
1274 | static int do_udp_getsockopt(struct sock *sk, int level, int optname, | ||
1260 | char __user *optval, int __user *optlen) | 1275 | char __user *optval, int __user *optlen) |
1261 | { | 1276 | { |
1262 | struct udp_sock *up = udp_sk(sk); | 1277 | struct udp_sock *up = udp_sk(sk); |
1263 | int val, len; | 1278 | int val, len; |
1264 | 1279 | ||
1265 | if (level != SOL_UDP) | ||
1266 | return ip_getsockopt(sk, level, optname, optval, optlen); | ||
1267 | |||
1268 | if(get_user(len,optlen)) | 1280 | if(get_user(len,optlen)) |
1269 | return -EFAULT; | 1281 | return -EFAULT; |
1270 | 1282 | ||
@@ -1293,6 +1305,23 @@ static int udp_getsockopt(struct sock *sk, int level, int optname, | |||
1293 | return 0; | 1305 | return 0; |
1294 | } | 1306 | } |
1295 | 1307 | ||
1308 | static int udp_getsockopt(struct sock *sk, int level, int optname, | ||
1309 | char __user *optval, int __user *optlen) | ||
1310 | { | ||
1311 | if (level != SOL_UDP) | ||
1312 | return ip_getsockopt(sk, level, optname, optval, optlen); | ||
1313 | return do_udp_getsockopt(sk, level, optname, optval, optlen); | ||
1314 | } | ||
1315 | |||
1316 | #ifdef CONFIG_COMPAT | ||
1317 | static int compat_udp_getsockopt(struct sock *sk, int level, int optname, | ||
1318 | char __user *optval, int __user *optlen) | ||
1319 | { | ||
1320 | if (level != SOL_UDP) | ||
1321 | return compat_ip_getsockopt(sk, level, optname, optval, optlen); | ||
1322 | return do_udp_getsockopt(sk, level, optname, optval, optlen); | ||
1323 | } | ||
1324 | #endif | ||
1296 | /** | 1325 | /** |
1297 | * udp_poll - wait for a UDP event. | 1326 | * udp_poll - wait for a UDP event. |
1298 | * @file - file struct | 1327 | * @file - file struct |
@@ -1341,23 +1370,27 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) | |||
1341 | } | 1370 | } |
1342 | 1371 | ||
1343 | struct proto udp_prot = { | 1372 | struct proto udp_prot = { |
1344 | .name = "UDP", | 1373 | .name = "UDP", |
1345 | .owner = THIS_MODULE, | 1374 | .owner = THIS_MODULE, |
1346 | .close = udp_close, | 1375 | .close = udp_close, |
1347 | .connect = ip4_datagram_connect, | 1376 | .connect = ip4_datagram_connect, |
1348 | .disconnect = udp_disconnect, | 1377 | .disconnect = udp_disconnect, |
1349 | .ioctl = udp_ioctl, | 1378 | .ioctl = udp_ioctl, |
1350 | .destroy = udp_destroy_sock, | 1379 | .destroy = udp_destroy_sock, |
1351 | .setsockopt = udp_setsockopt, | 1380 | .setsockopt = udp_setsockopt, |
1352 | .getsockopt = udp_getsockopt, | 1381 | .getsockopt = udp_getsockopt, |
1353 | .sendmsg = udp_sendmsg, | 1382 | .sendmsg = udp_sendmsg, |
1354 | .recvmsg = udp_recvmsg, | 1383 | .recvmsg = udp_recvmsg, |
1355 | .sendpage = udp_sendpage, | 1384 | .sendpage = udp_sendpage, |
1356 | .backlog_rcv = udp_queue_rcv_skb, | 1385 | .backlog_rcv = udp_queue_rcv_skb, |
1357 | .hash = udp_v4_hash, | 1386 | .hash = udp_v4_hash, |
1358 | .unhash = udp_v4_unhash, | 1387 | .unhash = udp_v4_unhash, |
1359 | .get_port = udp_v4_get_port, | 1388 | .get_port = udp_v4_get_port, |
1360 | .obj_size = sizeof(struct udp_sock), | 1389 | .obj_size = sizeof(struct udp_sock), |
1390 | #ifdef CONFIG_COMPAT | ||
1391 | .compat_setsockopt = compat_udp_setsockopt, | ||
1392 | .compat_getsockopt = compat_udp_getsockopt, | ||
1393 | #endif | ||
1361 | }; | 1394 | }; |
1362 | 1395 | ||
1363 | /* ------------------------------------------------------------------------ */ | 1396 | /* ------------------------------------------------------------------------ */ |
diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index afbb0d4cc305..b08d56b117f8 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | #include <linux/skbuff.h> | 6 | #include <linux/skbuff.h> |
7 | #include <linux/module.h> | 7 | #include <linux/module.h> |
8 | #include <linux/mutex.h> | ||
8 | #include <net/xfrm.h> | 9 | #include <net/xfrm.h> |
9 | #include <net/ip.h> | 10 | #include <net/ip.h> |
10 | #include <net/protocol.h> | 11 | #include <net/protocol.h> |
@@ -26,19 +27,19 @@ static int ipip_xfrm_rcv(struct xfrm_state *x, struct xfrm_decap_state *decap, s | |||
26 | } | 27 | } |
27 | 28 | ||
28 | static struct xfrm_tunnel *ipip_handler; | 29 | static struct xfrm_tunnel *ipip_handler; |
29 | static DECLARE_MUTEX(xfrm4_tunnel_sem); | 30 | static DEFINE_MUTEX(xfrm4_tunnel_mutex); |
30 | 31 | ||
31 | int xfrm4_tunnel_register(struct xfrm_tunnel *handler) | 32 | int xfrm4_tunnel_register(struct xfrm_tunnel *handler) |
32 | { | 33 | { |
33 | int ret; | 34 | int ret; |
34 | 35 | ||
35 | down(&xfrm4_tunnel_sem); | 36 | mutex_lock(&xfrm4_tunnel_mutex); |
36 | ret = 0; | 37 | ret = 0; |
37 | if (ipip_handler != NULL) | 38 | if (ipip_handler != NULL) |
38 | ret = -EINVAL; | 39 | ret = -EINVAL; |
39 | if (!ret) | 40 | if (!ret) |
40 | ipip_handler = handler; | 41 | ipip_handler = handler; |
41 | up(&xfrm4_tunnel_sem); | 42 | mutex_unlock(&xfrm4_tunnel_mutex); |
42 | 43 | ||
43 | return ret; | 44 | return ret; |
44 | } | 45 | } |
@@ -49,13 +50,13 @@ int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler) | |||
49 | { | 50 | { |
50 | int ret; | 51 | int ret; |
51 | 52 | ||
52 | down(&xfrm4_tunnel_sem); | 53 | mutex_lock(&xfrm4_tunnel_mutex); |
53 | ret = 0; | 54 | ret = 0; |
54 | if (ipip_handler != handler) | 55 | if (ipip_handler != handler) |
55 | ret = -EINVAL; | 56 | ret = -EINVAL; |
56 | if (!ret) | 57 | if (!ret) |
57 | ipip_handler = NULL; | 58 | ipip_handler = NULL; |
58 | up(&xfrm4_tunnel_sem); | 59 | mutex_unlock(&xfrm4_tunnel_mutex); |
59 | 60 | ||
60 | synchronize_net(); | 61 | synchronize_net(); |
61 | 62 | ||
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index ab7a9124f985..e6f83b6a2b76 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
@@ -6,8 +6,6 @@ | |||
6 | config IPV6 | 6 | config IPV6 |
7 | tristate "The IPv6 protocol" | 7 | tristate "The IPv6 protocol" |
8 | default m | 8 | default m |
9 | select CRYPTO if IPV6_PRIVACY | ||
10 | select CRYPTO_MD5 if IPV6_PRIVACY | ||
11 | ---help--- | 9 | ---help--- |
12 | This is complemental support for the IP version 6. | 10 | This is complemental support for the IP version 6. |
13 | You will still be able to do traditional IPv4 networking as well. | 11 | You will still be able to do traditional IPv4 networking as well. |
@@ -22,7 +20,7 @@ config IPV6 | |||
22 | module will be called ipv6. | 20 | module will be called ipv6. |
23 | 21 | ||
24 | config IPV6_PRIVACY | 22 | config IPV6_PRIVACY |
25 | bool "IPv6: Privacy Extensions (RFC 3041) support" | 23 | bool "IPv6: Privacy Extensions support" |
26 | depends on IPV6 | 24 | depends on IPV6 |
27 | ---help--- | 25 | ---help--- |
28 | Privacy Extensions for Stateless Address Autoconfiguration in IPv6 | 26 | Privacy Extensions for Stateless Address Autoconfiguration in IPv6 |
@@ -30,6 +28,9 @@ config IPV6_PRIVACY | |||
30 | pseudo-random global-scope unicast address(es) will assigned to | 28 | pseudo-random global-scope unicast address(es) will assigned to |
31 | your interface(s). | 29 | your interface(s). |
32 | 30 | ||
31 | We use our standard pseudo random algorithm to generate randomized | ||
32 | interface identifier, instead of one described in RFC 3041. | ||
33 | |||
33 | By default, kernel do not generate temporary addresses. | 34 | By default, kernel do not generate temporary addresses. |
34 | To use temporary addresses, do | 35 | To use temporary addresses, do |
35 | 36 | ||
@@ -37,6 +38,25 @@ config IPV6_PRIVACY | |||
37 | 38 | ||
38 | See <file:Documentation/networking/ip-sysctl.txt> for details. | 39 | See <file:Documentation/networking/ip-sysctl.txt> for details. |
39 | 40 | ||
41 | config IPV6_ROUTER_PREF | ||
42 | bool "IPv6: Router Preference (RFC 4191) support" | ||
43 | depends on IPV6 | ||
44 | ---help--- | ||
45 | Router Preference is an optional extension to the Router | ||
46 | Advertisement message to improve the ability of hosts | ||
47 | to pick more appropriate router, especially when the hosts | ||
48 | is placed in a multi-homed network. | ||
49 | |||
50 | If unsure, say N. | ||
51 | |||
52 | config IPV6_ROUTE_INFO | ||
53 | bool "IPv6: Route Information (RFC 4191) support (EXPERIMENTAL)" | ||
54 | depends on IPV6_ROUTER_PREF && EXPERIMENTAL | ||
55 | ---help--- | ||
56 | This is experimental support of Route Information. | ||
57 | |||
58 | If unsure, say N. | ||
59 | |||
40 | config INET6_AH | 60 | config INET6_AH |
41 | tristate "IPv6: AH transformation" | 61 | tristate "IPv6: AH transformation" |
42 | depends on IPV6 | 62 | depends on IPV6 |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 19727d941962..01c62a0d3742 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -78,8 +78,6 @@ | |||
78 | 78 | ||
79 | #ifdef CONFIG_IPV6_PRIVACY | 79 | #ifdef CONFIG_IPV6_PRIVACY |
80 | #include <linux/random.h> | 80 | #include <linux/random.h> |
81 | #include <linux/crypto.h> | ||
82 | #include <linux/scatterlist.h> | ||
83 | #endif | 81 | #endif |
84 | 82 | ||
85 | #include <asm/uaccess.h> | 83 | #include <asm/uaccess.h> |
@@ -110,8 +108,6 @@ static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpad | |||
110 | static void ipv6_regen_rndid(unsigned long data); | 108 | static void ipv6_regen_rndid(unsigned long data); |
111 | 109 | ||
112 | static int desync_factor = MAX_DESYNC_FACTOR * HZ; | 110 | static int desync_factor = MAX_DESYNC_FACTOR * HZ; |
113 | static struct crypto_tfm *md5_tfm; | ||
114 | static DEFINE_SPINLOCK(md5_tfm_lock); | ||
115 | #endif | 111 | #endif |
116 | 112 | ||
117 | static int ipv6_count_addresses(struct inet6_dev *idev); | 113 | static int ipv6_count_addresses(struct inet6_dev *idev); |
@@ -169,6 +165,15 @@ struct ipv6_devconf ipv6_devconf = { | |||
169 | .max_desync_factor = MAX_DESYNC_FACTOR, | 165 | .max_desync_factor = MAX_DESYNC_FACTOR, |
170 | #endif | 166 | #endif |
171 | .max_addresses = IPV6_MAX_ADDRESSES, | 167 | .max_addresses = IPV6_MAX_ADDRESSES, |
168 | .accept_ra_defrtr = 1, | ||
169 | .accept_ra_pinfo = 1, | ||
170 | #ifdef CONFIG_IPV6_ROUTER_PREF | ||
171 | .accept_ra_rtr_pref = 1, | ||
172 | .rtr_probe_interval = 60 * HZ, | ||
173 | #ifdef CONFIG_IPV6_ROUTE_INFO | ||
174 | .accept_ra_rt_info_max_plen = 0, | ||
175 | #endif | ||
176 | #endif | ||
172 | }; | 177 | }; |
173 | 178 | ||
174 | static struct ipv6_devconf ipv6_devconf_dflt = { | 179 | static struct ipv6_devconf ipv6_devconf_dflt = { |
@@ -190,6 +195,15 @@ static struct ipv6_devconf ipv6_devconf_dflt = { | |||
190 | .max_desync_factor = MAX_DESYNC_FACTOR, | 195 | .max_desync_factor = MAX_DESYNC_FACTOR, |
191 | #endif | 196 | #endif |
192 | .max_addresses = IPV6_MAX_ADDRESSES, | 197 | .max_addresses = IPV6_MAX_ADDRESSES, |
198 | .accept_ra_defrtr = 1, | ||
199 | .accept_ra_pinfo = 1, | ||
200 | #ifdef CONFIG_IPV6_ROUTER_PREF | ||
201 | .accept_ra_rtr_pref = 1, | ||
202 | .rtr_probe_interval = 60 * HZ, | ||
203 | #ifdef CONFIG_IPV6_ROUTE_INFO | ||
204 | .accept_ra_rt_info_max_plen = 0, | ||
205 | #endif | ||
206 | #endif | ||
193 | }; | 207 | }; |
194 | 208 | ||
195 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ | 209 | /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ |
@@ -327,86 +341,83 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |||
327 | if (dev->mtu < IPV6_MIN_MTU) | 341 | if (dev->mtu < IPV6_MIN_MTU) |
328 | return NULL; | 342 | return NULL; |
329 | 343 | ||
330 | ndev = kmalloc(sizeof(struct inet6_dev), GFP_KERNEL); | 344 | ndev = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL); |
331 | 345 | ||
332 | if (ndev) { | 346 | if (ndev == NULL) |
333 | memset(ndev, 0, sizeof(struct inet6_dev)); | 347 | return NULL; |
334 | 348 | ||
335 | rwlock_init(&ndev->lock); | 349 | rwlock_init(&ndev->lock); |
336 | ndev->dev = dev; | 350 | ndev->dev = dev; |
337 | memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf)); | 351 | memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf)); |
338 | ndev->cnf.mtu6 = dev->mtu; | 352 | ndev->cnf.mtu6 = dev->mtu; |
339 | ndev->cnf.sysctl = NULL; | 353 | ndev->cnf.sysctl = NULL; |
340 | ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl); | 354 | ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl); |
341 | if (ndev->nd_parms == NULL) { | 355 | if (ndev->nd_parms == NULL) { |
342 | kfree(ndev); | 356 | kfree(ndev); |
343 | return NULL; | 357 | return NULL; |
344 | } | 358 | } |
345 | /* We refer to the device */ | 359 | /* We refer to the device */ |
346 | dev_hold(dev); | 360 | dev_hold(dev); |
347 | |||
348 | if (snmp6_alloc_dev(ndev) < 0) { | ||
349 | ADBG((KERN_WARNING | ||
350 | "%s(): cannot allocate memory for statistics; dev=%s.\n", | ||
351 | __FUNCTION__, dev->name)); | ||
352 | neigh_parms_release(&nd_tbl, ndev->nd_parms); | ||
353 | ndev->dead = 1; | ||
354 | in6_dev_finish_destroy(ndev); | ||
355 | return NULL; | ||
356 | } | ||
357 | 361 | ||
358 | if (snmp6_register_dev(ndev) < 0) { | 362 | if (snmp6_alloc_dev(ndev) < 0) { |
359 | ADBG((KERN_WARNING | 363 | ADBG((KERN_WARNING |
360 | "%s(): cannot create /proc/net/dev_snmp6/%s\n", | 364 | "%s(): cannot allocate memory for statistics; dev=%s.\n", |
361 | __FUNCTION__, dev->name)); | 365 | __FUNCTION__, dev->name)); |
362 | neigh_parms_release(&nd_tbl, ndev->nd_parms); | 366 | neigh_parms_release(&nd_tbl, ndev->nd_parms); |
363 | ndev->dead = 1; | 367 | ndev->dead = 1; |
364 | in6_dev_finish_destroy(ndev); | 368 | in6_dev_finish_destroy(ndev); |
365 | return NULL; | 369 | return NULL; |
366 | } | 370 | } |
367 | 371 | ||
368 | /* One reference from device. We must do this before | 372 | if (snmp6_register_dev(ndev) < 0) { |
369 | * we invoke __ipv6_regen_rndid(). | 373 | ADBG((KERN_WARNING |
370 | */ | 374 | "%s(): cannot create /proc/net/dev_snmp6/%s\n", |
371 | in6_dev_hold(ndev); | 375 | __FUNCTION__, dev->name)); |
376 | neigh_parms_release(&nd_tbl, ndev->nd_parms); | ||
377 | ndev->dead = 1; | ||
378 | in6_dev_finish_destroy(ndev); | ||
379 | return NULL; | ||
380 | } | ||
381 | |||
382 | /* One reference from device. We must do this before | ||
383 | * we invoke __ipv6_regen_rndid(). | ||
384 | */ | ||
385 | in6_dev_hold(ndev); | ||
372 | 386 | ||
373 | #ifdef CONFIG_IPV6_PRIVACY | 387 | #ifdef CONFIG_IPV6_PRIVACY |
374 | get_random_bytes(ndev->rndid, sizeof(ndev->rndid)); | 388 | init_timer(&ndev->regen_timer); |
375 | get_random_bytes(ndev->entropy, sizeof(ndev->entropy)); | 389 | ndev->regen_timer.function = ipv6_regen_rndid; |
376 | init_timer(&ndev->regen_timer); | 390 | ndev->regen_timer.data = (unsigned long) ndev; |
377 | ndev->regen_timer.function = ipv6_regen_rndid; | 391 | if ((dev->flags&IFF_LOOPBACK) || |
378 | ndev->regen_timer.data = (unsigned long) ndev; | 392 | dev->type == ARPHRD_TUNNEL || |
379 | if ((dev->flags&IFF_LOOPBACK) || | 393 | dev->type == ARPHRD_NONE || |
380 | dev->type == ARPHRD_TUNNEL || | 394 | dev->type == ARPHRD_SIT) { |
381 | dev->type == ARPHRD_NONE || | 395 | printk(KERN_INFO |
382 | dev->type == ARPHRD_SIT) { | 396 | "%s: Disabled Privacy Extensions\n", |
383 | printk(KERN_INFO | 397 | dev->name); |
384 | "%s: Disabled Privacy Extensions\n", | 398 | ndev->cnf.use_tempaddr = -1; |
385 | dev->name); | 399 | } else { |
386 | ndev->cnf.use_tempaddr = -1; | 400 | in6_dev_hold(ndev); |
387 | } else { | 401 | ipv6_regen_rndid((unsigned long) ndev); |
388 | in6_dev_hold(ndev); | 402 | } |
389 | ipv6_regen_rndid((unsigned long) ndev); | ||
390 | } | ||
391 | #endif | 403 | #endif |
392 | 404 | ||
393 | if (netif_carrier_ok(dev)) | 405 | if (netif_carrier_ok(dev)) |
394 | ndev->if_flags |= IF_READY; | 406 | ndev->if_flags |= IF_READY; |
395 | 407 | ||
396 | write_lock_bh(&addrconf_lock); | 408 | write_lock_bh(&addrconf_lock); |
397 | dev->ip6_ptr = ndev; | 409 | dev->ip6_ptr = ndev; |
398 | write_unlock_bh(&addrconf_lock); | 410 | write_unlock_bh(&addrconf_lock); |
399 | 411 | ||
400 | ipv6_mc_init_dev(ndev); | 412 | ipv6_mc_init_dev(ndev); |
401 | ndev->tstamp = jiffies; | 413 | ndev->tstamp = jiffies; |
402 | #ifdef CONFIG_SYSCTL | 414 | #ifdef CONFIG_SYSCTL |
403 | neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6, | 415 | neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6, |
404 | NET_IPV6_NEIGH, "ipv6", | 416 | NET_IPV6_NEIGH, "ipv6", |
405 | &ndisc_ifinfo_sysctl_change, | 417 | &ndisc_ifinfo_sysctl_change, |
406 | NULL); | 418 | NULL); |
407 | addrconf_sysctl_register(ndev, &ndev->cnf); | 419 | addrconf_sysctl_register(ndev, &ndev->cnf); |
408 | #endif | 420 | #endif |
409 | } | ||
410 | return ndev; | 421 | return ndev; |
411 | } | 422 | } |
412 | 423 | ||
@@ -524,7 +535,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
524 | goto out; | 535 | goto out; |
525 | } | 536 | } |
526 | 537 | ||
527 | ifa = kmalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC); | 538 | ifa = kzalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC); |
528 | 539 | ||
529 | if (ifa == NULL) { | 540 | if (ifa == NULL) { |
530 | ADBG(("ipv6_add_addr: malloc failed\n")); | 541 | ADBG(("ipv6_add_addr: malloc failed\n")); |
@@ -538,7 +549,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
538 | goto out; | 549 | goto out; |
539 | } | 550 | } |
540 | 551 | ||
541 | memset(ifa, 0, sizeof(struct inet6_ifaddr)); | ||
542 | ipv6_addr_copy(&ifa->addr, addr); | 552 | ipv6_addr_copy(&ifa->addr, addr); |
543 | 553 | ||
544 | spin_lock_init(&ifa->lock); | 554 | spin_lock_init(&ifa->lock); |
@@ -1305,52 +1315,67 @@ static void addrconf_leave_anycast(struct inet6_ifaddr *ifp) | |||
1305 | __ipv6_dev_ac_dec(ifp->idev, &addr); | 1315 | __ipv6_dev_ac_dec(ifp->idev, &addr); |
1306 | } | 1316 | } |
1307 | 1317 | ||
1318 | static int addrconf_ifid_eui48(u8 *eui, struct net_device *dev) | ||
1319 | { | ||
1320 | if (dev->addr_len != ETH_ALEN) | ||
1321 | return -1; | ||
1322 | memcpy(eui, dev->dev_addr, 3); | ||
1323 | memcpy(eui + 5, dev->dev_addr + 3, 3); | ||
1324 | |||
1325 | /* | ||
1326 | * The zSeries OSA network cards can be shared among various | ||
1327 | * OS instances, but the OSA cards have only one MAC address. | ||
1328 | * This leads to duplicate address conflicts in conjunction | ||
1329 | * with IPv6 if more than one instance uses the same card. | ||
1330 | * | ||
1331 | * The driver for these cards can deliver a unique 16-bit | ||
1332 | * identifier for each instance sharing the same card. It is | ||
1333 | * placed instead of 0xFFFE in the interface identifier. The | ||
1334 | * "u" bit of the interface identifier is not inverted in this | ||
1335 | * case. Hence the resulting interface identifier has local | ||
1336 | * scope according to RFC2373. | ||
1337 | */ | ||
1338 | if (dev->dev_id) { | ||
1339 | eui[3] = (dev->dev_id >> 8) & 0xFF; | ||
1340 | eui[4] = dev->dev_id & 0xFF; | ||
1341 | } else { | ||
1342 | eui[3] = 0xFF; | ||
1343 | eui[4] = 0xFE; | ||
1344 | eui[0] ^= 2; | ||
1345 | } | ||
1346 | return 0; | ||
1347 | } | ||
1348 | |||
1349 | static int addrconf_ifid_arcnet(u8 *eui, struct net_device *dev) | ||
1350 | { | ||
1351 | /* XXX: inherit EUI-64 from other interface -- yoshfuji */ | ||
1352 | if (dev->addr_len != ARCNET_ALEN) | ||
1353 | return -1; | ||
1354 | memset(eui, 0, 7); | ||
1355 | eui[7] = *(u8*)dev->dev_addr; | ||
1356 | return 0; | ||
1357 | } | ||
1358 | |||
1359 | static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev) | ||
1360 | { | ||
1361 | if (dev->addr_len != INFINIBAND_ALEN) | ||
1362 | return -1; | ||
1363 | memcpy(eui, dev->dev_addr + 12, 8); | ||
1364 | eui[0] |= 2; | ||
1365 | return 0; | ||
1366 | } | ||
1367 | |||
1308 | static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) | 1368 | static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) |
1309 | { | 1369 | { |
1310 | switch (dev->type) { | 1370 | switch (dev->type) { |
1311 | case ARPHRD_ETHER: | 1371 | case ARPHRD_ETHER: |
1312 | case ARPHRD_FDDI: | 1372 | case ARPHRD_FDDI: |
1313 | case ARPHRD_IEEE802_TR: | 1373 | case ARPHRD_IEEE802_TR: |
1314 | if (dev->addr_len != ETH_ALEN) | 1374 | return addrconf_ifid_eui48(eui, dev); |
1315 | return -1; | ||
1316 | memcpy(eui, dev->dev_addr, 3); | ||
1317 | memcpy(eui + 5, dev->dev_addr + 3, 3); | ||
1318 | |||
1319 | /* | ||
1320 | * The zSeries OSA network cards can be shared among various | ||
1321 | * OS instances, but the OSA cards have only one MAC address. | ||
1322 | * This leads to duplicate address conflicts in conjunction | ||
1323 | * with IPv6 if more than one instance uses the same card. | ||
1324 | * | ||
1325 | * The driver for these cards can deliver a unique 16-bit | ||
1326 | * identifier for each instance sharing the same card. It is | ||
1327 | * placed instead of 0xFFFE in the interface identifier. The | ||
1328 | * "u" bit of the interface identifier is not inverted in this | ||
1329 | * case. Hence the resulting interface identifier has local | ||
1330 | * scope according to RFC2373. | ||
1331 | */ | ||
1332 | if (dev->dev_id) { | ||
1333 | eui[3] = (dev->dev_id >> 8) & 0xFF; | ||
1334 | eui[4] = dev->dev_id & 0xFF; | ||
1335 | } else { | ||
1336 | eui[3] = 0xFF; | ||
1337 | eui[4] = 0xFE; | ||
1338 | eui[0] ^= 2; | ||
1339 | } | ||
1340 | return 0; | ||
1341 | case ARPHRD_ARCNET: | 1375 | case ARPHRD_ARCNET: |
1342 | /* XXX: inherit EUI-64 from other interface -- yoshfuji */ | 1376 | return addrconf_ifid_arcnet(eui, dev); |
1343 | if (dev->addr_len != ARCNET_ALEN) | ||
1344 | return -1; | ||
1345 | memset(eui, 0, 7); | ||
1346 | eui[7] = *(u8*)dev->dev_addr; | ||
1347 | return 0; | ||
1348 | case ARPHRD_INFINIBAND: | 1377 | case ARPHRD_INFINIBAND: |
1349 | if (dev->addr_len != INFINIBAND_ALEN) | 1378 | return addrconf_ifid_infiniband(eui, dev); |
1350 | return -1; | ||
1351 | memcpy(eui, dev->dev_addr + 12, 8); | ||
1352 | eui[0] |= 2; | ||
1353 | return 0; | ||
1354 | } | 1379 | } |
1355 | return -1; | 1380 | return -1; |
1356 | } | 1381 | } |
@@ -1376,34 +1401,9 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev) | |||
1376 | /* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */ | 1401 | /* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */ |
1377 | static int __ipv6_regen_rndid(struct inet6_dev *idev) | 1402 | static int __ipv6_regen_rndid(struct inet6_dev *idev) |
1378 | { | 1403 | { |
1379 | struct net_device *dev; | ||
1380 | struct scatterlist sg[2]; | ||
1381 | |||
1382 | sg_set_buf(&sg[0], idev->entropy, 8); | ||
1383 | sg_set_buf(&sg[1], idev->work_eui64, 8); | ||
1384 | |||
1385 | dev = idev->dev; | ||
1386 | |||
1387 | if (ipv6_generate_eui64(idev->work_eui64, dev)) { | ||
1388 | printk(KERN_INFO | ||
1389 | "__ipv6_regen_rndid(idev=%p): cannot get EUI64 identifier; use random bytes.\n", | ||
1390 | idev); | ||
1391 | get_random_bytes(idev->work_eui64, sizeof(idev->work_eui64)); | ||
1392 | } | ||
1393 | regen: | 1404 | regen: |
1394 | spin_lock(&md5_tfm_lock); | 1405 | get_random_bytes(idev->rndid, sizeof(idev->rndid)); |
1395 | if (unlikely(md5_tfm == NULL)) { | ||
1396 | spin_unlock(&md5_tfm_lock); | ||
1397 | return -1; | ||
1398 | } | ||
1399 | crypto_digest_init(md5_tfm); | ||
1400 | crypto_digest_update(md5_tfm, sg, 2); | ||
1401 | crypto_digest_final(md5_tfm, idev->work_digest); | ||
1402 | spin_unlock(&md5_tfm_lock); | ||
1403 | |||
1404 | memcpy(idev->rndid, &idev->work_digest[0], 8); | ||
1405 | idev->rndid[0] &= ~0x02; | 1406 | idev->rndid[0] &= ~0x02; |
1406 | memcpy(idev->entropy, &idev->work_digest[8], 8); | ||
1407 | 1407 | ||
1408 | /* | 1408 | /* |
1409 | * <draft-ietf-ipngwg-temp-addresses-v2-00.txt>: | 1409 | * <draft-ietf-ipngwg-temp-addresses-v2-00.txt>: |
@@ -2143,7 +2143,6 @@ static void addrconf_ip6_tnl_config(struct net_device *dev) | |||
2143 | return; | 2143 | return; |
2144 | } | 2144 | } |
2145 | ip6_tnl_add_linklocal(idev); | 2145 | ip6_tnl_add_linklocal(idev); |
2146 | addrconf_add_mroute(dev); | ||
2147 | } | 2146 | } |
2148 | 2147 | ||
2149 | static int addrconf_notify(struct notifier_block *this, unsigned long event, | 2148 | static int addrconf_notify(struct notifier_block *this, unsigned long event, |
@@ -2668,11 +2667,10 @@ static int if6_seq_open(struct inode *inode, struct file *file) | |||
2668 | { | 2667 | { |
2669 | struct seq_file *seq; | 2668 | struct seq_file *seq; |
2670 | int rc = -ENOMEM; | 2669 | int rc = -ENOMEM; |
2671 | struct if6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); | 2670 | struct if6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); |
2672 | 2671 | ||
2673 | if (!s) | 2672 | if (!s) |
2674 | goto out; | 2673 | goto out; |
2675 | memset(s, 0, sizeof(*s)); | ||
2676 | 2674 | ||
2677 | rc = seq_open(file, &if6_seq_ops); | 2675 | rc = seq_open(file, &if6_seq_ops); |
2678 | if (rc) | 2676 | if (rc) |
@@ -3133,6 +3131,15 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
3133 | array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor; | 3131 | array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor; |
3134 | #endif | 3132 | #endif |
3135 | array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses; | 3133 | array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses; |
3134 | array[DEVCONF_ACCEPT_RA_DEFRTR] = cnf->accept_ra_defrtr; | ||
3135 | array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo; | ||
3136 | #ifdef CONFIG_IPV6_ROUTER_PREF | ||
3137 | array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref; | ||
3138 | array[DEVCONF_RTR_PROBE_INTERVAL] = cnf->rtr_probe_interval; | ||
3139 | #ifdef CONFIV_IPV6_ROUTE_INFO | ||
3140 | array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; | ||
3141 | #endif | ||
3142 | #endif | ||
3136 | } | 3143 | } |
3137 | 3144 | ||
3138 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, | 3145 | static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, |
@@ -3586,6 +3593,51 @@ static struct addrconf_sysctl_table | |||
3586 | .proc_handler = &proc_dointvec, | 3593 | .proc_handler = &proc_dointvec, |
3587 | }, | 3594 | }, |
3588 | { | 3595 | { |
3596 | .ctl_name = NET_IPV6_ACCEPT_RA_DEFRTR, | ||
3597 | .procname = "accept_ra_defrtr", | ||
3598 | .data = &ipv6_devconf.accept_ra_defrtr, | ||
3599 | .maxlen = sizeof(int), | ||
3600 | .mode = 0644, | ||
3601 | .proc_handler = &proc_dointvec, | ||
3602 | }, | ||
3603 | { | ||
3604 | .ctl_name = NET_IPV6_ACCEPT_RA_PINFO, | ||
3605 | .procname = "accept_ra_pinfo", | ||
3606 | .data = &ipv6_devconf.accept_ra_pinfo, | ||
3607 | .maxlen = sizeof(int), | ||
3608 | .mode = 0644, | ||
3609 | .proc_handler = &proc_dointvec, | ||
3610 | }, | ||
3611 | #ifdef CONFIG_IPV6_ROUTER_PREF | ||
3612 | { | ||
3613 | .ctl_name = NET_IPV6_ACCEPT_RA_RTR_PREF, | ||
3614 | .procname = "accept_ra_rtr_pref", | ||
3615 | .data = &ipv6_devconf.accept_ra_rtr_pref, | ||
3616 | .maxlen = sizeof(int), | ||
3617 | .mode = 0644, | ||
3618 | .proc_handler = &proc_dointvec, | ||
3619 | }, | ||
3620 | { | ||
3621 | .ctl_name = NET_IPV6_RTR_PROBE_INTERVAL, | ||
3622 | .procname = "router_probe_interval", | ||
3623 | .data = &ipv6_devconf.rtr_probe_interval, | ||
3624 | .maxlen = sizeof(int), | ||
3625 | .mode = 0644, | ||
3626 | .proc_handler = &proc_dointvec_jiffies, | ||
3627 | .strategy = &sysctl_jiffies, | ||
3628 | }, | ||
3629 | #ifdef CONFIV_IPV6_ROUTE_INFO | ||
3630 | { | ||
3631 | .ctl_name = NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN, | ||
3632 | .procname = "accept_ra_rt_info_max_plen", | ||
3633 | .data = &ipv6_devconf.accept_ra_rt_info_max_plen, | ||
3634 | .maxlen = sizeof(int), | ||
3635 | .mode = 0644, | ||
3636 | .proc_handler = &proc_dointvec, | ||
3637 | }, | ||
3638 | #endif | ||
3639 | #endif | ||
3640 | { | ||
3589 | .ctl_name = 0, /* sentinel */ | 3641 | .ctl_name = 0, /* sentinel */ |
3590 | } | 3642 | } |
3591 | }, | 3643 | }, |
@@ -3760,13 +3812,6 @@ int __init addrconf_init(void) | |||
3760 | 3812 | ||
3761 | register_netdevice_notifier(&ipv6_dev_notf); | 3813 | register_netdevice_notifier(&ipv6_dev_notf); |
3762 | 3814 | ||
3763 | #ifdef CONFIG_IPV6_PRIVACY | ||
3764 | md5_tfm = crypto_alloc_tfm("md5", 0); | ||
3765 | if (unlikely(md5_tfm == NULL)) | ||
3766 | printk(KERN_WARNING | ||
3767 | "failed to load transform for md5\n"); | ||
3768 | #endif | ||
3769 | |||
3770 | addrconf_verify(0); | 3815 | addrconf_verify(0); |
3771 | rtnetlink_links[PF_INET6] = inet6_rtnetlink_table; | 3816 | rtnetlink_links[PF_INET6] = inet6_rtnetlink_table; |
3772 | #ifdef CONFIG_SYSCTL | 3817 | #ifdef CONFIG_SYSCTL |
@@ -3829,11 +3874,6 @@ void __exit addrconf_cleanup(void) | |||
3829 | 3874 | ||
3830 | rtnl_unlock(); | 3875 | rtnl_unlock(); |
3831 | 3876 | ||
3832 | #ifdef CONFIG_IPV6_PRIVACY | ||
3833 | crypto_free_tfm(md5_tfm); | ||
3834 | md5_tfm = NULL; | ||
3835 | #endif | ||
3836 | |||
3837 | #ifdef CONFIG_PROC_FS | 3877 | #ifdef CONFIG_PROC_FS |
3838 | proc_net_remove("if_inet6"); | 3878 | proc_net_remove("if_inet6"); |
3839 | #endif | 3879 | #endif |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 6c9711ac1c03..e19457fe4f6e 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -456,45 +456,53 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
456 | } | 456 | } |
457 | 457 | ||
458 | const struct proto_ops inet6_stream_ops = { | 458 | const struct proto_ops inet6_stream_ops = { |
459 | .family = PF_INET6, | 459 | .family = PF_INET6, |
460 | .owner = THIS_MODULE, | 460 | .owner = THIS_MODULE, |
461 | .release = inet6_release, | 461 | .release = inet6_release, |
462 | .bind = inet6_bind, | 462 | .bind = inet6_bind, |
463 | .connect = inet_stream_connect, /* ok */ | 463 | .connect = inet_stream_connect, /* ok */ |
464 | .socketpair = sock_no_socketpair, /* a do nothing */ | 464 | .socketpair = sock_no_socketpair, /* a do nothing */ |
465 | .accept = inet_accept, /* ok */ | 465 | .accept = inet_accept, /* ok */ |
466 | .getname = inet6_getname, | 466 | .getname = inet6_getname, |
467 | .poll = tcp_poll, /* ok */ | 467 | .poll = tcp_poll, /* ok */ |
468 | .ioctl = inet6_ioctl, /* must change */ | 468 | .ioctl = inet6_ioctl, /* must change */ |
469 | .listen = inet_listen, /* ok */ | 469 | .listen = inet_listen, /* ok */ |
470 | .shutdown = inet_shutdown, /* ok */ | 470 | .shutdown = inet_shutdown, /* ok */ |
471 | .setsockopt = sock_common_setsockopt, /* ok */ | 471 | .setsockopt = sock_common_setsockopt, /* ok */ |
472 | .getsockopt = sock_common_getsockopt, /* ok */ | 472 | .getsockopt = sock_common_getsockopt, /* ok */ |
473 | .sendmsg = inet_sendmsg, /* ok */ | 473 | .sendmsg = inet_sendmsg, /* ok */ |
474 | .recvmsg = sock_common_recvmsg, /* ok */ | 474 | .recvmsg = sock_common_recvmsg, /* ok */ |
475 | .mmap = sock_no_mmap, | 475 | .mmap = sock_no_mmap, |
476 | .sendpage = tcp_sendpage | 476 | .sendpage = tcp_sendpage, |
477 | #ifdef CONFIG_COMPAT | ||
478 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
479 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
480 | #endif | ||
477 | }; | 481 | }; |
478 | 482 | ||
479 | const struct proto_ops inet6_dgram_ops = { | 483 | const struct proto_ops inet6_dgram_ops = { |
480 | .family = PF_INET6, | 484 | .family = PF_INET6, |
481 | .owner = THIS_MODULE, | 485 | .owner = THIS_MODULE, |
482 | .release = inet6_release, | 486 | .release = inet6_release, |
483 | .bind = inet6_bind, | 487 | .bind = inet6_bind, |
484 | .connect = inet_dgram_connect, /* ok */ | 488 | .connect = inet_dgram_connect, /* ok */ |
485 | .socketpair = sock_no_socketpair, /* a do nothing */ | 489 | .socketpair = sock_no_socketpair, /* a do nothing */ |
486 | .accept = sock_no_accept, /* a do nothing */ | 490 | .accept = sock_no_accept, /* a do nothing */ |
487 | .getname = inet6_getname, | 491 | .getname = inet6_getname, |
488 | .poll = udp_poll, /* ok */ | 492 | .poll = udp_poll, /* ok */ |
489 | .ioctl = inet6_ioctl, /* must change */ | 493 | .ioctl = inet6_ioctl, /* must change */ |
490 | .listen = sock_no_listen, /* ok */ | 494 | .listen = sock_no_listen, /* ok */ |
491 | .shutdown = inet_shutdown, /* ok */ | 495 | .shutdown = inet_shutdown, /* ok */ |
492 | .setsockopt = sock_common_setsockopt, /* ok */ | 496 | .setsockopt = sock_common_setsockopt, /* ok */ |
493 | .getsockopt = sock_common_getsockopt, /* ok */ | 497 | .getsockopt = sock_common_getsockopt, /* ok */ |
494 | .sendmsg = inet_sendmsg, /* ok */ | 498 | .sendmsg = inet_sendmsg, /* ok */ |
495 | .recvmsg = sock_common_recvmsg, /* ok */ | 499 | .recvmsg = sock_common_recvmsg, /* ok */ |
496 | .mmap = sock_no_mmap, | 500 | .mmap = sock_no_mmap, |
497 | .sendpage = sock_no_sendpage, | 501 | .sendpage = sock_no_sendpage, |
502 | #ifdef CONFIG_COMPAT | ||
503 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
504 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
505 | #endif | ||
498 | }; | 506 | }; |
499 | 507 | ||
500 | static struct net_proto_family inet6_family_ops = { | 508 | static struct net_proto_family inet6_family_ops = { |
@@ -505,24 +513,28 @@ static struct net_proto_family inet6_family_ops = { | |||
505 | 513 | ||
506 | /* Same as inet6_dgram_ops, sans udp_poll. */ | 514 | /* Same as inet6_dgram_ops, sans udp_poll. */ |
507 | static const struct proto_ops inet6_sockraw_ops = { | 515 | static const struct proto_ops inet6_sockraw_ops = { |
508 | .family = PF_INET6, | 516 | .family = PF_INET6, |
509 | .owner = THIS_MODULE, | 517 | .owner = THIS_MODULE, |
510 | .release = inet6_release, | 518 | .release = inet6_release, |
511 | .bind = inet6_bind, | 519 | .bind = inet6_bind, |
512 | .connect = inet_dgram_connect, /* ok */ | 520 | .connect = inet_dgram_connect, /* ok */ |
513 | .socketpair = sock_no_socketpair, /* a do nothing */ | 521 | .socketpair = sock_no_socketpair, /* a do nothing */ |
514 | .accept = sock_no_accept, /* a do nothing */ | 522 | .accept = sock_no_accept, /* a do nothing */ |
515 | .getname = inet6_getname, | 523 | .getname = inet6_getname, |
516 | .poll = datagram_poll, /* ok */ | 524 | .poll = datagram_poll, /* ok */ |
517 | .ioctl = inet6_ioctl, /* must change */ | 525 | .ioctl = inet6_ioctl, /* must change */ |
518 | .listen = sock_no_listen, /* ok */ | 526 | .listen = sock_no_listen, /* ok */ |
519 | .shutdown = inet_shutdown, /* ok */ | 527 | .shutdown = inet_shutdown, /* ok */ |
520 | .setsockopt = sock_common_setsockopt, /* ok */ | 528 | .setsockopt = sock_common_setsockopt, /* ok */ |
521 | .getsockopt = sock_common_getsockopt, /* ok */ | 529 | .getsockopt = sock_common_getsockopt, /* ok */ |
522 | .sendmsg = inet_sendmsg, /* ok */ | 530 | .sendmsg = inet_sendmsg, /* ok */ |
523 | .recvmsg = sock_common_recvmsg, /* ok */ | 531 | .recvmsg = sock_common_recvmsg, /* ok */ |
524 | .mmap = sock_no_mmap, | 532 | .mmap = sock_no_mmap, |
525 | .sendpage = sock_no_sendpage, | 533 | .sendpage = sock_no_sendpage, |
534 | #ifdef CONFIG_COMPAT | ||
535 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
536 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
537 | #endif | ||
526 | }; | 538 | }; |
527 | 539 | ||
528 | static struct inet_protosw rawv6_protosw = { | 540 | static struct inet_protosw rawv6_protosw = { |
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 84963749ab77..cf58251df4b3 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
@@ -213,6 +213,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
213 | ah->reserved = 0; | 213 | ah->reserved = 0; |
214 | ah->spi = x->id.spi; | 214 | ah->spi = x->id.spi; |
215 | ah->seq_no = htonl(++x->replay.oseq); | 215 | ah->seq_no = htonl(++x->replay.oseq); |
216 | xfrm_aevent_doreplay(x); | ||
216 | ahp->icv(ahp, skb, ah->auth_data); | 217 | ahp->icv(ahp, skb, ah->auth_data); |
217 | 218 | ||
218 | err = 0; | 219 | err = 0; |
@@ -353,12 +354,10 @@ static int ah6_init_state(struct xfrm_state *x) | |||
353 | if (x->encap) | 354 | if (x->encap) |
354 | goto error; | 355 | goto error; |
355 | 356 | ||
356 | ahp = kmalloc(sizeof(*ahp), GFP_KERNEL); | 357 | ahp = kzalloc(sizeof(*ahp), GFP_KERNEL); |
357 | if (ahp == NULL) | 358 | if (ahp == NULL) |
358 | return -ENOMEM; | 359 | return -ENOMEM; |
359 | 360 | ||
360 | memset(ahp, 0, sizeof(*ahp)); | ||
361 | |||
362 | ahp->key = x->aalg->alg_key; | 361 | ahp->key = x->aalg->alg_key; |
363 | ahp->key_len = (x->aalg->alg_key_len+7)/8; | 362 | ahp->key_len = (x->aalg->alg_key_len+7)/8; |
364 | ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); | 363 | ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); |
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 840a33d33296..39ec528923f6 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
@@ -308,7 +308,7 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr) | |||
308 | * not found: create a new one. | 308 | * not found: create a new one. |
309 | */ | 309 | */ |
310 | 310 | ||
311 | aca = kmalloc(sizeof(struct ifacaddr6), GFP_ATOMIC); | 311 | aca = kzalloc(sizeof(struct ifacaddr6), GFP_ATOMIC); |
312 | 312 | ||
313 | if (aca == NULL) { | 313 | if (aca == NULL) { |
314 | err = -ENOMEM; | 314 | err = -ENOMEM; |
@@ -322,8 +322,6 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr) | |||
322 | goto out; | 322 | goto out; |
323 | } | 323 | } |
324 | 324 | ||
325 | memset(aca, 0, sizeof(struct ifacaddr6)); | ||
326 | |||
327 | ipv6_addr_copy(&aca->aca_addr, addr); | 325 | ipv6_addr_copy(&aca->aca_addr, addr); |
328 | aca->aca_idev = idev; | 326 | aca->aca_idev = idev; |
329 | aca->aca_rt = rt; | 327 | aca->aca_rt = rt; |
@@ -550,7 +548,7 @@ static int ac6_seq_open(struct inode *inode, struct file *file) | |||
550 | { | 548 | { |
551 | struct seq_file *seq; | 549 | struct seq_file *seq; |
552 | int rc = -ENOMEM; | 550 | int rc = -ENOMEM; |
553 | struct ac6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); | 551 | struct ac6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); |
554 | 552 | ||
555 | if (!s) | 553 | if (!s) |
556 | goto out; | 554 | goto out; |
@@ -561,7 +559,6 @@ static int ac6_seq_open(struct inode *inode, struct file *file) | |||
561 | 559 | ||
562 | seq = file->private_data; | 560 | seq = file->private_data; |
563 | seq->private = s; | 561 | seq->private = s; |
564 | memset(s, 0, sizeof(*s)); | ||
565 | out: | 562 | out: |
566 | return rc; | 563 | return rc; |
567 | out_kfree: | 564 | out_kfree: |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 7b5b94f13902..3dcaac7a0972 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
@@ -94,6 +94,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
94 | 94 | ||
95 | esph->spi = x->id.spi; | 95 | esph->spi = x->id.spi; |
96 | esph->seq_no = htonl(++x->replay.oseq); | 96 | esph->seq_no = htonl(++x->replay.oseq); |
97 | xfrm_aevent_doreplay(x); | ||
97 | 98 | ||
98 | if (esp->conf.ivlen) | 99 | if (esp->conf.ivlen) |
99 | crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); | 100 | crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); |
@@ -304,12 +305,10 @@ static int esp6_init_state(struct xfrm_state *x) | |||
304 | if (x->encap) | 305 | if (x->encap) |
305 | goto error; | 306 | goto error; |
306 | 307 | ||
307 | esp = kmalloc(sizeof(*esp), GFP_KERNEL); | 308 | esp = kzalloc(sizeof(*esp), GFP_KERNEL); |
308 | if (esp == NULL) | 309 | if (esp == NULL) |
309 | return -ENOMEM; | 310 | return -ENOMEM; |
310 | 311 | ||
311 | memset(esp, 0, sizeof(*esp)); | ||
312 | |||
313 | if (x->aalg) { | 312 | if (x->aalg) { |
314 | struct xfrm_algo_desc *aalg_desc; | 313 | struct xfrm_algo_desc *aalg_desc; |
315 | 314 | ||
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 1bf6d9a769e6..2cb6149349bf 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -1105,7 +1105,6 @@ static int fib6_age(struct rt6_info *rt, void *arg) | |||
1105 | if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) { | 1105 | if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) { |
1106 | if (time_after(now, rt->rt6i_expires)) { | 1106 | if (time_after(now, rt->rt6i_expires)) { |
1107 | RT6_TRACE("expiring %p\n", rt); | 1107 | RT6_TRACE("expiring %p\n", rt); |
1108 | rt6_reset_dflt_pointer(rt); | ||
1109 | return -1; | 1108 | return -1; |
1110 | } | 1109 | } |
1111 | gc_args.more++; | 1110 | gc_args.more++; |
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 69cbe8a66d02..f9ca63912fbf 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -287,10 +287,9 @@ fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int * | |||
287 | int err; | 287 | int err; |
288 | 288 | ||
289 | err = -ENOMEM; | 289 | err = -ENOMEM; |
290 | fl = kmalloc(sizeof(*fl), GFP_KERNEL); | 290 | fl = kzalloc(sizeof(*fl), GFP_KERNEL); |
291 | if (fl == NULL) | 291 | if (fl == NULL) |
292 | goto done; | 292 | goto done; |
293 | memset(fl, 0, sizeof(*fl)); | ||
294 | 293 | ||
295 | olen = optlen - CMSG_ALIGN(sizeof(*freq)); | 294 | olen = optlen - CMSG_ALIGN(sizeof(*freq)); |
296 | if (olen > 0) { | 295 | if (olen > 0) { |
@@ -663,7 +662,7 @@ static int ip6fl_seq_open(struct inode *inode, struct file *file) | |||
663 | { | 662 | { |
664 | struct seq_file *seq; | 663 | struct seq_file *seq; |
665 | int rc = -ENOMEM; | 664 | int rc = -ENOMEM; |
666 | struct ip6fl_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); | 665 | struct ip6fl_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); |
667 | 666 | ||
668 | if (!s) | 667 | if (!s) |
669 | goto out; | 668 | goto out; |
@@ -674,7 +673,6 @@ static int ip6fl_seq_open(struct inode *inode, struct file *file) | |||
674 | 673 | ||
675 | seq = file->private_data; | 674 | seq = file->private_data; |
676 | seq->private = s; | 675 | seq->private = s; |
677 | memset(s, 0, sizeof(*s)); | ||
678 | out: | 676 | out: |
679 | return rc; | 677 | return rc; |
680 | out_kfree: | 678 | out_kfree: |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 5bf70b1442ea..e46048974f37 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -161,7 +161,7 @@ int ip6_output(struct sk_buff *skb) | |||
161 | int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | 161 | int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, |
162 | struct ipv6_txoptions *opt, int ipfragok) | 162 | struct ipv6_txoptions *opt, int ipfragok) |
163 | { | 163 | { |
164 | struct ipv6_pinfo *np = sk ? inet6_sk(sk) : NULL; | 164 | struct ipv6_pinfo *np = inet6_sk(sk); |
165 | struct in6_addr *first_hop = &fl->fl6_dst; | 165 | struct in6_addr *first_hop = &fl->fl6_dst; |
166 | struct dst_entry *dst = skb->dst; | 166 | struct dst_entry *dst = skb->dst; |
167 | struct ipv6hdr *hdr; | 167 | struct ipv6hdr *hdr; |
@@ -733,28 +733,29 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl) | |||
733 | if (*dst) { | 733 | if (*dst) { |
734 | struct rt6_info *rt = (struct rt6_info*)*dst; | 734 | struct rt6_info *rt = (struct rt6_info*)*dst; |
735 | 735 | ||
736 | /* Yes, checking route validity in not connected | 736 | /* Yes, checking route validity in not connected |
737 | case is not very simple. Take into account, | 737 | * case is not very simple. Take into account, |
738 | that we do not support routing by source, TOS, | 738 | * that we do not support routing by source, TOS, |
739 | and MSG_DONTROUTE --ANK (980726) | 739 | * and MSG_DONTROUTE --ANK (980726) |
740 | 740 | * | |
741 | 1. If route was host route, check that | 741 | * 1. If route was host route, check that |
742 | cached destination is current. | 742 | * cached destination is current. |
743 | If it is network route, we still may | 743 | * If it is network route, we still may |
744 | check its validity using saved pointer | 744 | * check its validity using saved pointer |
745 | to the last used address: daddr_cache. | 745 | * to the last used address: daddr_cache. |
746 | We do not want to save whole address now, | 746 | * We do not want to save whole address now, |
747 | (because main consumer of this service | 747 | * (because main consumer of this service |
748 | is tcp, which has not this problem), | 748 | * is tcp, which has not this problem), |
749 | so that the last trick works only on connected | 749 | * so that the last trick works only on connected |
750 | sockets. | 750 | * sockets. |
751 | 2. oif also should be the same. | 751 | * 2. oif also should be the same. |
752 | */ | 752 | */ |
753 | |||
754 | if (((rt->rt6i_dst.plen != 128 || | 753 | if (((rt->rt6i_dst.plen != 128 || |
755 | !ipv6_addr_equal(&fl->fl6_dst, &rt->rt6i_dst.addr)) | 754 | !ipv6_addr_equal(&fl->fl6_dst, |
755 | &rt->rt6i_dst.addr)) | ||
756 | && (np->daddr_cache == NULL || | 756 | && (np->daddr_cache == NULL || |
757 | !ipv6_addr_equal(&fl->fl6_dst, np->daddr_cache))) | 757 | !ipv6_addr_equal(&fl->fl6_dst, |
758 | np->daddr_cache))) | ||
758 | || (fl->oif && fl->oif != (*dst)->dev->ifindex)) { | 759 | || (fl->oif && fl->oif != (*dst)->dev->ifindex)) { |
759 | dst_release(*dst); | 760 | dst_release(*dst); |
760 | *dst = NULL; | 761 | *dst = NULL; |
@@ -889,7 +890,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | |||
889 | np->cork.hop_limit = hlimit; | 890 | np->cork.hop_limit = hlimit; |
890 | np->cork.tclass = tclass; | 891 | np->cork.tclass = tclass; |
891 | mtu = dst_mtu(rt->u.dst.path); | 892 | mtu = dst_mtu(rt->u.dst.path); |
892 | if (np && np->frag_size < mtu) { | 893 | if (np->frag_size < mtu) { |
893 | if (np->frag_size) | 894 | if (np->frag_size) |
894 | mtu = np->frag_size; | 895 | mtu = np->frag_size; |
895 | } | 896 | } |
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index d511a884dad0..028b636687ec 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <net/protocol.h> | 50 | #include <net/protocol.h> |
51 | #include <linux/ipv6.h> | 51 | #include <linux/ipv6.h> |
52 | #include <linux/icmpv6.h> | 52 | #include <linux/icmpv6.h> |
53 | #include <linux/mutex.h> | ||
53 | 54 | ||
54 | struct ipcomp6_tfms { | 55 | struct ipcomp6_tfms { |
55 | struct list_head list; | 56 | struct list_head list; |
@@ -57,7 +58,7 @@ struct ipcomp6_tfms { | |||
57 | int users; | 58 | int users; |
58 | }; | 59 | }; |
59 | 60 | ||
60 | static DECLARE_MUTEX(ipcomp6_resource_sem); | 61 | static DEFINE_MUTEX(ipcomp6_resource_mutex); |
61 | static void **ipcomp6_scratches; | 62 | static void **ipcomp6_scratches; |
62 | static int ipcomp6_scratch_users; | 63 | static int ipcomp6_scratch_users; |
63 | static LIST_HEAD(ipcomp6_tfms_list); | 64 | static LIST_HEAD(ipcomp6_tfms_list); |
@@ -286,8 +287,8 @@ static void ipcomp6_free_scratches(void) | |||
286 | 287 | ||
287 | for_each_cpu(i) { | 288 | for_each_cpu(i) { |
288 | void *scratch = *per_cpu_ptr(scratches, i); | 289 | void *scratch = *per_cpu_ptr(scratches, i); |
289 | if (scratch) | 290 | |
290 | vfree(scratch); | 291 | vfree(scratch); |
291 | } | 292 | } |
292 | 293 | ||
293 | free_percpu(scratches); | 294 | free_percpu(scratches); |
@@ -405,9 +406,9 @@ static void ipcomp6_destroy(struct xfrm_state *x) | |||
405 | if (!ipcd) | 406 | if (!ipcd) |
406 | return; | 407 | return; |
407 | xfrm_state_delete_tunnel(x); | 408 | xfrm_state_delete_tunnel(x); |
408 | down(&ipcomp6_resource_sem); | 409 | mutex_lock(&ipcomp6_resource_mutex); |
409 | ipcomp6_free_data(ipcd); | 410 | ipcomp6_free_data(ipcd); |
410 | up(&ipcomp6_resource_sem); | 411 | mutex_unlock(&ipcomp6_resource_mutex); |
411 | kfree(ipcd); | 412 | kfree(ipcd); |
412 | 413 | ||
413 | xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr); | 414 | xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr); |
@@ -427,23 +428,22 @@ static int ipcomp6_init_state(struct xfrm_state *x) | |||
427 | goto out; | 428 | goto out; |
428 | 429 | ||
429 | err = -ENOMEM; | 430 | err = -ENOMEM; |
430 | ipcd = kmalloc(sizeof(*ipcd), GFP_KERNEL); | 431 | ipcd = kzalloc(sizeof(*ipcd), GFP_KERNEL); |
431 | if (!ipcd) | 432 | if (!ipcd) |
432 | goto out; | 433 | goto out; |
433 | 434 | ||
434 | memset(ipcd, 0, sizeof(*ipcd)); | ||
435 | x->props.header_len = 0; | 435 | x->props.header_len = 0; |
436 | if (x->props.mode) | 436 | if (x->props.mode) |
437 | x->props.header_len += sizeof(struct ipv6hdr); | 437 | x->props.header_len += sizeof(struct ipv6hdr); |
438 | 438 | ||
439 | down(&ipcomp6_resource_sem); | 439 | mutex_lock(&ipcomp6_resource_mutex); |
440 | if (!ipcomp6_alloc_scratches()) | 440 | if (!ipcomp6_alloc_scratches()) |
441 | goto error; | 441 | goto error; |
442 | 442 | ||
443 | ipcd->tfms = ipcomp6_alloc_tfms(x->calg->alg_name); | 443 | ipcd->tfms = ipcomp6_alloc_tfms(x->calg->alg_name); |
444 | if (!ipcd->tfms) | 444 | if (!ipcd->tfms) |
445 | goto error; | 445 | goto error; |
446 | up(&ipcomp6_resource_sem); | 446 | mutex_unlock(&ipcomp6_resource_mutex); |
447 | 447 | ||
448 | if (x->props.mode) { | 448 | if (x->props.mode) { |
449 | err = ipcomp6_tunnel_attach(x); | 449 | err = ipcomp6_tunnel_attach(x); |
@@ -459,10 +459,10 @@ static int ipcomp6_init_state(struct xfrm_state *x) | |||
459 | out: | 459 | out: |
460 | return err; | 460 | return err; |
461 | error_tunnel: | 461 | error_tunnel: |
462 | down(&ipcomp6_resource_sem); | 462 | mutex_lock(&ipcomp6_resource_mutex); |
463 | error: | 463 | error: |
464 | ipcomp6_free_data(ipcd); | 464 | ipcomp6_free_data(ipcd); |
465 | up(&ipcomp6_resource_sem); | 465 | mutex_unlock(&ipcomp6_resource_mutex); |
466 | kfree(ipcd); | 466 | kfree(ipcd); |
467 | 467 | ||
468 | goto out; | 468 | goto out; |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index f7142ba519ab..4c20eeb3d568 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -109,19 +109,13 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *)) | |||
109 | return 0; | 109 | return 0; |
110 | } | 110 | } |
111 | 111 | ||
112 | int ipv6_setsockopt(struct sock *sk, int level, int optname, | 112 | static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, |
113 | char __user *optval, int optlen) | 113 | char __user *optval, int optlen) |
114 | { | 114 | { |
115 | struct ipv6_pinfo *np = inet6_sk(sk); | 115 | struct ipv6_pinfo *np = inet6_sk(sk); |
116 | int val, valbool; | 116 | int val, valbool; |
117 | int retv = -ENOPROTOOPT; | 117 | int retv = -ENOPROTOOPT; |
118 | 118 | ||
119 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
120 | return udp_prot.setsockopt(sk, level, optname, optval, optlen); | ||
121 | |||
122 | if(level!=SOL_IPV6) | ||
123 | goto out; | ||
124 | |||
125 | if (optval == NULL) | 119 | if (optval == NULL) |
126 | val=0; | 120 | val=0; |
127 | else if (get_user(val, (int __user *) optval)) | 121 | else if (get_user(val, (int __user *) optval)) |
@@ -613,17 +607,9 @@ done: | |||
613 | retv = xfrm_user_policy(sk, optname, optval, optlen); | 607 | retv = xfrm_user_policy(sk, optname, optval, optlen); |
614 | break; | 608 | break; |
615 | 609 | ||
616 | #ifdef CONFIG_NETFILTER | ||
617 | default: | ||
618 | retv = nf_setsockopt(sk, PF_INET6, optname, optval, | ||
619 | optlen); | ||
620 | break; | ||
621 | #endif | ||
622 | |||
623 | } | 610 | } |
624 | release_sock(sk); | 611 | release_sock(sk); |
625 | 612 | ||
626 | out: | ||
627 | return retv; | 613 | return retv; |
628 | 614 | ||
629 | e_inval: | 615 | e_inval: |
@@ -631,6 +617,65 @@ e_inval: | |||
631 | return -EINVAL; | 617 | return -EINVAL; |
632 | } | 618 | } |
633 | 619 | ||
620 | int ipv6_setsockopt(struct sock *sk, int level, int optname, | ||
621 | char __user *optval, int optlen) | ||
622 | { | ||
623 | int err; | ||
624 | |||
625 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
626 | return udp_prot.setsockopt(sk, level, optname, optval, optlen); | ||
627 | |||
628 | if (level != SOL_IPV6) | ||
629 | return -ENOPROTOOPT; | ||
630 | |||
631 | err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); | ||
632 | #ifdef CONFIG_NETFILTER | ||
633 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
634 | if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && | ||
635 | optname != IPV6_XFRM_POLICY) { | ||
636 | lock_sock(sk); | ||
637 | err = nf_setsockopt(sk, PF_INET6, optname, optval, | ||
638 | optlen); | ||
639 | release_sock(sk); | ||
640 | } | ||
641 | #endif | ||
642 | return err; | ||
643 | } | ||
644 | |||
645 | |||
646 | #ifdef CONFIG_COMPAT | ||
647 | int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, | ||
648 | char __user *optval, int optlen) | ||
649 | { | ||
650 | int err; | ||
651 | |||
652 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) { | ||
653 | if (udp_prot.compat_setsockopt != NULL) | ||
654 | return udp_prot.compat_setsockopt(sk, level, optname, | ||
655 | optval, optlen); | ||
656 | return udp_prot.setsockopt(sk, level, optname, optval, optlen); | ||
657 | } | ||
658 | |||
659 | if (level != SOL_IPV6) | ||
660 | return -ENOPROTOOPT; | ||
661 | |||
662 | err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); | ||
663 | #ifdef CONFIG_NETFILTER | ||
664 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
665 | if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && | ||
666 | optname != IPV6_XFRM_POLICY) { | ||
667 | lock_sock(sk); | ||
668 | err = compat_nf_setsockopt(sk, PF_INET6, optname, | ||
669 | optval, optlen); | ||
670 | release_sock(sk); | ||
671 | } | ||
672 | #endif | ||
673 | return err; | ||
674 | } | ||
675 | |||
676 | EXPORT_SYMBOL(compat_ipv6_setsockopt); | ||
677 | #endif | ||
678 | |||
634 | static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, | 679 | static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, |
635 | char __user *optval, int len) | 680 | char __user *optval, int len) |
636 | { | 681 | { |
@@ -642,17 +687,13 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, | |||
642 | return len; | 687 | return len; |
643 | } | 688 | } |
644 | 689 | ||
645 | int ipv6_getsockopt(struct sock *sk, int level, int optname, | 690 | static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, |
646 | char __user *optval, int __user *optlen) | 691 | char __user *optval, int __user *optlen) |
647 | { | 692 | { |
648 | struct ipv6_pinfo *np = inet6_sk(sk); | 693 | struct ipv6_pinfo *np = inet6_sk(sk); |
649 | int len; | 694 | int len; |
650 | int val; | 695 | int val; |
651 | 696 | ||
652 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
653 | return udp_prot.getsockopt(sk, level, optname, optval, optlen); | ||
654 | if(level!=SOL_IPV6) | ||
655 | return -ENOPROTOOPT; | ||
656 | if (get_user(len, optlen)) | 697 | if (get_user(len, optlen)) |
657 | return -EFAULT; | 698 | return -EFAULT; |
658 | switch (optname) { | 699 | switch (optname) { |
@@ -842,17 +883,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
842 | break; | 883 | break; |
843 | 884 | ||
844 | default: | 885 | default: |
845 | #ifdef CONFIG_NETFILTER | ||
846 | lock_sock(sk); | ||
847 | val = nf_getsockopt(sk, PF_INET6, optname, optval, | ||
848 | &len); | ||
849 | release_sock(sk); | ||
850 | if (val >= 0) | ||
851 | val = put_user(len, optlen); | ||
852 | return val; | ||
853 | #else | ||
854 | return -EINVAL; | 886 | return -EINVAL; |
855 | #endif | ||
856 | } | 887 | } |
857 | len = min_t(unsigned int, sizeof(int), len); | 888 | len = min_t(unsigned int, sizeof(int), len); |
858 | if(put_user(len, optlen)) | 889 | if(put_user(len, optlen)) |
@@ -862,6 +893,78 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
862 | return 0; | 893 | return 0; |
863 | } | 894 | } |
864 | 895 | ||
896 | int ipv6_getsockopt(struct sock *sk, int level, int optname, | ||
897 | char __user *optval, int __user *optlen) | ||
898 | { | ||
899 | int err; | ||
900 | |||
901 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
902 | return udp_prot.getsockopt(sk, level, optname, optval, optlen); | ||
903 | |||
904 | if(level != SOL_IPV6) | ||
905 | return -ENOPROTOOPT; | ||
906 | |||
907 | err = do_ipv6_getsockopt(sk, level, optname, optval, optlen); | ||
908 | #ifdef CONFIG_NETFILTER | ||
909 | /* we need to exclude all possible EINVALs except default case */ | ||
910 | if (err == -EINVAL && optname != IPV6_ADDRFORM && | ||
911 | optname != MCAST_MSFILTER) { | ||
912 | int len; | ||
913 | |||
914 | if (get_user(len, optlen)) | ||
915 | return -EFAULT; | ||
916 | |||
917 | lock_sock(sk); | ||
918 | err = nf_getsockopt(sk, PF_INET6, optname, optval, | ||
919 | &len); | ||
920 | release_sock(sk); | ||
921 | if (err >= 0) | ||
922 | err = put_user(len, optlen); | ||
923 | } | ||
924 | #endif | ||
925 | return err; | ||
926 | } | ||
927 | |||
928 | #ifdef CONFIG_COMPAT | ||
929 | int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, | ||
930 | char __user *optval, int __user *optlen) | ||
931 | { | ||
932 | int err; | ||
933 | |||
934 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) { | ||
935 | if (udp_prot.compat_getsockopt != NULL) | ||
936 | return udp_prot.compat_getsockopt(sk, level, optname, | ||
937 | optval, optlen); | ||
938 | return udp_prot.getsockopt(sk, level, optname, optval, optlen); | ||
939 | } | ||
940 | |||
941 | if (level != SOL_IPV6) | ||
942 | return -ENOPROTOOPT; | ||
943 | |||
944 | err = do_ipv6_getsockopt(sk, level, optname, optval, optlen); | ||
945 | #ifdef CONFIG_NETFILTER | ||
946 | /* we need to exclude all possible EINVALs except default case */ | ||
947 | if (err == -EINVAL && optname != IPV6_ADDRFORM && | ||
948 | optname != MCAST_MSFILTER) { | ||
949 | int len; | ||
950 | |||
951 | if (get_user(len, optlen)) | ||
952 | return -EFAULT; | ||
953 | |||
954 | lock_sock(sk); | ||
955 | err = compat_nf_getsockopt(sk, PF_INET6, | ||
956 | optname, optval, &len); | ||
957 | release_sock(sk); | ||
958 | if (err >= 0) | ||
959 | err = put_user(len, optlen); | ||
960 | } | ||
961 | #endif | ||
962 | return err; | ||
963 | } | ||
964 | |||
965 | EXPORT_SYMBOL(compat_ipv6_getsockopt); | ||
966 | #endif | ||
967 | |||
865 | void __init ipv6_packet_init(void) | 968 | void __init ipv6_packet_init(void) |
866 | { | 969 | { |
867 | dev_add_pack(&ipv6_packet_type); | 970 | dev_add_pack(&ipv6_packet_type); |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 807c021d64a2..6e871afbb2c7 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -767,10 +767,10 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) | |||
767 | * for deleted items allows change reports to use common code with | 767 | * for deleted items allows change reports to use common code with |
768 | * non-deleted or query-response MCA's. | 768 | * non-deleted or query-response MCA's. |
769 | */ | 769 | */ |
770 | pmc = kmalloc(sizeof(*pmc), GFP_ATOMIC); | 770 | pmc = kzalloc(sizeof(*pmc), GFP_ATOMIC); |
771 | if (!pmc) | 771 | if (!pmc) |
772 | return; | 772 | return; |
773 | memset(pmc, 0, sizeof(*pmc)); | 773 | |
774 | spin_lock_bh(&im->mca_lock); | 774 | spin_lock_bh(&im->mca_lock); |
775 | spin_lock_init(&pmc->mca_lock); | 775 | spin_lock_init(&pmc->mca_lock); |
776 | pmc->idev = im->idev; | 776 | pmc->idev = im->idev; |
@@ -893,7 +893,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr) | |||
893 | * not found: create a new one. | 893 | * not found: create a new one. |
894 | */ | 894 | */ |
895 | 895 | ||
896 | mc = kmalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC); | 896 | mc = kzalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC); |
897 | 897 | ||
898 | if (mc == NULL) { | 898 | if (mc == NULL) { |
899 | write_unlock_bh(&idev->lock); | 899 | write_unlock_bh(&idev->lock); |
@@ -901,7 +901,6 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr) | |||
901 | return -ENOMEM; | 901 | return -ENOMEM; |
902 | } | 902 | } |
903 | 903 | ||
904 | memset(mc, 0, sizeof(struct ifmcaddr6)); | ||
905 | init_timer(&mc->mca_timer); | 904 | init_timer(&mc->mca_timer); |
906 | mc->mca_timer.function = igmp6_timer_handler; | 905 | mc->mca_timer.function = igmp6_timer_handler; |
907 | mc->mca_timer.data = (unsigned long) mc; | 906 | mc->mca_timer.data = (unsigned long) mc; |
@@ -1934,10 +1933,10 @@ static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode, | |||
1934 | psf_prev = psf; | 1933 | psf_prev = psf; |
1935 | } | 1934 | } |
1936 | if (!psf) { | 1935 | if (!psf) { |
1937 | psf = kmalloc(sizeof(*psf), GFP_ATOMIC); | 1936 | psf = kzalloc(sizeof(*psf), GFP_ATOMIC); |
1938 | if (!psf) | 1937 | if (!psf) |
1939 | return -ENOBUFS; | 1938 | return -ENOBUFS; |
1940 | memset(psf, 0, sizeof(*psf)); | 1939 | |
1941 | psf->sf_addr = *psfsrc; | 1940 | psf->sf_addr = *psfsrc; |
1942 | if (psf_prev) { | 1941 | if (psf_prev) { |
1943 | psf_prev->sf_next = psf; | 1942 | psf_prev->sf_next = psf; |
@@ -2431,7 +2430,7 @@ static int igmp6_mc_seq_open(struct inode *inode, struct file *file) | |||
2431 | { | 2430 | { |
2432 | struct seq_file *seq; | 2431 | struct seq_file *seq; |
2433 | int rc = -ENOMEM; | 2432 | int rc = -ENOMEM; |
2434 | struct igmp6_mc_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); | 2433 | struct igmp6_mc_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); |
2435 | 2434 | ||
2436 | if (!s) | 2435 | if (!s) |
2437 | goto out; | 2436 | goto out; |
@@ -2442,7 +2441,6 @@ static int igmp6_mc_seq_open(struct inode *inode, struct file *file) | |||
2442 | 2441 | ||
2443 | seq = file->private_data; | 2442 | seq = file->private_data; |
2444 | seq->private = s; | 2443 | seq->private = s; |
2445 | memset(s, 0, sizeof(*s)); | ||
2446 | out: | 2444 | out: |
2447 | return rc; | 2445 | return rc; |
2448 | out_kfree: | 2446 | out_kfree: |
@@ -2606,7 +2604,7 @@ static int igmp6_mcf_seq_open(struct inode *inode, struct file *file) | |||
2606 | { | 2604 | { |
2607 | struct seq_file *seq; | 2605 | struct seq_file *seq; |
2608 | int rc = -ENOMEM; | 2606 | int rc = -ENOMEM; |
2609 | struct igmp6_mcf_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); | 2607 | struct igmp6_mcf_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); |
2610 | 2608 | ||
2611 | if (!s) | 2609 | if (!s) |
2612 | goto out; | 2610 | goto out; |
@@ -2617,7 +2615,6 @@ static int igmp6_mcf_seq_open(struct inode *inode, struct file *file) | |||
2617 | 2615 | ||
2618 | seq = file->private_data; | 2616 | seq = file->private_data; |
2619 | seq->private = s; | 2617 | seq->private = s; |
2620 | memset(s, 0, sizeof(*s)); | ||
2621 | out: | 2618 | out: |
2622 | return rc; | 2619 | return rc; |
2623 | out_kfree: | 2620 | out_kfree: |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index cb8856b1d951..dfa20d3be9b6 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -156,7 +156,11 @@ struct neigh_table nd_tbl = { | |||
156 | 156 | ||
157 | /* ND options */ | 157 | /* ND options */ |
158 | struct ndisc_options { | 158 | struct ndisc_options { |
159 | struct nd_opt_hdr *nd_opt_array[__ND_OPT_MAX]; | 159 | struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX]; |
160 | #ifdef CONFIG_IPV6_ROUTE_INFO | ||
161 | struct nd_opt_hdr *nd_opts_ri; | ||
162 | struct nd_opt_hdr *nd_opts_ri_end; | ||
163 | #endif | ||
160 | }; | 164 | }; |
161 | 165 | ||
162 | #define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR] | 166 | #define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR] |
@@ -255,6 +259,13 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, | |||
255 | if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) | 259 | if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) |
256 | ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; | 260 | ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; |
257 | break; | 261 | break; |
262 | #ifdef CONFIG_IPV6_ROUTE_INFO | ||
263 | case ND_OPT_ROUTE_INFO: | ||
264 | ndopts->nd_opts_ri_end = nd_opt; | ||
265 | if (!ndopts->nd_opts_ri) | ||
266 | ndopts->nd_opts_ri = nd_opt; | ||
267 | break; | ||
268 | #endif | ||
258 | default: | 269 | default: |
259 | /* | 270 | /* |
260 | * Unknown options must be silently ignored, | 271 | * Unknown options must be silently ignored, |
@@ -1019,10 +1030,11 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1019 | struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw; | 1030 | struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw; |
1020 | struct neighbour *neigh = NULL; | 1031 | struct neighbour *neigh = NULL; |
1021 | struct inet6_dev *in6_dev; | 1032 | struct inet6_dev *in6_dev; |
1022 | struct rt6_info *rt; | 1033 | struct rt6_info *rt = NULL; |
1023 | int lifetime; | 1034 | int lifetime; |
1024 | struct ndisc_options ndopts; | 1035 | struct ndisc_options ndopts; |
1025 | int optlen; | 1036 | int optlen; |
1037 | unsigned int pref = 0; | ||
1026 | 1038 | ||
1027 | __u8 * opt = (__u8 *)(ra_msg + 1); | 1039 | __u8 * opt = (__u8 *)(ra_msg + 1); |
1028 | 1040 | ||
@@ -1081,8 +1093,19 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1081 | (ra_msg->icmph.icmp6_addrconf_other ? | 1093 | (ra_msg->icmph.icmp6_addrconf_other ? |
1082 | IF_RA_OTHERCONF : 0); | 1094 | IF_RA_OTHERCONF : 0); |
1083 | 1095 | ||
1096 | if (!in6_dev->cnf.accept_ra_defrtr) | ||
1097 | goto skip_defrtr; | ||
1098 | |||
1084 | lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); | 1099 | lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); |
1085 | 1100 | ||
1101 | #ifdef CONFIG_IPV6_ROUTER_PREF | ||
1102 | pref = ra_msg->icmph.icmp6_router_pref; | ||
1103 | /* 10b is handled as if it were 00b (medium) */ | ||
1104 | if (pref == ICMPV6_ROUTER_PREF_INVALID || | ||
1105 | in6_dev->cnf.accept_ra_rtr_pref) | ||
1106 | pref = ICMPV6_ROUTER_PREF_MEDIUM; | ||
1107 | #endif | ||
1108 | |||
1086 | rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev); | 1109 | rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev); |
1087 | 1110 | ||
1088 | if (rt) | 1111 | if (rt) |
@@ -1098,7 +1121,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1098 | ND_PRINTK3(KERN_DEBUG | 1121 | ND_PRINTK3(KERN_DEBUG |
1099 | "ICMPv6 RA: adding default router.\n"); | 1122 | "ICMPv6 RA: adding default router.\n"); |
1100 | 1123 | ||
1101 | rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev); | 1124 | rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev, pref); |
1102 | if (rt == NULL) { | 1125 | if (rt == NULL) { |
1103 | ND_PRINTK0(KERN_ERR | 1126 | ND_PRINTK0(KERN_ERR |
1104 | "ICMPv6 RA: %s() failed to add default route.\n", | 1127 | "ICMPv6 RA: %s() failed to add default route.\n", |
@@ -1117,6 +1140,8 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1117 | return; | 1140 | return; |
1118 | } | 1141 | } |
1119 | neigh->flags |= NTF_ROUTER; | 1142 | neigh->flags |= NTF_ROUTER; |
1143 | } else if (rt) { | ||
1144 | rt->rt6i_flags |= (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); | ||
1120 | } | 1145 | } |
1121 | 1146 | ||
1122 | if (rt) | 1147 | if (rt) |
@@ -1128,6 +1153,8 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1128 | rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit; | 1153 | rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit; |
1129 | } | 1154 | } |
1130 | 1155 | ||
1156 | skip_defrtr: | ||
1157 | |||
1131 | /* | 1158 | /* |
1132 | * Update Reachable Time and Retrans Timer | 1159 | * Update Reachable Time and Retrans Timer |
1133 | */ | 1160 | */ |
@@ -1186,7 +1213,21 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1186 | NEIGH_UPDATE_F_ISROUTER); | 1213 | NEIGH_UPDATE_F_ISROUTER); |
1187 | } | 1214 | } |
1188 | 1215 | ||
1189 | if (ndopts.nd_opts_pi) { | 1216 | #ifdef CONFIG_IPV6_ROUTE_INFO |
1217 | if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) { | ||
1218 | struct nd_opt_hdr *p; | ||
1219 | for (p = ndopts.nd_opts_ri; | ||
1220 | p; | ||
1221 | p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) { | ||
1222 | if (((struct route_info *)p)->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen) | ||
1223 | continue; | ||
1224 | rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3, | ||
1225 | &skb->nh.ipv6h->saddr); | ||
1226 | } | ||
1227 | } | ||
1228 | #endif | ||
1229 | |||
1230 | if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) { | ||
1190 | struct nd_opt_hdr *p; | 1231 | struct nd_opt_hdr *p; |
1191 | for (p = ndopts.nd_opts_pi; | 1232 | for (p = ndopts.nd_opts_pi; |
1192 | p; | 1233 | p; |
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 2d6f8ecbc27b..98f78759f1ab 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -133,16 +133,6 @@ config IP6_NF_MATCH_EUI64 | |||
133 | 133 | ||
134 | To compile it as a module, choose M here. If unsure, say N. | 134 | To compile it as a module, choose M here. If unsure, say N. |
135 | 135 | ||
136 | config IP6_NF_MATCH_POLICY | ||
137 | tristate "IPsec policy match support" | ||
138 | depends on IP6_NF_IPTABLES && XFRM | ||
139 | help | ||
140 | Policy matching allows you to match packets based on the | ||
141 | IPsec policy that was used during decapsulation/will | ||
142 | be used during encapsulation. | ||
143 | |||
144 | To compile it as a module, choose M here. If unsure, say N. | ||
145 | |||
146 | # The targets | 136 | # The targets |
147 | config IP6_NF_FILTER | 137 | config IP6_NF_FILTER |
148 | tristate "Packet filtering" | 138 | tristate "Packet filtering" |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index db6073c94163..8436a1a1731f 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -9,7 +9,6 @@ obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o | |||
9 | obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o | 9 | obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o |
10 | obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o | 10 | obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o |
11 | obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o | 11 | obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o |
12 | obj-$(CONFIG_IP6_NF_MATCH_POLICY) += ip6t_policy.o | ||
13 | obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o | 12 | obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o |
14 | obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o | 13 | obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o |
15 | obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o | 14 | obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o |
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index af0635084df8..344eab3b5da8 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/spinlock.h> | 35 | #include <linux/spinlock.h> |
36 | #include <linux/sysctl.h> | 36 | #include <linux/sysctl.h> |
37 | #include <linux/proc_fs.h> | 37 | #include <linux/proc_fs.h> |
38 | #include <linux/mutex.h> | ||
38 | #include <net/sock.h> | 39 | #include <net/sock.h> |
39 | #include <net/ipv6.h> | 40 | #include <net/ipv6.h> |
40 | #include <net/ip6_route.h> | 41 | #include <net/ip6_route.h> |
@@ -65,7 +66,7 @@ static unsigned int queue_dropped = 0; | |||
65 | static unsigned int queue_user_dropped = 0; | 66 | static unsigned int queue_user_dropped = 0; |
66 | static struct sock *ipqnl; | 67 | static struct sock *ipqnl; |
67 | static LIST_HEAD(queue_list); | 68 | static LIST_HEAD(queue_list); |
68 | static DECLARE_MUTEX(ipqnl_sem); | 69 | static DEFINE_MUTEX(ipqnl_mutex); |
69 | 70 | ||
70 | static void | 71 | static void |
71 | ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict) | 72 | ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict) |
@@ -537,7 +538,7 @@ ipq_rcv_sk(struct sock *sk, int len) | |||
537 | struct sk_buff *skb; | 538 | struct sk_buff *skb; |
538 | unsigned int qlen; | 539 | unsigned int qlen; |
539 | 540 | ||
540 | down(&ipqnl_sem); | 541 | mutex_lock(&ipqnl_mutex); |
541 | 542 | ||
542 | for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { | 543 | for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { |
543 | skb = skb_dequeue(&sk->sk_receive_queue); | 544 | skb = skb_dequeue(&sk->sk_receive_queue); |
@@ -545,7 +546,7 @@ ipq_rcv_sk(struct sock *sk, int len) | |||
545 | kfree_skb(skb); | 546 | kfree_skb(skb); |
546 | } | 547 | } |
547 | 548 | ||
548 | up(&ipqnl_sem); | 549 | mutex_unlock(&ipqnl_mutex); |
549 | } | 550 | } |
550 | 551 | ||
551 | static int | 552 | static int |
@@ -704,8 +705,8 @@ cleanup_sysctl: | |||
704 | 705 | ||
705 | cleanup_ipqnl: | 706 | cleanup_ipqnl: |
706 | sock_release(ipqnl->sk_socket); | 707 | sock_release(ipqnl->sk_socket); |
707 | down(&ipqnl_sem); | 708 | mutex_lock(&ipqnl_mutex); |
708 | up(&ipqnl_sem); | 709 | mutex_unlock(&ipqnl_mutex); |
709 | 710 | ||
710 | cleanup_netlink_notifier: | 711 | cleanup_netlink_notifier: |
711 | netlink_unregister_notifier(&ipq_nl_notifier); | 712 | netlink_unregister_notifier(&ipq_nl_notifier); |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 74ff56c322f4..db3c9ae98e95 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -29,7 +29,7 @@ | |||
29 | #include <linux/icmpv6.h> | 29 | #include <linux/icmpv6.h> |
30 | #include <net/ipv6.h> | 30 | #include <net/ipv6.h> |
31 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
32 | #include <asm/semaphore.h> | 32 | #include <linux/mutex.h> |
33 | #include <linux/proc_fs.h> | 33 | #include <linux/proc_fs.h> |
34 | #include <linux/cpumask.h> | 34 | #include <linux/cpumask.h> |
35 | 35 | ||
@@ -94,19 +94,6 @@ do { \ | |||
94 | #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0) | 94 | #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0) |
95 | #endif | 95 | #endif |
96 | 96 | ||
97 | int | ||
98 | ip6_masked_addrcmp(const struct in6_addr *addr1, const struct in6_addr *mask, | ||
99 | const struct in6_addr *addr2) | ||
100 | { | ||
101 | int i; | ||
102 | for( i = 0; i < 16; i++){ | ||
103 | if((addr1->s6_addr[i] & mask->s6_addr[i]) != | ||
104 | (addr2->s6_addr[i] & mask->s6_addr[i])) | ||
105 | return 1; | ||
106 | } | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | /* Check for an extension */ | 97 | /* Check for an extension */ |
111 | int | 98 | int |
112 | ip6t_ext_hdr(u8 nexthdr) | 99 | ip6t_ext_hdr(u8 nexthdr) |
@@ -135,10 +122,10 @@ ip6_packet_match(const struct sk_buff *skb, | |||
135 | 122 | ||
136 | #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg)) | 123 | #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg)) |
137 | 124 | ||
138 | if (FWINV(ip6_masked_addrcmp(&ipv6->saddr, &ip6info->smsk, | 125 | if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk, |
139 | &ip6info->src), IP6T_INV_SRCIP) | 126 | &ip6info->src), IP6T_INV_SRCIP) |
140 | || FWINV(ip6_masked_addrcmp(&ipv6->daddr, &ip6info->dmsk, | 127 | || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk, |
141 | &ip6info->dst), IP6T_INV_DSTIP)) { | 128 | &ip6info->dst), IP6T_INV_DSTIP)) { |
142 | dprintf("Source or dest mismatch.\n"); | 129 | dprintf("Source or dest mismatch.\n"); |
143 | /* | 130 | /* |
144 | dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, | 131 | dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, |
@@ -232,6 +219,7 @@ ip6t_error(struct sk_buff **pskb, | |||
232 | const struct net_device *in, | 219 | const struct net_device *in, |
233 | const struct net_device *out, | 220 | const struct net_device *out, |
234 | unsigned int hooknum, | 221 | unsigned int hooknum, |
222 | const struct xt_target *target, | ||
235 | const void *targinfo, | 223 | const void *targinfo, |
236 | void *userinfo) | 224 | void *userinfo) |
237 | { | 225 | { |
@@ -251,7 +239,7 @@ int do_match(struct ip6t_entry_match *m, | |||
251 | int *hotdrop) | 239 | int *hotdrop) |
252 | { | 240 | { |
253 | /* Stop iteration if it doesn't match */ | 241 | /* Stop iteration if it doesn't match */ |
254 | if (!m->u.kernel.match->match(skb, in, out, m->data, | 242 | if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data, |
255 | offset, protoff, hotdrop)) | 243 | offset, protoff, hotdrop)) |
256 | return 1; | 244 | return 1; |
257 | else | 245 | else |
@@ -373,6 +361,7 @@ ip6t_do_table(struct sk_buff **pskb, | |||
373 | verdict = t->u.kernel.target->target(pskb, | 361 | verdict = t->u.kernel.target->target(pskb, |
374 | in, out, | 362 | in, out, |
375 | hook, | 363 | hook, |
364 | t->u.kernel.target, | ||
376 | t->data, | 365 | t->data, |
377 | userdata); | 366 | userdata); |
378 | 367 | ||
@@ -531,7 +520,7 @@ cleanup_match(struct ip6t_entry_match *m, unsigned int *i) | |||
531 | return 1; | 520 | return 1; |
532 | 521 | ||
533 | if (m->u.kernel.match->destroy) | 522 | if (m->u.kernel.match->destroy) |
534 | m->u.kernel.match->destroy(m->data, | 523 | m->u.kernel.match->destroy(m->u.kernel.match, m->data, |
535 | m->u.match_size - sizeof(*m)); | 524 | m->u.match_size - sizeof(*m)); |
536 | module_put(m->u.kernel.match->me); | 525 | module_put(m->u.kernel.match->me); |
537 | return 0; | 526 | return 0; |
@@ -544,21 +533,12 @@ standard_check(const struct ip6t_entry_target *t, | |||
544 | struct ip6t_standard_target *targ = (void *)t; | 533 | struct ip6t_standard_target *targ = (void *)t; |
545 | 534 | ||
546 | /* Check standard info. */ | 535 | /* Check standard info. */ |
547 | if (t->u.target_size | ||
548 | != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) { | ||
549 | duprintf("standard_check: target size %u != %u\n", | ||
550 | t->u.target_size, | ||
551 | IP6T_ALIGN(sizeof(struct ip6t_standard_target))); | ||
552 | return 0; | ||
553 | } | ||
554 | |||
555 | if (targ->verdict >= 0 | 536 | if (targ->verdict >= 0 |
556 | && targ->verdict > max_offset - sizeof(struct ip6t_entry)) { | 537 | && targ->verdict > max_offset - sizeof(struct ip6t_entry)) { |
557 | duprintf("ip6t_standard_check: bad verdict (%i)\n", | 538 | duprintf("ip6t_standard_check: bad verdict (%i)\n", |
558 | targ->verdict); | 539 | targ->verdict); |
559 | return 0; | 540 | return 0; |
560 | } | 541 | } |
561 | |||
562 | if (targ->verdict < -NF_MAX_VERDICT - 1) { | 542 | if (targ->verdict < -NF_MAX_VERDICT - 1) { |
563 | duprintf("ip6t_standard_check: bad negative verdict (%i)\n", | 543 | duprintf("ip6t_standard_check: bad negative verdict (%i)\n", |
564 | targ->verdict); | 544 | targ->verdict); |
@@ -575,6 +555,7 @@ check_match(struct ip6t_entry_match *m, | |||
575 | unsigned int *i) | 555 | unsigned int *i) |
576 | { | 556 | { |
577 | struct ip6t_match *match; | 557 | struct ip6t_match *match; |
558 | int ret; | ||
578 | 559 | ||
579 | match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name, | 560 | match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name, |
580 | m->u.user.revision), | 561 | m->u.user.revision), |
@@ -585,18 +566,27 @@ check_match(struct ip6t_entry_match *m, | |||
585 | } | 566 | } |
586 | m->u.kernel.match = match; | 567 | m->u.kernel.match = match; |
587 | 568 | ||
569 | ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m), | ||
570 | name, hookmask, ipv6->proto, | ||
571 | ipv6->invflags & IP6T_INV_PROTO); | ||
572 | if (ret) | ||
573 | goto err; | ||
574 | |||
588 | if (m->u.kernel.match->checkentry | 575 | if (m->u.kernel.match->checkentry |
589 | && !m->u.kernel.match->checkentry(name, ipv6, m->data, | 576 | && !m->u.kernel.match->checkentry(name, ipv6, match, m->data, |
590 | m->u.match_size - sizeof(*m), | 577 | m->u.match_size - sizeof(*m), |
591 | hookmask)) { | 578 | hookmask)) { |
592 | module_put(m->u.kernel.match->me); | ||
593 | duprintf("ip_tables: check failed for `%s'.\n", | 579 | duprintf("ip_tables: check failed for `%s'.\n", |
594 | m->u.kernel.match->name); | 580 | m->u.kernel.match->name); |
595 | return -EINVAL; | 581 | ret = -EINVAL; |
582 | goto err; | ||
596 | } | 583 | } |
597 | 584 | ||
598 | (*i)++; | 585 | (*i)++; |
599 | return 0; | 586 | return 0; |
587 | err: | ||
588 | module_put(m->u.kernel.match->me); | ||
589 | return ret; | ||
600 | } | 590 | } |
601 | 591 | ||
602 | static struct ip6t_target ip6t_standard_target; | 592 | static struct ip6t_target ip6t_standard_target; |
@@ -632,26 +622,32 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, | |||
632 | } | 622 | } |
633 | t->u.kernel.target = target; | 623 | t->u.kernel.target = target; |
634 | 624 | ||
625 | ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t), | ||
626 | name, e->comefrom, e->ipv6.proto, | ||
627 | e->ipv6.invflags & IP6T_INV_PROTO); | ||
628 | if (ret) | ||
629 | goto err; | ||
630 | |||
635 | if (t->u.kernel.target == &ip6t_standard_target) { | 631 | if (t->u.kernel.target == &ip6t_standard_target) { |
636 | if (!standard_check(t, size)) { | 632 | if (!standard_check(t, size)) { |
637 | ret = -EINVAL; | 633 | ret = -EINVAL; |
638 | goto cleanup_matches; | 634 | goto cleanup_matches; |
639 | } | 635 | } |
640 | } else if (t->u.kernel.target->checkentry | 636 | } else if (t->u.kernel.target->checkentry |
641 | && !t->u.kernel.target->checkentry(name, e, t->data, | 637 | && !t->u.kernel.target->checkentry(name, e, target, t->data, |
642 | t->u.target_size | 638 | t->u.target_size |
643 | - sizeof(*t), | 639 | - sizeof(*t), |
644 | e->comefrom)) { | 640 | e->comefrom)) { |
645 | module_put(t->u.kernel.target->me); | ||
646 | duprintf("ip_tables: check failed for `%s'.\n", | 641 | duprintf("ip_tables: check failed for `%s'.\n", |
647 | t->u.kernel.target->name); | 642 | t->u.kernel.target->name); |
648 | ret = -EINVAL; | 643 | ret = -EINVAL; |
649 | goto cleanup_matches; | 644 | goto err; |
650 | } | 645 | } |
651 | 646 | ||
652 | (*i)++; | 647 | (*i)++; |
653 | return 0; | 648 | return 0; |
654 | 649 | err: | |
650 | module_put(t->u.kernel.target->me); | ||
655 | cleanup_matches: | 651 | cleanup_matches: |
656 | IP6T_MATCH_ITERATE(e, cleanup_match, &j); | 652 | IP6T_MATCH_ITERATE(e, cleanup_match, &j); |
657 | return ret; | 653 | return ret; |
@@ -712,7 +708,7 @@ cleanup_entry(struct ip6t_entry *e, unsigned int *i) | |||
712 | IP6T_MATCH_ITERATE(e, cleanup_match, NULL); | 708 | IP6T_MATCH_ITERATE(e, cleanup_match, NULL); |
713 | t = ip6t_get_target(e); | 709 | t = ip6t_get_target(e); |
714 | if (t->u.kernel.target->destroy) | 710 | if (t->u.kernel.target->destroy) |
715 | t->u.kernel.target->destroy(t->data, | 711 | t->u.kernel.target->destroy(t->u.kernel.target, t->data, |
716 | t->u.target_size - sizeof(*t)); | 712 | t->u.target_size - sizeof(*t)); |
717 | module_put(t->u.kernel.target->me); | 713 | module_put(t->u.kernel.target->me); |
718 | return 0; | 714 | return 0; |
@@ -1333,6 +1329,7 @@ static int | |||
1333 | icmp6_match(const struct sk_buff *skb, | 1329 | icmp6_match(const struct sk_buff *skb, |
1334 | const struct net_device *in, | 1330 | const struct net_device *in, |
1335 | const struct net_device *out, | 1331 | const struct net_device *out, |
1332 | const struct xt_match *match, | ||
1336 | const void *matchinfo, | 1333 | const void *matchinfo, |
1337 | int offset, | 1334 | int offset, |
1338 | unsigned int protoff, | 1335 | unsigned int protoff, |
@@ -1365,28 +1362,29 @@ icmp6_match(const struct sk_buff *skb, | |||
1365 | static int | 1362 | static int |
1366 | icmp6_checkentry(const char *tablename, | 1363 | icmp6_checkentry(const char *tablename, |
1367 | const void *entry, | 1364 | const void *entry, |
1365 | const struct xt_match *match, | ||
1368 | void *matchinfo, | 1366 | void *matchinfo, |
1369 | unsigned int matchsize, | 1367 | unsigned int matchsize, |
1370 | unsigned int hook_mask) | 1368 | unsigned int hook_mask) |
1371 | { | 1369 | { |
1372 | const struct ip6t_ip6 *ipv6 = entry; | ||
1373 | const struct ip6t_icmp *icmpinfo = matchinfo; | 1370 | const struct ip6t_icmp *icmpinfo = matchinfo; |
1374 | 1371 | ||
1375 | /* Must specify proto == ICMP, and no unknown invflags */ | 1372 | /* Must specify no unknown invflags */ |
1376 | return ipv6->proto == IPPROTO_ICMPV6 | 1373 | return !(icmpinfo->invflags & ~IP6T_ICMP_INV); |
1377 | && !(ipv6->invflags & IP6T_INV_PROTO) | ||
1378 | && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp)) | ||
1379 | && !(icmpinfo->invflags & ~IP6T_ICMP_INV); | ||
1380 | } | 1374 | } |
1381 | 1375 | ||
1382 | /* The built-in targets: standard (NULL) and error. */ | 1376 | /* The built-in targets: standard (NULL) and error. */ |
1383 | static struct ip6t_target ip6t_standard_target = { | 1377 | static struct ip6t_target ip6t_standard_target = { |
1384 | .name = IP6T_STANDARD_TARGET, | 1378 | .name = IP6T_STANDARD_TARGET, |
1379 | .targetsize = sizeof(int), | ||
1380 | .family = AF_INET6, | ||
1385 | }; | 1381 | }; |
1386 | 1382 | ||
1387 | static struct ip6t_target ip6t_error_target = { | 1383 | static struct ip6t_target ip6t_error_target = { |
1388 | .name = IP6T_ERROR_TARGET, | 1384 | .name = IP6T_ERROR_TARGET, |
1389 | .target = ip6t_error, | 1385 | .target = ip6t_error, |
1386 | .targetsize = IP6T_FUNCTION_MAXNAMELEN, | ||
1387 | .family = AF_INET6, | ||
1390 | }; | 1388 | }; |
1391 | 1389 | ||
1392 | static struct nf_sockopt_ops ip6t_sockopts = { | 1390 | static struct nf_sockopt_ops ip6t_sockopts = { |
@@ -1402,7 +1400,10 @@ static struct nf_sockopt_ops ip6t_sockopts = { | |||
1402 | static struct ip6t_match icmp6_matchstruct = { | 1400 | static struct ip6t_match icmp6_matchstruct = { |
1403 | .name = "icmp6", | 1401 | .name = "icmp6", |
1404 | .match = &icmp6_match, | 1402 | .match = &icmp6_match, |
1405 | .checkentry = &icmp6_checkentry, | 1403 | .matchsize = sizeof(struct ip6t_icmp), |
1404 | .checkentry = icmp6_checkentry, | ||
1405 | .proto = IPPROTO_ICMPV6, | ||
1406 | .family = AF_INET6, | ||
1406 | }; | 1407 | }; |
1407 | 1408 | ||
1408 | static int __init init(void) | 1409 | static int __init init(void) |
@@ -1412,9 +1413,9 @@ static int __init init(void) | |||
1412 | xt_proto_init(AF_INET6); | 1413 | xt_proto_init(AF_INET6); |
1413 | 1414 | ||
1414 | /* Noone else will be downing sem now, so we won't sleep */ | 1415 | /* Noone else will be downing sem now, so we won't sleep */ |
1415 | xt_register_target(AF_INET6, &ip6t_standard_target); | 1416 | xt_register_target(&ip6t_standard_target); |
1416 | xt_register_target(AF_INET6, &ip6t_error_target); | 1417 | xt_register_target(&ip6t_error_target); |
1417 | xt_register_match(AF_INET6, &icmp6_matchstruct); | 1418 | xt_register_match(&icmp6_matchstruct); |
1418 | 1419 | ||
1419 | /* Register setsockopt */ | 1420 | /* Register setsockopt */ |
1420 | ret = nf_register_sockopt(&ip6t_sockopts); | 1421 | ret = nf_register_sockopt(&ip6t_sockopts); |
@@ -1431,9 +1432,9 @@ static int __init init(void) | |||
1431 | static void __exit fini(void) | 1432 | static void __exit fini(void) |
1432 | { | 1433 | { |
1433 | nf_unregister_sockopt(&ip6t_sockopts); | 1434 | nf_unregister_sockopt(&ip6t_sockopts); |
1434 | xt_unregister_match(AF_INET6, &icmp6_matchstruct); | 1435 | xt_unregister_match(&icmp6_matchstruct); |
1435 | xt_unregister_target(AF_INET6, &ip6t_error_target); | 1436 | xt_unregister_target(&ip6t_error_target); |
1436 | xt_unregister_target(AF_INET6, &ip6t_standard_target); | 1437 | xt_unregister_target(&ip6t_standard_target); |
1437 | xt_proto_fini(AF_INET6); | 1438 | xt_proto_fini(AF_INET6); |
1438 | } | 1439 | } |
1439 | 1440 | ||
@@ -1515,7 +1516,6 @@ EXPORT_SYMBOL(ip6t_unregister_table); | |||
1515 | EXPORT_SYMBOL(ip6t_do_table); | 1516 | EXPORT_SYMBOL(ip6t_do_table); |
1516 | EXPORT_SYMBOL(ip6t_ext_hdr); | 1517 | EXPORT_SYMBOL(ip6t_ext_hdr); |
1517 | EXPORT_SYMBOL(ipv6_find_hdr); | 1518 | EXPORT_SYMBOL(ipv6_find_hdr); |
1518 | EXPORT_SYMBOL(ip6_masked_addrcmp); | ||
1519 | 1519 | ||
1520 | module_init(init); | 1520 | module_init(init); |
1521 | module_exit(fini); | 1521 | module_exit(fini); |
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c index 306200c35057..da14c6d86bcc 100644 --- a/net/ipv6/netfilter/ip6t_HL.c +++ b/net/ipv6/netfilter/ip6t_HL.c | |||
@@ -21,6 +21,7 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb, | |||
21 | const struct net_device *in, | 21 | const struct net_device *in, |
22 | const struct net_device *out, | 22 | const struct net_device *out, |
23 | unsigned int hooknum, | 23 | unsigned int hooknum, |
24 | const struct xt_target *target, | ||
24 | const void *targinfo, void *userinfo) | 25 | const void *targinfo, void *userinfo) |
25 | { | 26 | { |
26 | struct ipv6hdr *ip6h; | 27 | struct ipv6hdr *ip6h; |
@@ -63,43 +64,31 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb, | |||
63 | 64 | ||
64 | static int ip6t_hl_checkentry(const char *tablename, | 65 | static int ip6t_hl_checkentry(const char *tablename, |
65 | const void *entry, | 66 | const void *entry, |
67 | const struct xt_target *target, | ||
66 | void *targinfo, | 68 | void *targinfo, |
67 | unsigned int targinfosize, | 69 | unsigned int targinfosize, |
68 | unsigned int hook_mask) | 70 | unsigned int hook_mask) |
69 | { | 71 | { |
70 | struct ip6t_HL_info *info = targinfo; | 72 | struct ip6t_HL_info *info = targinfo; |
71 | 73 | ||
72 | if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) { | ||
73 | printk(KERN_WARNING "ip6t_HL: targinfosize %u != %Zu\n", | ||
74 | targinfosize, | ||
75 | IP6T_ALIGN(sizeof(struct ip6t_HL_info))); | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | if (strcmp(tablename, "mangle")) { | ||
80 | printk(KERN_WARNING "ip6t_HL: can only be called from " | ||
81 | "\"mangle\" table, not \"%s\"\n", tablename); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | if (info->mode > IP6T_HL_MAXMODE) { | 74 | if (info->mode > IP6T_HL_MAXMODE) { |
86 | printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n", | 75 | printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n", |
87 | info->mode); | 76 | info->mode); |
88 | return 0; | 77 | return 0; |
89 | } | 78 | } |
90 | |||
91 | if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) { | 79 | if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) { |
92 | printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't " | 80 | printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't " |
93 | "make sense with value 0\n"); | 81 | "make sense with value 0\n"); |
94 | return 0; | 82 | return 0; |
95 | } | 83 | } |
96 | |||
97 | return 1; | 84 | return 1; |
98 | } | 85 | } |
99 | 86 | ||
100 | static struct ip6t_target ip6t_HL = { | 87 | static struct ip6t_target ip6t_HL = { |
101 | .name = "HL", | 88 | .name = "HL", |
102 | .target = ip6t_hl_target, | 89 | .target = ip6t_hl_target, |
90 | .targetsize = sizeof(struct ip6t_HL_info), | ||
91 | .table = "mangle", | ||
103 | .checkentry = ip6t_hl_checkentry, | 92 | .checkentry = ip6t_hl_checkentry, |
104 | .me = THIS_MODULE | 93 | .me = THIS_MODULE |
105 | }; | 94 | }; |
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 6b930efa9fb9..07c6bcbe4c5f 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c | |||
@@ -426,6 +426,7 @@ ip6t_log_target(struct sk_buff **pskb, | |||
426 | const struct net_device *in, | 426 | const struct net_device *in, |
427 | const struct net_device *out, | 427 | const struct net_device *out, |
428 | unsigned int hooknum, | 428 | unsigned int hooknum, |
429 | const struct xt_target *target, | ||
429 | const void *targinfo, | 430 | const void *targinfo, |
430 | void *userinfo) | 431 | void *userinfo) |
431 | { | 432 | { |
@@ -449,35 +450,29 @@ ip6t_log_target(struct sk_buff **pskb, | |||
449 | 450 | ||
450 | static int ip6t_log_checkentry(const char *tablename, | 451 | static int ip6t_log_checkentry(const char *tablename, |
451 | const void *entry, | 452 | const void *entry, |
453 | const struct xt_target *target, | ||
452 | void *targinfo, | 454 | void *targinfo, |
453 | unsigned int targinfosize, | 455 | unsigned int targinfosize, |
454 | unsigned int hook_mask) | 456 | unsigned int hook_mask) |
455 | { | 457 | { |
456 | const struct ip6t_log_info *loginfo = targinfo; | 458 | const struct ip6t_log_info *loginfo = targinfo; |
457 | 459 | ||
458 | if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_log_info))) { | ||
459 | DEBUGP("LOG: targinfosize %u != %u\n", | ||
460 | targinfosize, IP6T_ALIGN(sizeof(struct ip6t_log_info))); | ||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | if (loginfo->level >= 8) { | 460 | if (loginfo->level >= 8) { |
465 | DEBUGP("LOG: level %u >= 8\n", loginfo->level); | 461 | DEBUGP("LOG: level %u >= 8\n", loginfo->level); |
466 | return 0; | 462 | return 0; |
467 | } | 463 | } |
468 | |||
469 | if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { | 464 | if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { |
470 | DEBUGP("LOG: prefix term %i\n", | 465 | DEBUGP("LOG: prefix term %i\n", |
471 | loginfo->prefix[sizeof(loginfo->prefix)-1]); | 466 | loginfo->prefix[sizeof(loginfo->prefix)-1]); |
472 | return 0; | 467 | return 0; |
473 | } | 468 | } |
474 | |||
475 | return 1; | 469 | return 1; |
476 | } | 470 | } |
477 | 471 | ||
478 | static struct ip6t_target ip6t_log_reg = { | 472 | static struct ip6t_target ip6t_log_reg = { |
479 | .name = "LOG", | 473 | .name = "LOG", |
480 | .target = ip6t_log_target, | 474 | .target = ip6t_log_target, |
475 | .targetsize = sizeof(struct ip6t_log_info), | ||
481 | .checkentry = ip6t_log_checkentry, | 476 | .checkentry = ip6t_log_checkentry, |
482 | .me = THIS_MODULE, | 477 | .me = THIS_MODULE, |
483 | }; | 478 | }; |
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 0e6d1d4bbd5c..ddfa38575fe2 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c | |||
@@ -179,6 +179,7 @@ static unsigned int reject6_target(struct sk_buff **pskb, | |||
179 | const struct net_device *in, | 179 | const struct net_device *in, |
180 | const struct net_device *out, | 180 | const struct net_device *out, |
181 | unsigned int hooknum, | 181 | unsigned int hooknum, |
182 | const struct xt_target *target, | ||
182 | const void *targinfo, | 183 | const void *targinfo, |
183 | void *userinfo) | 184 | void *userinfo) |
184 | { | 185 | { |
@@ -221,6 +222,7 @@ static unsigned int reject6_target(struct sk_buff **pskb, | |||
221 | 222 | ||
222 | static int check(const char *tablename, | 223 | static int check(const char *tablename, |
223 | const void *entry, | 224 | const void *entry, |
225 | const struct xt_target *target, | ||
224 | void *targinfo, | 226 | void *targinfo, |
225 | unsigned int targinfosize, | 227 | unsigned int targinfosize, |
226 | unsigned int hook_mask) | 228 | unsigned int hook_mask) |
@@ -228,24 +230,6 @@ static int check(const char *tablename, | |||
228 | const struct ip6t_reject_info *rejinfo = targinfo; | 230 | const struct ip6t_reject_info *rejinfo = targinfo; |
229 | const struct ip6t_entry *e = entry; | 231 | const struct ip6t_entry *e = entry; |
230 | 232 | ||
231 | if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) { | ||
232 | DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize); | ||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | /* Only allow these for packet filtering. */ | ||
237 | if (strcmp(tablename, "filter") != 0) { | ||
238 | DEBUGP("ip6t_REJECT: bad table `%s'.\n", tablename); | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN) | ||
243 | | (1 << NF_IP6_FORWARD) | ||
244 | | (1 << NF_IP6_LOCAL_OUT))) != 0) { | ||
245 | DEBUGP("ip6t_REJECT: bad hook mask %X\n", hook_mask); | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) { | 233 | if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) { |
250 | printk("ip6t_REJECT: ECHOREPLY is not supported.\n"); | 234 | printk("ip6t_REJECT: ECHOREPLY is not supported.\n"); |
251 | return 0; | 235 | return 0; |
@@ -257,13 +241,16 @@ static int check(const char *tablename, | |||
257 | return 0; | 241 | return 0; |
258 | } | 242 | } |
259 | } | 243 | } |
260 | |||
261 | return 1; | 244 | return 1; |
262 | } | 245 | } |
263 | 246 | ||
264 | static struct ip6t_target ip6t_reject_reg = { | 247 | static struct ip6t_target ip6t_reject_reg = { |
265 | .name = "REJECT", | 248 | .name = "REJECT", |
266 | .target = reject6_target, | 249 | .target = reject6_target, |
250 | .targetsize = sizeof(struct ip6t_reject_info), | ||
251 | .table = "filter", | ||
252 | .hooks = (1 << NF_IP6_LOCAL_IN) | (1 << NF_IP6_FORWARD) | | ||
253 | (1 << NF_IP6_LOCAL_OUT), | ||
267 | .checkentry = check, | 254 | .checkentry = check, |
268 | .me = THIS_MODULE | 255 | .me = THIS_MODULE |
269 | }; | 256 | }; |
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c index 219a30365dff..178f6fb1e53d 100644 --- a/net/ipv6/netfilter/ip6t_ah.c +++ b/net/ipv6/netfilter/ip6t_ah.c | |||
@@ -44,6 +44,7 @@ static int | |||
44 | match(const struct sk_buff *skb, | 44 | match(const struct sk_buff *skb, |
45 | const struct net_device *in, | 45 | const struct net_device *in, |
46 | const struct net_device *out, | 46 | const struct net_device *out, |
47 | const struct xt_match *match, | ||
47 | const void *matchinfo, | 48 | const void *matchinfo, |
48 | int offset, | 49 | int offset, |
49 | unsigned int protoff, | 50 | unsigned int protoff, |
@@ -99,17 +100,13 @@ match(const struct sk_buff *skb, | |||
99 | static int | 100 | static int |
100 | checkentry(const char *tablename, | 101 | checkentry(const char *tablename, |
101 | const void *entry, | 102 | const void *entry, |
103 | const struct xt_match *match, | ||
102 | void *matchinfo, | 104 | void *matchinfo, |
103 | unsigned int matchinfosize, | 105 | unsigned int matchinfosize, |
104 | unsigned int hook_mask) | 106 | unsigned int hook_mask) |
105 | { | 107 | { |
106 | const struct ip6t_ah *ahinfo = matchinfo; | 108 | const struct ip6t_ah *ahinfo = matchinfo; |
107 | 109 | ||
108 | if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) { | ||
109 | DEBUGP("ip6t_ah: matchsize %u != %u\n", | ||
110 | matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah))); | ||
111 | return 0; | ||
112 | } | ||
113 | if (ahinfo->invflags & ~IP6T_AH_INV_MASK) { | 110 | if (ahinfo->invflags & ~IP6T_AH_INV_MASK) { |
114 | DEBUGP("ip6t_ah: unknown flags %X\n", ahinfo->invflags); | 111 | DEBUGP("ip6t_ah: unknown flags %X\n", ahinfo->invflags); |
115 | return 0; | 112 | return 0; |
@@ -119,8 +116,9 @@ checkentry(const char *tablename, | |||
119 | 116 | ||
120 | static struct ip6t_match ah_match = { | 117 | static struct ip6t_match ah_match = { |
121 | .name = "ah", | 118 | .name = "ah", |
122 | .match = &match, | 119 | .match = match, |
123 | .checkentry = &checkentry, | 120 | .matchsize = sizeof(struct ip6t_ah), |
121 | .checkentry = checkentry, | ||
124 | .me = THIS_MODULE, | 122 | .me = THIS_MODULE, |
125 | }; | 123 | }; |
126 | 124 | ||
diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c index b4c153a53500..e97a70226987 100644 --- a/net/ipv6/netfilter/ip6t_dst.c +++ b/net/ipv6/netfilter/ip6t_dst.c | |||
@@ -55,6 +55,7 @@ static int | |||
55 | match(const struct sk_buff *skb, | 55 | match(const struct sk_buff *skb, |
56 | const struct net_device *in, | 56 | const struct net_device *in, |
57 | const struct net_device *out, | 57 | const struct net_device *out, |
58 | const struct xt_match *match, | ||
58 | const void *matchinfo, | 59 | const void *matchinfo, |
59 | int offset, | 60 | int offset, |
60 | unsigned int protoff, | 61 | unsigned int protoff, |
@@ -179,22 +180,17 @@ match(const struct sk_buff *skb, | |||
179 | static int | 180 | static int |
180 | checkentry(const char *tablename, | 181 | checkentry(const char *tablename, |
181 | const void *info, | 182 | const void *info, |
183 | const struct xt_match *match, | ||
182 | void *matchinfo, | 184 | void *matchinfo, |
183 | unsigned int matchinfosize, | 185 | unsigned int matchinfosize, |
184 | unsigned int hook_mask) | 186 | unsigned int hook_mask) |
185 | { | 187 | { |
186 | const struct ip6t_opts *optsinfo = matchinfo; | 188 | const struct ip6t_opts *optsinfo = matchinfo; |
187 | 189 | ||
188 | if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) { | ||
189 | DEBUGP("ip6t_opts: matchsize %u != %u\n", | ||
190 | matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts))); | ||
191 | return 0; | ||
192 | } | ||
193 | if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { | 190 | if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { |
194 | DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags); | 191 | DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags); |
195 | return 0; | 192 | return 0; |
196 | } | 193 | } |
197 | |||
198 | return 1; | 194 | return 1; |
199 | } | 195 | } |
200 | 196 | ||
@@ -204,8 +200,9 @@ static struct ip6t_match opts_match = { | |||
204 | #else | 200 | #else |
205 | .name = "dst", | 201 | .name = "dst", |
206 | #endif | 202 | #endif |
207 | .match = &match, | 203 | .match = match, |
208 | .checkentry = &checkentry, | 204 | .matchsize = sizeof(struct ip6t_opts), |
205 | .checkentry = checkentry, | ||
209 | .me = THIS_MODULE, | 206 | .me = THIS_MODULE, |
210 | }; | 207 | }; |
211 | 208 | ||
diff --git a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c index 724285df8711..540b8bfd5055 100644 --- a/net/ipv6/netfilter/ip6t_esp.c +++ b/net/ipv6/netfilter/ip6t_esp.c | |||
@@ -44,6 +44,7 @@ static int | |||
44 | match(const struct sk_buff *skb, | 44 | match(const struct sk_buff *skb, |
45 | const struct net_device *in, | 45 | const struct net_device *in, |
46 | const struct net_device *out, | 46 | const struct net_device *out, |
47 | const struct xt_match *match, | ||
47 | const void *matchinfo, | 48 | const void *matchinfo, |
48 | int offset, | 49 | int offset, |
49 | unsigned int protoff, | 50 | unsigned int protoff, |
@@ -77,17 +78,13 @@ match(const struct sk_buff *skb, | |||
77 | static int | 78 | static int |
78 | checkentry(const char *tablename, | 79 | checkentry(const char *tablename, |
79 | const void *ip, | 80 | const void *ip, |
81 | const struct xt_match *match, | ||
80 | void *matchinfo, | 82 | void *matchinfo, |
81 | unsigned int matchinfosize, | 83 | unsigned int matchinfosize, |
82 | unsigned int hook_mask) | 84 | unsigned int hook_mask) |
83 | { | 85 | { |
84 | const struct ip6t_esp *espinfo = matchinfo; | 86 | const struct ip6t_esp *espinfo = matchinfo; |
85 | 87 | ||
86 | if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_esp))) { | ||
87 | DEBUGP("ip6t_esp: matchsize %u != %u\n", | ||
88 | matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_esp))); | ||
89 | return 0; | ||
90 | } | ||
91 | if (espinfo->invflags & ~IP6T_ESP_INV_MASK) { | 88 | if (espinfo->invflags & ~IP6T_ESP_INV_MASK) { |
92 | DEBUGP("ip6t_esp: unknown flags %X\n", | 89 | DEBUGP("ip6t_esp: unknown flags %X\n", |
93 | espinfo->invflags); | 90 | espinfo->invflags); |
@@ -98,8 +95,9 @@ checkentry(const char *tablename, | |||
98 | 95 | ||
99 | static struct ip6t_match esp_match = { | 96 | static struct ip6t_match esp_match = { |
100 | .name = "esp", | 97 | .name = "esp", |
101 | .match = &match, | 98 | .match = match, |
102 | .checkentry = &checkentry, | 99 | .matchsize = sizeof(struct ip6t_esp), |
100 | .checkentry = checkentry, | ||
103 | .me = THIS_MODULE, | 101 | .me = THIS_MODULE, |
104 | }; | 102 | }; |
105 | 103 | ||
diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c index 27396ac0b9ed..d4b0bad52830 100644 --- a/net/ipv6/netfilter/ip6t_eui64.c +++ b/net/ipv6/netfilter/ip6t_eui64.c | |||
@@ -22,6 +22,7 @@ static int | |||
22 | match(const struct sk_buff *skb, | 22 | match(const struct sk_buff *skb, |
23 | const struct net_device *in, | 23 | const struct net_device *in, |
24 | const struct net_device *out, | 24 | const struct net_device *out, |
25 | const struct xt_match *match, | ||
25 | const void *matchinfo, | 26 | const void *matchinfo, |
26 | int offset, | 27 | int offset, |
27 | unsigned int protoff, | 28 | unsigned int protoff, |
@@ -60,30 +61,12 @@ match(const struct sk_buff *skb, | |||
60 | return 0; | 61 | return 0; |
61 | } | 62 | } |
62 | 63 | ||
63 | static int | ||
64 | ip6t_eui64_checkentry(const char *tablename, | ||
65 | const void *ip, | ||
66 | void *matchinfo, | ||
67 | unsigned int matchsize, | ||
68 | unsigned int hook_mask) | ||
69 | { | ||
70 | if (hook_mask | ||
71 | & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) | | ||
72 | (1 << NF_IP6_FORWARD))) { | ||
73 | printk("ip6t_eui64: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n"); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | if (matchsize != IP6T_ALIGN(sizeof(int))) | ||
78 | return 0; | ||
79 | |||
80 | return 1; | ||
81 | } | ||
82 | |||
83 | static struct ip6t_match eui64_match = { | 64 | static struct ip6t_match eui64_match = { |
84 | .name = "eui64", | 65 | .name = "eui64", |
85 | .match = &match, | 66 | .match = match, |
86 | .checkentry = &ip6t_eui64_checkentry, | 67 | .matchsize = sizeof(int), |
68 | .hooks = (1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) | | ||
69 | (1 << NF_IP6_FORWARD), | ||
87 | .me = THIS_MODULE, | 70 | .me = THIS_MODULE, |
88 | }; | 71 | }; |
89 | 72 | ||
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c index 4c14125a0e26..4c41e14823d5 100644 --- a/net/ipv6/netfilter/ip6t_frag.c +++ b/net/ipv6/netfilter/ip6t_frag.c | |||
@@ -43,6 +43,7 @@ static int | |||
43 | match(const struct sk_buff *skb, | 43 | match(const struct sk_buff *skb, |
44 | const struct net_device *in, | 44 | const struct net_device *in, |
45 | const struct net_device *out, | 45 | const struct net_device *out, |
46 | const struct xt_match *match, | ||
46 | const void *matchinfo, | 47 | const void *matchinfo, |
47 | int offset, | 48 | int offset, |
48 | unsigned int protoff, | 49 | unsigned int protoff, |
@@ -116,29 +117,25 @@ match(const struct sk_buff *skb, | |||
116 | static int | 117 | static int |
117 | checkentry(const char *tablename, | 118 | checkentry(const char *tablename, |
118 | const void *ip, | 119 | const void *ip, |
120 | const struct xt_match *match, | ||
119 | void *matchinfo, | 121 | void *matchinfo, |
120 | unsigned int matchinfosize, | 122 | unsigned int matchinfosize, |
121 | unsigned int hook_mask) | 123 | unsigned int hook_mask) |
122 | { | 124 | { |
123 | const struct ip6t_frag *fraginfo = matchinfo; | 125 | const struct ip6t_frag *fraginfo = matchinfo; |
124 | 126 | ||
125 | if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_frag))) { | ||
126 | DEBUGP("ip6t_frag: matchsize %u != %u\n", | ||
127 | matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_frag))); | ||
128 | return 0; | ||
129 | } | ||
130 | if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) { | 127 | if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) { |
131 | DEBUGP("ip6t_frag: unknown flags %X\n", fraginfo->invflags); | 128 | DEBUGP("ip6t_frag: unknown flags %X\n", fraginfo->invflags); |
132 | return 0; | 129 | return 0; |
133 | } | 130 | } |
134 | |||
135 | return 1; | 131 | return 1; |
136 | } | 132 | } |
137 | 133 | ||
138 | static struct ip6t_match frag_match = { | 134 | static struct ip6t_match frag_match = { |
139 | .name = "frag", | 135 | .name = "frag", |
140 | .match = &match, | 136 | .match = match, |
141 | .checkentry = &checkentry, | 137 | .matchsize = sizeof(struct ip6t_frag), |
138 | .checkentry = checkentry, | ||
142 | .me = THIS_MODULE, | 139 | .me = THIS_MODULE, |
143 | }; | 140 | }; |
144 | 141 | ||
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c index 37a8474a7e0c..b4a1fdfe6abc 100644 --- a/net/ipv6/netfilter/ip6t_hbh.c +++ b/net/ipv6/netfilter/ip6t_hbh.c | |||
@@ -55,6 +55,7 @@ static int | |||
55 | match(const struct sk_buff *skb, | 55 | match(const struct sk_buff *skb, |
56 | const struct net_device *in, | 56 | const struct net_device *in, |
57 | const struct net_device *out, | 57 | const struct net_device *out, |
58 | const struct xt_match *match, | ||
58 | const void *matchinfo, | 59 | const void *matchinfo, |
59 | int offset, | 60 | int offset, |
60 | unsigned int protoff, | 61 | unsigned int protoff, |
@@ -179,22 +180,17 @@ match(const struct sk_buff *skb, | |||
179 | static int | 180 | static int |
180 | checkentry(const char *tablename, | 181 | checkentry(const char *tablename, |
181 | const void *entry, | 182 | const void *entry, |
183 | const struct xt_match *match, | ||
182 | void *matchinfo, | 184 | void *matchinfo, |
183 | unsigned int matchinfosize, | 185 | unsigned int matchinfosize, |
184 | unsigned int hook_mask) | 186 | unsigned int hook_mask) |
185 | { | 187 | { |
186 | const struct ip6t_opts *optsinfo = matchinfo; | 188 | const struct ip6t_opts *optsinfo = matchinfo; |
187 | 189 | ||
188 | if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) { | ||
189 | DEBUGP("ip6t_opts: matchsize %u != %u\n", | ||
190 | matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts))); | ||
191 | return 0; | ||
192 | } | ||
193 | if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { | 190 | if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { |
194 | DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags); | 191 | DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags); |
195 | return 0; | 192 | return 0; |
196 | } | 193 | } |
197 | |||
198 | return 1; | 194 | return 1; |
199 | } | 195 | } |
200 | 196 | ||
@@ -204,8 +200,9 @@ static struct ip6t_match opts_match = { | |||
204 | #else | 200 | #else |
205 | .name = "dst", | 201 | .name = "dst", |
206 | #endif | 202 | #endif |
207 | .match = &match, | 203 | .match = match, |
208 | .checkentry = &checkentry, | 204 | .matchsize = sizeof(struct ip6t_opts), |
205 | .checkentry = checkentry, | ||
209 | .me = THIS_MODULE, | 206 | .me = THIS_MODULE, |
210 | }; | 207 | }; |
211 | 208 | ||
diff --git a/net/ipv6/netfilter/ip6t_hl.c b/net/ipv6/netfilter/ip6t_hl.c index c5d9079f2d9d..374055733b26 100644 --- a/net/ipv6/netfilter/ip6t_hl.c +++ b/net/ipv6/netfilter/ip6t_hl.c | |||
@@ -18,10 +18,10 @@ MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>"); | |||
18 | MODULE_DESCRIPTION("IP tables Hop Limit matching module"); | 18 | MODULE_DESCRIPTION("IP tables Hop Limit matching module"); |
19 | MODULE_LICENSE("GPL"); | 19 | MODULE_LICENSE("GPL"); |
20 | 20 | ||
21 | static int match(const struct sk_buff *skb, const struct net_device *in, | 21 | static int match(const struct sk_buff *skb, |
22 | const struct net_device *out, const void *matchinfo, | 22 | const struct net_device *in, const struct net_device *out, |
23 | int offset, unsigned int protoff, | 23 | const struct xt_match *match, const void *matchinfo, |
24 | int *hotdrop) | 24 | int offset, unsigned int protoff, int *hotdrop) |
25 | { | 25 | { |
26 | const struct ip6t_hl_info *info = matchinfo; | 26 | const struct ip6t_hl_info *info = matchinfo; |
27 | const struct ipv6hdr *ip6h = skb->nh.ipv6h; | 27 | const struct ipv6hdr *ip6h = skb->nh.ipv6h; |
@@ -48,20 +48,10 @@ static int match(const struct sk_buff *skb, const struct net_device *in, | |||
48 | return 0; | 48 | return 0; |
49 | } | 49 | } |
50 | 50 | ||
51 | static int checkentry(const char *tablename, const void *entry, | ||
52 | void *matchinfo, unsigned int matchsize, | ||
53 | unsigned int hook_mask) | ||
54 | { | ||
55 | if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_hl_info))) | ||
56 | return 0; | ||
57 | |||
58 | return 1; | ||
59 | } | ||
60 | |||
61 | static struct ip6t_match hl_match = { | 51 | static struct ip6t_match hl_match = { |
62 | .name = "hl", | 52 | .name = "hl", |
63 | .match = &match, | 53 | .match = match, |
64 | .checkentry = &checkentry, | 54 | .matchsize = sizeof(struct ip6t_hl_info), |
65 | .me = THIS_MODULE, | 55 | .me = THIS_MODULE, |
66 | }; | 56 | }; |
67 | 57 | ||
diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c index 83ad6b272f7e..9375eeb1369f 100644 --- a/net/ipv6/netfilter/ip6t_ipv6header.c +++ b/net/ipv6/netfilter/ip6t_ipv6header.c | |||
@@ -29,6 +29,7 @@ static int | |||
29 | ipv6header_match(const struct sk_buff *skb, | 29 | ipv6header_match(const struct sk_buff *skb, |
30 | const struct net_device *in, | 30 | const struct net_device *in, |
31 | const struct net_device *out, | 31 | const struct net_device *out, |
32 | const struct xt_match *match, | ||
32 | const void *matchinfo, | 33 | const void *matchinfo, |
33 | int offset, | 34 | int offset, |
34 | unsigned int protoff, | 35 | unsigned int protoff, |
@@ -125,17 +126,13 @@ ipv6header_match(const struct sk_buff *skb, | |||
125 | static int | 126 | static int |
126 | ipv6header_checkentry(const char *tablename, | 127 | ipv6header_checkentry(const char *tablename, |
127 | const void *ip, | 128 | const void *ip, |
129 | const struct xt_match *match, | ||
128 | void *matchinfo, | 130 | void *matchinfo, |
129 | unsigned int matchsize, | 131 | unsigned int matchsize, |
130 | unsigned int hook_mask) | 132 | unsigned int hook_mask) |
131 | { | 133 | { |
132 | const struct ip6t_ipv6header_info *info = matchinfo; | 134 | const struct ip6t_ipv6header_info *info = matchinfo; |
133 | 135 | ||
134 | /* Check for obvious errors */ | ||
135 | /* This match is valid in all hooks! */ | ||
136 | if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info))) | ||
137 | return 0; | ||
138 | |||
139 | /* invflags is 0 or 0xff in hard mode */ | 136 | /* invflags is 0 or 0xff in hard mode */ |
140 | if ((!info->modeflag) && info->invflags != 0x00 && | 137 | if ((!info->modeflag) && info->invflags != 0x00 && |
141 | info->invflags != 0xFF) | 138 | info->invflags != 0xFF) |
@@ -147,6 +144,7 @@ ipv6header_checkentry(const char *tablename, | |||
147 | static struct ip6t_match ip6t_ipv6header_match = { | 144 | static struct ip6t_match ip6t_ipv6header_match = { |
148 | .name = "ipv6header", | 145 | .name = "ipv6header", |
149 | .match = &ipv6header_match, | 146 | .match = &ipv6header_match, |
147 | .matchsize = sizeof(struct ip6t_ipv6header_info), | ||
150 | .checkentry = &ipv6header_checkentry, | 148 | .checkentry = &ipv6header_checkentry, |
151 | .destroy = NULL, | 149 | .destroy = NULL, |
152 | .me = THIS_MODULE, | 150 | .me = THIS_MODULE, |
diff --git a/net/ipv6/netfilter/ip6t_multiport.c b/net/ipv6/netfilter/ip6t_multiport.c index 49f7829dfbc2..752b65d21c72 100644 --- a/net/ipv6/netfilter/ip6t_multiport.c +++ b/net/ipv6/netfilter/ip6t_multiport.c | |||
@@ -51,6 +51,7 @@ static int | |||
51 | match(const struct sk_buff *skb, | 51 | match(const struct sk_buff *skb, |
52 | const struct net_device *in, | 52 | const struct net_device *in, |
53 | const struct net_device *out, | 53 | const struct net_device *out, |
54 | const struct xt_match *match, | ||
54 | const void *matchinfo, | 55 | const void *matchinfo, |
55 | int offset, | 56 | int offset, |
56 | unsigned int protoff, | 57 | unsigned int protoff, |
@@ -85,6 +86,7 @@ match(const struct sk_buff *skb, | |||
85 | static int | 86 | static int |
86 | checkentry(const char *tablename, | 87 | checkentry(const char *tablename, |
87 | const void *info, | 88 | const void *info, |
89 | const struct xt_match *match, | ||
88 | void *matchinfo, | 90 | void *matchinfo, |
89 | unsigned int matchsize, | 91 | unsigned int matchsize, |
90 | unsigned int hook_mask) | 92 | unsigned int hook_mask) |
@@ -92,13 +94,9 @@ checkentry(const char *tablename, | |||
92 | const struct ip6t_ip6 *ip = info; | 94 | const struct ip6t_ip6 *ip = info; |
93 | const struct ip6t_multiport *multiinfo = matchinfo; | 95 | const struct ip6t_multiport *multiinfo = matchinfo; |
94 | 96 | ||
95 | if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_multiport))) | ||
96 | return 0; | ||
97 | |||
98 | /* Must specify proto == TCP/UDP, no unknown flags or bad count */ | 97 | /* Must specify proto == TCP/UDP, no unknown flags or bad count */ |
99 | return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP) | 98 | return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP) |
100 | && !(ip->invflags & IP6T_INV_PROTO) | 99 | && !(ip->invflags & IP6T_INV_PROTO) |
101 | && matchsize == IP6T_ALIGN(sizeof(struct ip6t_multiport)) | ||
102 | && (multiinfo->flags == IP6T_MULTIPORT_SOURCE | 100 | && (multiinfo->flags == IP6T_MULTIPORT_SOURCE |
103 | || multiinfo->flags == IP6T_MULTIPORT_DESTINATION | 101 | || multiinfo->flags == IP6T_MULTIPORT_DESTINATION |
104 | || multiinfo->flags == IP6T_MULTIPORT_EITHER) | 102 | || multiinfo->flags == IP6T_MULTIPORT_EITHER) |
@@ -107,8 +105,9 @@ checkentry(const char *tablename, | |||
107 | 105 | ||
108 | static struct ip6t_match multiport_match = { | 106 | static struct ip6t_match multiport_match = { |
109 | .name = "multiport", | 107 | .name = "multiport", |
110 | .match = &match, | 108 | .match = match, |
111 | .checkentry = &checkentry, | 109 | .matchsize = sizeof(struct ip6t_multiport), |
110 | .checkentry = checkentry, | ||
112 | .me = THIS_MODULE, | 111 | .me = THIS_MODULE, |
113 | }; | 112 | }; |
114 | 113 | ||
diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c index 8c8a4c7ec934..e2cee3bcdef9 100644 --- a/net/ipv6/netfilter/ip6t_owner.c +++ b/net/ipv6/netfilter/ip6t_owner.c | |||
@@ -26,6 +26,7 @@ static int | |||
26 | match(const struct sk_buff *skb, | 26 | match(const struct sk_buff *skb, |
27 | const struct net_device *in, | 27 | const struct net_device *in, |
28 | const struct net_device *out, | 28 | const struct net_device *out, |
29 | const struct xt_match *match, | ||
29 | const void *matchinfo, | 30 | const void *matchinfo, |
30 | int offset, | 31 | int offset, |
31 | unsigned int protoff, | 32 | unsigned int protoff, |
@@ -54,34 +55,27 @@ match(const struct sk_buff *skb, | |||
54 | static int | 55 | static int |
55 | checkentry(const char *tablename, | 56 | checkentry(const char *tablename, |
56 | const void *ip, | 57 | const void *ip, |
58 | const struct xt_match *match, | ||
57 | void *matchinfo, | 59 | void *matchinfo, |
58 | unsigned int matchsize, | 60 | unsigned int matchsize, |
59 | unsigned int hook_mask) | 61 | unsigned int hook_mask) |
60 | { | 62 | { |
61 | const struct ip6t_owner_info *info = matchinfo; | 63 | const struct ip6t_owner_info *info = matchinfo; |
62 | 64 | ||
63 | if (hook_mask | ||
64 | & ~((1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING))) { | ||
65 | printk("ip6t_owner: only valid for LOCAL_OUT or POST_ROUTING.\n"); | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_owner_info))) | ||
70 | return 0; | ||
71 | |||
72 | if (info->match & (IP6T_OWNER_PID | IP6T_OWNER_SID)) { | 65 | if (info->match & (IP6T_OWNER_PID | IP6T_OWNER_SID)) { |
73 | printk("ipt_owner: pid and sid matching " | 66 | printk("ipt_owner: pid and sid matching " |
74 | "not supported anymore\n"); | 67 | "not supported anymore\n"); |
75 | return 0; | 68 | return 0; |
76 | } | 69 | } |
77 | |||
78 | return 1; | 70 | return 1; |
79 | } | 71 | } |
80 | 72 | ||
81 | static struct ip6t_match owner_match = { | 73 | static struct ip6t_match owner_match = { |
82 | .name = "owner", | 74 | .name = "owner", |
83 | .match = &match, | 75 | .match = match, |
84 | .checkentry = &checkentry, | 76 | .matchsize = sizeof(struct ip6t_owner_info), |
77 | .hooks = (1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING), | ||
78 | .checkentry = checkentry, | ||
85 | .me = THIS_MODULE, | 79 | .me = THIS_MODULE, |
86 | }; | 80 | }; |
87 | 81 | ||
diff --git a/net/ipv6/netfilter/ip6t_policy.c b/net/ipv6/netfilter/ip6t_policy.c deleted file mode 100644 index 3d39ec924041..000000000000 --- a/net/ipv6/netfilter/ip6t_policy.c +++ /dev/null | |||
@@ -1,176 +0,0 @@ | |||
1 | /* IP tables module for matching IPsec policy | ||
2 | * | ||
3 | * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/skbuff.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <net/xfrm.h> | ||
16 | |||
17 | #include <linux/netfilter_ipv6.h> | ||
18 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
19 | #include <linux/netfilter_ipv6/ip6t_policy.h> | ||
20 | |||
21 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
22 | MODULE_DESCRIPTION("IPtables IPsec policy matching module"); | ||
23 | MODULE_LICENSE("GPL"); | ||
24 | |||
25 | |||
26 | static inline int | ||
27 | match_xfrm_state(struct xfrm_state *x, const struct ip6t_policy_elem *e) | ||
28 | { | ||
29 | #define MATCH_ADDR(x,y,z) (!e->match.x || \ | ||
30 | ((!ip6_masked_addrcmp(&e->x.a6, &e->y.a6, z)) \ | ||
31 | ^ e->invert.x)) | ||
32 | #define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x)) | ||
33 | |||
34 | return MATCH_ADDR(saddr, smask, (struct in6_addr *)&x->props.saddr.a6) && | ||
35 | MATCH_ADDR(daddr, dmask, (struct in6_addr *)&x->id.daddr.a6) && | ||
36 | MATCH(proto, x->id.proto) && | ||
37 | MATCH(mode, x->props.mode) && | ||
38 | MATCH(spi, x->id.spi) && | ||
39 | MATCH(reqid, x->props.reqid); | ||
40 | } | ||
41 | |||
42 | static int | ||
43 | match_policy_in(const struct sk_buff *skb, const struct ip6t_policy_info *info) | ||
44 | { | ||
45 | const struct ip6t_policy_elem *e; | ||
46 | struct sec_path *sp = skb->sp; | ||
47 | int strict = info->flags & IP6T_POLICY_MATCH_STRICT; | ||
48 | int i, pos; | ||
49 | |||
50 | if (sp == NULL) | ||
51 | return -1; | ||
52 | if (strict && info->len != sp->len) | ||
53 | return 0; | ||
54 | |||
55 | for (i = sp->len - 1; i >= 0; i--) { | ||
56 | pos = strict ? i - sp->len + 1 : 0; | ||
57 | if (pos >= info->len) | ||
58 | return 0; | ||
59 | e = &info->pol[pos]; | ||
60 | |||
61 | if (match_xfrm_state(sp->x[i].xvec, e)) { | ||
62 | if (!strict) | ||
63 | return 1; | ||
64 | } else if (strict) | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | return strict ? 1 : 0; | ||
69 | } | ||
70 | |||
71 | static int | ||
72 | match_policy_out(const struct sk_buff *skb, const struct ip6t_policy_info *info) | ||
73 | { | ||
74 | const struct ip6t_policy_elem *e; | ||
75 | struct dst_entry *dst = skb->dst; | ||
76 | int strict = info->flags & IP6T_POLICY_MATCH_STRICT; | ||
77 | int i, pos; | ||
78 | |||
79 | if (dst->xfrm == NULL) | ||
80 | return -1; | ||
81 | |||
82 | for (i = 0; dst && dst->xfrm; dst = dst->child, i++) { | ||
83 | pos = strict ? i : 0; | ||
84 | if (pos >= info->len) | ||
85 | return 0; | ||
86 | e = &info->pol[pos]; | ||
87 | |||
88 | if (match_xfrm_state(dst->xfrm, e)) { | ||
89 | if (!strict) | ||
90 | return 1; | ||
91 | } else if (strict) | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | return strict ? i == info->len : 0; | ||
96 | } | ||
97 | |||
98 | static int match(const struct sk_buff *skb, | ||
99 | const struct net_device *in, | ||
100 | const struct net_device *out, | ||
101 | const void *matchinfo, | ||
102 | int offset, | ||
103 | unsigned int protoff, | ||
104 | int *hotdrop) | ||
105 | { | ||
106 | const struct ip6t_policy_info *info = matchinfo; | ||
107 | int ret; | ||
108 | |||
109 | if (info->flags & IP6T_POLICY_MATCH_IN) | ||
110 | ret = match_policy_in(skb, info); | ||
111 | else | ||
112 | ret = match_policy_out(skb, info); | ||
113 | |||
114 | if (ret < 0) | ||
115 | ret = info->flags & IP6T_POLICY_MATCH_NONE ? 1 : 0; | ||
116 | else if (info->flags & IP6T_POLICY_MATCH_NONE) | ||
117 | ret = 0; | ||
118 | |||
119 | return ret; | ||
120 | } | ||
121 | |||
122 | static int checkentry(const char *tablename, const void *ip_void, | ||
123 | void *matchinfo, unsigned int matchsize, | ||
124 | unsigned int hook_mask) | ||
125 | { | ||
126 | struct ip6t_policy_info *info = matchinfo; | ||
127 | |||
128 | if (matchsize != IP6T_ALIGN(sizeof(*info))) { | ||
129 | printk(KERN_ERR "ip6t_policy: matchsize %u != %zu\n", | ||
130 | matchsize, IP6T_ALIGN(sizeof(*info))); | ||
131 | return 0; | ||
132 | } | ||
133 | if (!(info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT))) { | ||
134 | printk(KERN_ERR "ip6t_policy: neither incoming nor " | ||
135 | "outgoing policy selected\n"); | ||
136 | return 0; | ||
137 | } | ||
138 | if (hook_mask & (1 << NF_IP6_PRE_ROUTING | 1 << NF_IP6_LOCAL_IN) | ||
139 | && info->flags & IP6T_POLICY_MATCH_OUT) { | ||
140 | printk(KERN_ERR "ip6t_policy: output policy not valid in " | ||
141 | "PRE_ROUTING and INPUT\n"); | ||
142 | return 0; | ||
143 | } | ||
144 | if (hook_mask & (1 << NF_IP6_POST_ROUTING | 1 << NF_IP6_LOCAL_OUT) | ||
145 | && info->flags & IP6T_POLICY_MATCH_IN) { | ||
146 | printk(KERN_ERR "ip6t_policy: input policy not valid in " | ||
147 | "POST_ROUTING and OUTPUT\n"); | ||
148 | return 0; | ||
149 | } | ||
150 | if (info->len > IP6T_POLICY_MAX_ELEM) { | ||
151 | printk(KERN_ERR "ip6t_policy: too many policy elements\n"); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | return 1; | ||
156 | } | ||
157 | |||
158 | static struct ip6t_match policy_match = { | ||
159 | .name = "policy", | ||
160 | .match = match, | ||
161 | .checkentry = checkentry, | ||
162 | .me = THIS_MODULE, | ||
163 | }; | ||
164 | |||
165 | static int __init init(void) | ||
166 | { | ||
167 | return ip6t_register_match(&policy_match); | ||
168 | } | ||
169 | |||
170 | static void __exit fini(void) | ||
171 | { | ||
172 | ip6t_unregister_match(&policy_match); | ||
173 | } | ||
174 | |||
175 | module_init(init); | ||
176 | module_exit(fini); | ||
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index 8f82476dc89e..4c6b55bb225b 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c | |||
@@ -45,6 +45,7 @@ static int | |||
45 | match(const struct sk_buff *skb, | 45 | match(const struct sk_buff *skb, |
46 | const struct net_device *in, | 46 | const struct net_device *in, |
47 | const struct net_device *out, | 47 | const struct net_device *out, |
48 | const struct xt_match *match, | ||
48 | const void *matchinfo, | 49 | const void *matchinfo, |
49 | int offset, | 50 | int offset, |
50 | unsigned int protoff, | 51 | unsigned int protoff, |
@@ -194,17 +195,13 @@ match(const struct sk_buff *skb, | |||
194 | static int | 195 | static int |
195 | checkentry(const char *tablename, | 196 | checkentry(const char *tablename, |
196 | const void *entry, | 197 | const void *entry, |
198 | const struct xt_match *match, | ||
197 | void *matchinfo, | 199 | void *matchinfo, |
198 | unsigned int matchinfosize, | 200 | unsigned int matchinfosize, |
199 | unsigned int hook_mask) | 201 | unsigned int hook_mask) |
200 | { | 202 | { |
201 | const struct ip6t_rt *rtinfo = matchinfo; | 203 | const struct ip6t_rt *rtinfo = matchinfo; |
202 | 204 | ||
203 | if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_rt))) { | ||
204 | DEBUGP("ip6t_rt: matchsize %u != %u\n", | ||
205 | matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_rt))); | ||
206 | return 0; | ||
207 | } | ||
208 | if (rtinfo->invflags & ~IP6T_RT_INV_MASK) { | 205 | if (rtinfo->invflags & ~IP6T_RT_INV_MASK) { |
209 | DEBUGP("ip6t_rt: unknown flags %X\n", rtinfo->invflags); | 206 | DEBUGP("ip6t_rt: unknown flags %X\n", rtinfo->invflags); |
210 | return 0; | 207 | return 0; |
@@ -222,8 +219,9 @@ checkentry(const char *tablename, | |||
222 | 219 | ||
223 | static struct ip6t_match rt_match = { | 220 | static struct ip6t_match rt_match = { |
224 | .name = "rt", | 221 | .name = "rt", |
225 | .match = &match, | 222 | .match = match, |
226 | .checkentry = &checkentry, | 223 | .matchsize = sizeof(struct ip6t_rt), |
224 | .checkentry = checkentry, | ||
227 | .me = THIS_MODULE, | 225 | .me = THIS_MODULE, |
228 | }; | 226 | }; |
229 | 227 | ||
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index ac702a29dd16..c16f62934bd9 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -179,31 +179,36 @@ static unsigned int ipv6_confirm(unsigned int hooknum, | |||
179 | int (*okfn)(struct sk_buff *)) | 179 | int (*okfn)(struct sk_buff *)) |
180 | { | 180 | { |
181 | struct nf_conn *ct; | 181 | struct nf_conn *ct; |
182 | struct nf_conn_help *help; | ||
182 | enum ip_conntrack_info ctinfo; | 183 | enum ip_conntrack_info ctinfo; |
184 | unsigned int ret, protoff; | ||
185 | unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1) | ||
186 | - (*pskb)->data; | ||
187 | unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr; | ||
188 | |||
183 | 189 | ||
184 | /* This is where we call the helper: as the packet goes out. */ | 190 | /* This is where we call the helper: as the packet goes out. */ |
185 | ct = nf_ct_get(*pskb, &ctinfo); | 191 | ct = nf_ct_get(*pskb, &ctinfo); |
186 | if (ct && ct->helper) { | 192 | if (!ct) |
187 | unsigned int ret, protoff; | 193 | goto out; |
188 | unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1) | ||
189 | - (*pskb)->data; | ||
190 | unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr; | ||
191 | |||
192 | protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, | ||
193 | (*pskb)->len - extoff); | ||
194 | if (protoff < 0 || protoff > (*pskb)->len || | ||
195 | pnum == NEXTHDR_FRAGMENT) { | ||
196 | DEBUGP("proto header not found\n"); | ||
197 | return NF_ACCEPT; | ||
198 | } | ||
199 | 194 | ||
200 | ret = ct->helper->help(pskb, protoff, ct, ctinfo); | 195 | help = nfct_help(ct); |
201 | if (ret != NF_ACCEPT) | 196 | if (!help || !help->helper) |
202 | return ret; | 197 | goto out; |
198 | |||
199 | protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, | ||
200 | (*pskb)->len - extoff); | ||
201 | if (protoff < 0 || protoff > (*pskb)->len || | ||
202 | pnum == NEXTHDR_FRAGMENT) { | ||
203 | DEBUGP("proto header not found\n"); | ||
204 | return NF_ACCEPT; | ||
203 | } | 205 | } |
204 | 206 | ||
207 | ret = help->helper->help(pskb, protoff, ct, ctinfo); | ||
208 | if (ret != NF_ACCEPT) | ||
209 | return ret; | ||
210 | out: | ||
205 | /* We've seen it coming out the other side: confirm it */ | 211 | /* We've seen it coming out the other side: confirm it */ |
206 | |||
207 | return nf_conntrack_confirm(pskb); | 212 | return nf_conntrack_confirm(pskb); |
208 | } | 213 | } |
209 | 214 | ||
@@ -579,6 +584,7 @@ static int init_or_cleanup(int init) | |||
579 | return ret; | 584 | return ret; |
580 | } | 585 | } |
581 | 586 | ||
587 | MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); | ||
582 | MODULE_LICENSE("GPL"); | 588 | MODULE_LICENSE("GPL"); |
583 | MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>"); | 589 | MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>"); |
584 | 590 | ||
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 84ef9a13108d..3e319035f82d 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -313,8 +313,8 @@ static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash, | |||
313 | #ifdef CONFIG_SMP | 313 | #ifdef CONFIG_SMP |
314 | hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) { | 314 | hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) { |
315 | if (fq->id == fq_in->id && | 315 | if (fq->id == fq_in->id && |
316 | !ipv6_addr_cmp(&fq_in->saddr, &fq->saddr) && | 316 | ipv6_addr_equal(&fq_in->saddr, &fq->saddr) && |
317 | !ipv6_addr_cmp(&fq_in->daddr, &fq->daddr)) { | 317 | ipv6_addr_equal(&fq_in->daddr, &fq->daddr)) { |
318 | atomic_inc(&fq->refcnt); | 318 | atomic_inc(&fq->refcnt); |
319 | write_unlock(&nf_ct_frag6_lock); | 319 | write_unlock(&nf_ct_frag6_lock); |
320 | fq_in->last_in |= COMPLETE; | 320 | fq_in->last_in |= COMPLETE; |
@@ -376,8 +376,8 @@ fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst) | |||
376 | read_lock(&nf_ct_frag6_lock); | 376 | read_lock(&nf_ct_frag6_lock); |
377 | hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) { | 377 | hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) { |
378 | if (fq->id == id && | 378 | if (fq->id == id && |
379 | !ipv6_addr_cmp(src, &fq->saddr) && | 379 | ipv6_addr_equal(src, &fq->saddr) && |
380 | !ipv6_addr_cmp(dst, &fq->daddr)) { | 380 | ipv6_addr_equal(dst, &fq->daddr)) { |
381 | atomic_inc(&fq->refcnt); | 381 | atomic_inc(&fq->refcnt); |
382 | read_unlock(&nf_ct_frag6_lock); | 382 | read_unlock(&nf_ct_frag6_lock); |
383 | return fq; | 383 | return fq; |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index ae20a0ec9bd8..fa1ce0ae123e 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -859,29 +859,12 @@ static int rawv6_geticmpfilter(struct sock *sk, int level, int optname, | |||
859 | } | 859 | } |
860 | 860 | ||
861 | 861 | ||
862 | static int rawv6_setsockopt(struct sock *sk, int level, int optname, | 862 | static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, |
863 | char __user *optval, int optlen) | 863 | char __user *optval, int optlen) |
864 | { | 864 | { |
865 | struct raw6_sock *rp = raw6_sk(sk); | 865 | struct raw6_sock *rp = raw6_sk(sk); |
866 | int val; | 866 | int val; |
867 | 867 | ||
868 | switch(level) { | ||
869 | case SOL_RAW: | ||
870 | break; | ||
871 | |||
872 | case SOL_ICMPV6: | ||
873 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | ||
874 | return -EOPNOTSUPP; | ||
875 | return rawv6_seticmpfilter(sk, level, optname, optval, | ||
876 | optlen); | ||
877 | case SOL_IPV6: | ||
878 | if (optname == IPV6_CHECKSUM) | ||
879 | break; | ||
880 | default: | ||
881 | return ipv6_setsockopt(sk, level, optname, optval, | ||
882 | optlen); | ||
883 | }; | ||
884 | |||
885 | if (get_user(val, (int __user *)optval)) | 868 | if (get_user(val, (int __user *)optval)) |
886 | return -EFAULT; | 869 | return -EFAULT; |
887 | 870 | ||
@@ -906,12 +889,9 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
906 | } | 889 | } |
907 | } | 890 | } |
908 | 891 | ||
909 | static int rawv6_getsockopt(struct sock *sk, int level, int optname, | 892 | static int rawv6_setsockopt(struct sock *sk, int level, int optname, |
910 | char __user *optval, int __user *optlen) | 893 | char __user *optval, int optlen) |
911 | { | 894 | { |
912 | struct raw6_sock *rp = raw6_sk(sk); | ||
913 | int val, len; | ||
914 | |||
915 | switch(level) { | 895 | switch(level) { |
916 | case SOL_RAW: | 896 | case SOL_RAW: |
917 | break; | 897 | break; |
@@ -919,15 +899,45 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname, | |||
919 | case SOL_ICMPV6: | 899 | case SOL_ICMPV6: |
920 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | 900 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) |
921 | return -EOPNOTSUPP; | 901 | return -EOPNOTSUPP; |
922 | return rawv6_geticmpfilter(sk, level, optname, optval, | 902 | return rawv6_seticmpfilter(sk, level, optname, optval, |
923 | optlen); | 903 | optlen); |
924 | case SOL_IPV6: | 904 | case SOL_IPV6: |
925 | if (optname == IPV6_CHECKSUM) | 905 | if (optname == IPV6_CHECKSUM) |
926 | break; | 906 | break; |
927 | default: | 907 | default: |
928 | return ipv6_getsockopt(sk, level, optname, optval, | 908 | return ipv6_setsockopt(sk, level, optname, optval, |
929 | optlen); | 909 | optlen); |
930 | }; | 910 | }; |
911 | return do_rawv6_setsockopt(sk, level, optname, optval, optlen); | ||
912 | } | ||
913 | |||
914 | #ifdef CONFIG_COMPAT | ||
915 | static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname, | ||
916 | char __user *optval, int optlen) | ||
917 | { | ||
918 | switch (level) { | ||
919 | case SOL_RAW: | ||
920 | break; | ||
921 | case SOL_ICMPV6: | ||
922 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | ||
923 | return -EOPNOTSUPP; | ||
924 | return rawv6_seticmpfilter(sk, level, optname, optval, optlen); | ||
925 | case SOL_IPV6: | ||
926 | if (optname == IPV6_CHECKSUM) | ||
927 | break; | ||
928 | default: | ||
929 | return compat_ipv6_setsockopt(sk, level, optname, | ||
930 | optval, optlen); | ||
931 | }; | ||
932 | return do_rawv6_setsockopt(sk, level, optname, optval, optlen); | ||
933 | } | ||
934 | #endif | ||
935 | |||
936 | static int do_rawv6_getsockopt(struct sock *sk, int level, int optname, | ||
937 | char __user *optval, int __user *optlen) | ||
938 | { | ||
939 | struct raw6_sock *rp = raw6_sk(sk); | ||
940 | int val, len; | ||
931 | 941 | ||
932 | if (get_user(len,optlen)) | 942 | if (get_user(len,optlen)) |
933 | return -EFAULT; | 943 | return -EFAULT; |
@@ -953,6 +963,50 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname, | |||
953 | return 0; | 963 | return 0; |
954 | } | 964 | } |
955 | 965 | ||
966 | static int rawv6_getsockopt(struct sock *sk, int level, int optname, | ||
967 | char __user *optval, int __user *optlen) | ||
968 | { | ||
969 | switch(level) { | ||
970 | case SOL_RAW: | ||
971 | break; | ||
972 | |||
973 | case SOL_ICMPV6: | ||
974 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | ||
975 | return -EOPNOTSUPP; | ||
976 | return rawv6_geticmpfilter(sk, level, optname, optval, | ||
977 | optlen); | ||
978 | case SOL_IPV6: | ||
979 | if (optname == IPV6_CHECKSUM) | ||
980 | break; | ||
981 | default: | ||
982 | return ipv6_getsockopt(sk, level, optname, optval, | ||
983 | optlen); | ||
984 | }; | ||
985 | return do_rawv6_getsockopt(sk, level, optname, optval, optlen); | ||
986 | } | ||
987 | |||
988 | #ifdef CONFIG_COMPAT | ||
989 | static int compat_rawv6_getsockopt(struct sock *sk, int level, int optname, | ||
990 | char __user *optval, int __user *optlen) | ||
991 | { | ||
992 | switch (level) { | ||
993 | case SOL_RAW: | ||
994 | break; | ||
995 | case SOL_ICMPV6: | ||
996 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | ||
997 | return -EOPNOTSUPP; | ||
998 | return rawv6_geticmpfilter(sk, level, optname, optval, optlen); | ||
999 | case SOL_IPV6: | ||
1000 | if (optname == IPV6_CHECKSUM) | ||
1001 | break; | ||
1002 | default: | ||
1003 | return compat_ipv6_getsockopt(sk, level, optname, | ||
1004 | optval, optlen); | ||
1005 | }; | ||
1006 | return do_rawv6_getsockopt(sk, level, optname, optval, optlen); | ||
1007 | } | ||
1008 | #endif | ||
1009 | |||
956 | static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) | 1010 | static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) |
957 | { | 1011 | { |
958 | switch(cmd) { | 1012 | switch(cmd) { |
@@ -998,23 +1052,27 @@ static int rawv6_init_sk(struct sock *sk) | |||
998 | } | 1052 | } |
999 | 1053 | ||
1000 | struct proto rawv6_prot = { | 1054 | struct proto rawv6_prot = { |
1001 | .name = "RAWv6", | 1055 | .name = "RAWv6", |
1002 | .owner = THIS_MODULE, | 1056 | .owner = THIS_MODULE, |
1003 | .close = rawv6_close, | 1057 | .close = rawv6_close, |
1004 | .connect = ip6_datagram_connect, | 1058 | .connect = ip6_datagram_connect, |
1005 | .disconnect = udp_disconnect, | 1059 | .disconnect = udp_disconnect, |
1006 | .ioctl = rawv6_ioctl, | 1060 | .ioctl = rawv6_ioctl, |
1007 | .init = rawv6_init_sk, | 1061 | .init = rawv6_init_sk, |
1008 | .destroy = inet6_destroy_sock, | 1062 | .destroy = inet6_destroy_sock, |
1009 | .setsockopt = rawv6_setsockopt, | 1063 | .setsockopt = rawv6_setsockopt, |
1010 | .getsockopt = rawv6_getsockopt, | 1064 | .getsockopt = rawv6_getsockopt, |
1011 | .sendmsg = rawv6_sendmsg, | 1065 | .sendmsg = rawv6_sendmsg, |
1012 | .recvmsg = rawv6_recvmsg, | 1066 | .recvmsg = rawv6_recvmsg, |
1013 | .bind = rawv6_bind, | 1067 | .bind = rawv6_bind, |
1014 | .backlog_rcv = rawv6_rcv_skb, | 1068 | .backlog_rcv = rawv6_rcv_skb, |
1015 | .hash = raw_v6_hash, | 1069 | .hash = raw_v6_hash, |
1016 | .unhash = raw_v6_unhash, | 1070 | .unhash = raw_v6_unhash, |
1017 | .obj_size = sizeof(struct raw6_sock), | 1071 | .obj_size = sizeof(struct raw6_sock), |
1072 | #ifdef CONFIG_COMPAT | ||
1073 | .compat_setsockopt = compat_rawv6_setsockopt, | ||
1074 | .compat_getsockopt = compat_rawv6_getsockopt, | ||
1075 | #endif | ||
1018 | }; | 1076 | }; |
1019 | 1077 | ||
1020 | #ifdef CONFIG_PROC_FS | 1078 | #ifdef CONFIG_PROC_FS |
@@ -1140,7 +1198,7 @@ static int raw6_seq_open(struct inode *inode, struct file *file) | |||
1140 | { | 1198 | { |
1141 | struct seq_file *seq; | 1199 | struct seq_file *seq; |
1142 | int rc = -ENOMEM; | 1200 | int rc = -ENOMEM; |
1143 | struct raw6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); | 1201 | struct raw6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); |
1144 | if (!s) | 1202 | if (!s) |
1145 | goto out; | 1203 | goto out; |
1146 | rc = seq_open(file, &raw6_seq_ops); | 1204 | rc = seq_open(file, &raw6_seq_ops); |
@@ -1148,7 +1206,6 @@ static int raw6_seq_open(struct inode *inode, struct file *file) | |||
1148 | goto out_kfree; | 1206 | goto out_kfree; |
1149 | seq = file->private_data; | 1207 | seq = file->private_data; |
1150 | seq->private = s; | 1208 | seq->private = s; |
1151 | memset(s, 0, sizeof(*s)); | ||
1152 | out: | 1209 | out: |
1153 | return rc; | 1210 | return rc; |
1154 | out_kfree: | 1211 | out_kfree: |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 15e1456b3f18..b67a45fb93e9 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -203,7 +203,7 @@ static inline void frag_free_queue(struct frag_queue *fq, int *work) | |||
203 | 203 | ||
204 | static inline struct frag_queue *frag_alloc_queue(void) | 204 | static inline struct frag_queue *frag_alloc_queue(void) |
205 | { | 205 | { |
206 | struct frag_queue *fq = kmalloc(sizeof(struct frag_queue), GFP_ATOMIC); | 206 | struct frag_queue *fq = kzalloc(sizeof(struct frag_queue), GFP_ATOMIC); |
207 | 207 | ||
208 | if(!fq) | 208 | if(!fq) |
209 | return NULL; | 209 | return NULL; |
@@ -288,6 +288,7 @@ static void ip6_evictor(void) | |||
288 | static void ip6_frag_expire(unsigned long data) | 288 | static void ip6_frag_expire(unsigned long data) |
289 | { | 289 | { |
290 | struct frag_queue *fq = (struct frag_queue *) data; | 290 | struct frag_queue *fq = (struct frag_queue *) data; |
291 | struct net_device *dev; | ||
291 | 292 | ||
292 | spin_lock(&fq->lock); | 293 | spin_lock(&fq->lock); |
293 | 294 | ||
@@ -299,22 +300,22 @@ static void ip6_frag_expire(unsigned long data) | |||
299 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT); | 300 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT); |
300 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); | 301 | IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); |
301 | 302 | ||
302 | /* Send error only if the first segment arrived. */ | 303 | /* Don't send error if the first segment did not arrive. */ |
303 | if (fq->last_in&FIRST_IN && fq->fragments) { | 304 | if (!(fq->last_in&FIRST_IN) || !fq->fragments) |
304 | struct net_device *dev = dev_get_by_index(fq->iif); | 305 | goto out; |
305 | 306 | ||
306 | /* | 307 | dev = dev_get_by_index(fq->iif); |
307 | But use as source device on which LAST ARRIVED | 308 | if (!dev) |
308 | segment was received. And do not use fq->dev | 309 | goto out; |
309 | pointer directly, device might already disappeared. | 310 | |
310 | */ | 311 | /* |
311 | if (dev) { | 312 | But use as source device on which LAST ARRIVED |
312 | fq->fragments->dev = dev; | 313 | segment was received. And do not use fq->dev |
313 | icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, | 314 | pointer directly, device might already disappeared. |
314 | dev); | 315 | */ |
315 | dev_put(dev); | 316 | fq->fragments->dev = dev; |
316 | } | 317 | icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev); |
317 | } | 318 | dev_put(dev); |
318 | out: | 319 | out: |
319 | spin_unlock(&fq->lock); | 320 | spin_unlock(&fq->lock); |
320 | fq_put(fq, NULL); | 321 | fq_put(fq, NULL); |
@@ -368,8 +369,6 @@ ip6_frag_create(unsigned int hash, u32 id, struct in6_addr *src, struct in6_addr | |||
368 | if ((fq = frag_alloc_queue()) == NULL) | 369 | if ((fq = frag_alloc_queue()) == NULL) |
369 | goto oom; | 370 | goto oom; |
370 | 371 | ||
371 | memset(fq, 0, sizeof(struct frag_queue)); | ||
372 | |||
373 | fq->id = id; | 372 | fq->id = id; |
374 | ipv6_addr_copy(&fq->saddr, src); | 373 | ipv6_addr_copy(&fq->saddr, src); |
375 | ipv6_addr_copy(&fq->daddr, dst); | 374 | ipv6_addr_copy(&fq->daddr, dst); |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e0d3ad02ffb5..79078747a646 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -72,6 +72,10 @@ | |||
72 | #define RT6_TRACE(x...) do { ; } while (0) | 72 | #define RT6_TRACE(x...) do { ; } while (0) |
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | #define CLONE_OFFLINK_ROUTE 0 | ||
76 | |||
77 | #define RT6_SELECT_F_IFACE 0x1 | ||
78 | #define RT6_SELECT_F_REACHABLE 0x2 | ||
75 | 79 | ||
76 | static int ip6_rt_max_size = 4096; | 80 | static int ip6_rt_max_size = 4096; |
77 | static int ip6_rt_gc_min_interval = HZ / 2; | 81 | static int ip6_rt_gc_min_interval = HZ / 2; |
@@ -94,6 +98,14 @@ static int ip6_pkt_discard_out(struct sk_buff *skb); | |||
94 | static void ip6_link_failure(struct sk_buff *skb); | 98 | static void ip6_link_failure(struct sk_buff *skb); |
95 | static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); | 99 | static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); |
96 | 100 | ||
101 | #ifdef CONFIG_IPV6_ROUTE_INFO | ||
102 | static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen, | ||
103 | struct in6_addr *gwaddr, int ifindex, | ||
104 | unsigned pref); | ||
105 | static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen, | ||
106 | struct in6_addr *gwaddr, int ifindex); | ||
107 | #endif | ||
108 | |||
97 | static struct dst_ops ip6_dst_ops = { | 109 | static struct dst_ops ip6_dst_ops = { |
98 | .family = AF_INET6, | 110 | .family = AF_INET6, |
99 | .protocol = __constant_htons(ETH_P_IPV6), | 111 | .protocol = __constant_htons(ETH_P_IPV6), |
@@ -214,150 +226,211 @@ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, | |||
214 | return rt; | 226 | return rt; |
215 | } | 227 | } |
216 | 228 | ||
229 | #ifdef CONFIG_IPV6_ROUTER_PREF | ||
230 | static void rt6_probe(struct rt6_info *rt) | ||
231 | { | ||
232 | struct neighbour *neigh = rt ? rt->rt6i_nexthop : NULL; | ||
233 | /* | ||
234 | * Okay, this does not seem to be appropriate | ||
235 | * for now, however, we need to check if it | ||
236 | * is really so; aka Router Reachability Probing. | ||
237 | * | ||
238 | * Router Reachability Probe MUST be rate-limited | ||
239 | * to no more than one per minute. | ||
240 | */ | ||
241 | if (!neigh || (neigh->nud_state & NUD_VALID)) | ||
242 | return; | ||
243 | read_lock_bh(&neigh->lock); | ||
244 | if (!(neigh->nud_state & NUD_VALID) && | ||
245 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { | ||
246 | struct in6_addr mcaddr; | ||
247 | struct in6_addr *target; | ||
248 | |||
249 | neigh->updated = jiffies; | ||
250 | read_unlock_bh(&neigh->lock); | ||
251 | |||
252 | target = (struct in6_addr *)&neigh->primary_key; | ||
253 | addrconf_addr_solict_mult(target, &mcaddr); | ||
254 | ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL); | ||
255 | } else | ||
256 | read_unlock_bh(&neigh->lock); | ||
257 | } | ||
258 | #else | ||
259 | static inline void rt6_probe(struct rt6_info *rt) | ||
260 | { | ||
261 | return; | ||
262 | } | ||
263 | #endif | ||
264 | |||
217 | /* | 265 | /* |
218 | * pointer to the last default router chosen. BH is disabled locally. | 266 | * Default Router Selection (RFC 2461 6.3.6) |
219 | */ | 267 | */ |
220 | static struct rt6_info *rt6_dflt_pointer; | 268 | static int inline rt6_check_dev(struct rt6_info *rt, int oif) |
221 | static DEFINE_SPINLOCK(rt6_dflt_lock); | 269 | { |
270 | struct net_device *dev = rt->rt6i_dev; | ||
271 | if (!oif || dev->ifindex == oif) | ||
272 | return 2; | ||
273 | if ((dev->flags & IFF_LOOPBACK) && | ||
274 | rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif) | ||
275 | return 1; | ||
276 | return 0; | ||
277 | } | ||
222 | 278 | ||
223 | void rt6_reset_dflt_pointer(struct rt6_info *rt) | 279 | static int inline rt6_check_neigh(struct rt6_info *rt) |
224 | { | 280 | { |
225 | spin_lock_bh(&rt6_dflt_lock); | 281 | struct neighbour *neigh = rt->rt6i_nexthop; |
226 | if (rt == NULL || rt == rt6_dflt_pointer) { | 282 | int m = 0; |
227 | RT6_TRACE("reset default router: %p->NULL\n", rt6_dflt_pointer); | 283 | if (neigh) { |
228 | rt6_dflt_pointer = NULL; | 284 | read_lock_bh(&neigh->lock); |
285 | if (neigh->nud_state & NUD_VALID) | ||
286 | m = 1; | ||
287 | read_unlock_bh(&neigh->lock); | ||
229 | } | 288 | } |
230 | spin_unlock_bh(&rt6_dflt_lock); | 289 | return m; |
231 | } | 290 | } |
232 | 291 | ||
233 | /* Default Router Selection (RFC 2461 6.3.6) */ | 292 | static int rt6_score_route(struct rt6_info *rt, int oif, |
234 | static struct rt6_info *rt6_best_dflt(struct rt6_info *rt, int oif) | 293 | int strict) |
235 | { | 294 | { |
236 | struct rt6_info *match = NULL; | 295 | int m = rt6_check_dev(rt, oif); |
237 | struct rt6_info *sprt; | 296 | if (!m && (strict & RT6_SELECT_F_IFACE)) |
238 | int mpri = 0; | 297 | return -1; |
239 | 298 | #ifdef CONFIG_IPV6_ROUTER_PREF | |
240 | for (sprt = rt; sprt; sprt = sprt->u.next) { | 299 | m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2; |
241 | struct neighbour *neigh; | 300 | #endif |
242 | int m = 0; | 301 | if (rt6_check_neigh(rt)) |
243 | 302 | m |= 16; | |
244 | if (!oif || | 303 | else if (strict & RT6_SELECT_F_REACHABLE) |
245 | (sprt->rt6i_dev && | 304 | return -1; |
246 | sprt->rt6i_dev->ifindex == oif)) | 305 | return m; |
247 | m += 8; | 306 | } |
248 | 307 | ||
249 | if (rt6_check_expired(sprt)) | 308 | static struct rt6_info *rt6_select(struct rt6_info **head, int oif, |
250 | continue; | 309 | int strict) |
310 | { | ||
311 | struct rt6_info *match = NULL, *last = NULL; | ||
312 | struct rt6_info *rt, *rt0 = *head; | ||
313 | u32 metric; | ||
314 | int mpri = -1; | ||
251 | 315 | ||
252 | if (sprt == rt6_dflt_pointer) | 316 | RT6_TRACE("%s(head=%p(*head=%p), oif=%d)\n", |
253 | m += 4; | 317 | __FUNCTION__, head, head ? *head : NULL, oif); |
254 | 318 | ||
255 | if ((neigh = sprt->rt6i_nexthop) != NULL) { | 319 | for (rt = rt0, metric = rt0->rt6i_metric; |
256 | read_lock_bh(&neigh->lock); | 320 | rt && rt->rt6i_metric == metric; |
257 | switch (neigh->nud_state) { | 321 | rt = rt->u.next) { |
258 | case NUD_REACHABLE: | 322 | int m; |
259 | m += 3; | ||
260 | break; | ||
261 | 323 | ||
262 | case NUD_STALE: | 324 | if (rt6_check_expired(rt)) |
263 | case NUD_DELAY: | 325 | continue; |
264 | case NUD_PROBE: | ||
265 | m += 2; | ||
266 | break; | ||
267 | 326 | ||
268 | case NUD_NOARP: | 327 | last = rt; |
269 | case NUD_PERMANENT: | ||
270 | m += 1; | ||
271 | break; | ||
272 | 328 | ||
273 | case NUD_INCOMPLETE: | 329 | m = rt6_score_route(rt, oif, strict); |
274 | default: | 330 | if (m < 0) |
275 | read_unlock_bh(&neigh->lock); | ||
276 | continue; | ||
277 | } | ||
278 | read_unlock_bh(&neigh->lock); | ||
279 | } else { | ||
280 | continue; | 331 | continue; |
281 | } | ||
282 | 332 | ||
283 | if (m > mpri || m >= 12) { | 333 | if (m > mpri) { |
284 | match = sprt; | 334 | rt6_probe(match); |
335 | match = rt; | ||
285 | mpri = m; | 336 | mpri = m; |
286 | if (m >= 12) { | 337 | } else { |
287 | /* we choose the last default router if it | 338 | rt6_probe(rt); |
288 | * is in (probably) reachable state. | ||
289 | * If route changed, we should do pmtu | ||
290 | * discovery. --yoshfuji | ||
291 | */ | ||
292 | break; | ||
293 | } | ||
294 | } | 339 | } |
295 | } | 340 | } |
296 | 341 | ||
297 | spin_lock(&rt6_dflt_lock); | 342 | if (!match && |
298 | if (!match) { | 343 | (strict & RT6_SELECT_F_REACHABLE) && |
299 | /* | 344 | last && last != rt0) { |
300 | * No default routers are known to be reachable. | 345 | /* no entries matched; do round-robin */ |
301 | * SHOULD round robin | 346 | *head = rt0->u.next; |
302 | */ | 347 | rt0->u.next = last->u.next; |
303 | if (rt6_dflt_pointer) { | 348 | last->u.next = rt0; |
304 | for (sprt = rt6_dflt_pointer->u.next; | ||
305 | sprt; sprt = sprt->u.next) { | ||
306 | if (sprt->u.dst.obsolete <= 0 && | ||
307 | sprt->u.dst.error == 0 && | ||
308 | !rt6_check_expired(sprt)) { | ||
309 | match = sprt; | ||
310 | break; | ||
311 | } | ||
312 | } | ||
313 | for (sprt = rt; | ||
314 | !match && sprt; | ||
315 | sprt = sprt->u.next) { | ||
316 | if (sprt->u.dst.obsolete <= 0 && | ||
317 | sprt->u.dst.error == 0 && | ||
318 | !rt6_check_expired(sprt)) { | ||
319 | match = sprt; | ||
320 | break; | ||
321 | } | ||
322 | if (sprt == rt6_dflt_pointer) | ||
323 | break; | ||
324 | } | ||
325 | } | ||
326 | } | 349 | } |
327 | 350 | ||
328 | if (match) { | 351 | RT6_TRACE("%s() => %p, score=%d\n", |
329 | if (rt6_dflt_pointer != match) | 352 | __FUNCTION__, match, mpri); |
330 | RT6_TRACE("changed default router: %p->%p\n", | 353 | |
331 | rt6_dflt_pointer, match); | 354 | return (match ? match : &ip6_null_entry); |
332 | rt6_dflt_pointer = match; | 355 | } |
356 | |||
357 | #ifdef CONFIG_IPV6_ROUTE_INFO | ||
358 | int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, | ||
359 | struct in6_addr *gwaddr) | ||
360 | { | ||
361 | struct route_info *rinfo = (struct route_info *) opt; | ||
362 | struct in6_addr prefix_buf, *prefix; | ||
363 | unsigned int pref; | ||
364 | u32 lifetime; | ||
365 | struct rt6_info *rt; | ||
366 | |||
367 | if (len < sizeof(struct route_info)) { | ||
368 | return -EINVAL; | ||
333 | } | 369 | } |
334 | spin_unlock(&rt6_dflt_lock); | ||
335 | 370 | ||
336 | if (!match) { | 371 | /* Sanity check for prefix_len and length */ |
337 | /* | 372 | if (rinfo->length > 3) { |
338 | * Last Resort: if no default routers found, | 373 | return -EINVAL; |
339 | * use addrconf default route. | 374 | } else if (rinfo->prefix_len > 128) { |
340 | * We don't record this route. | 375 | return -EINVAL; |
341 | */ | 376 | } else if (rinfo->prefix_len > 64) { |
342 | for (sprt = ip6_routing_table.leaf; | 377 | if (rinfo->length < 2) { |
343 | sprt; sprt = sprt->u.next) { | 378 | return -EINVAL; |
344 | if (!rt6_check_expired(sprt) && | ||
345 | (sprt->rt6i_flags & RTF_DEFAULT) && | ||
346 | (!oif || | ||
347 | (sprt->rt6i_dev && | ||
348 | sprt->rt6i_dev->ifindex == oif))) { | ||
349 | match = sprt; | ||
350 | break; | ||
351 | } | ||
352 | } | 379 | } |
353 | if (!match) { | 380 | } else if (rinfo->prefix_len > 0) { |
354 | /* no default route. give up. */ | 381 | if (rinfo->length < 1) { |
355 | match = &ip6_null_entry; | 382 | return -EINVAL; |
356 | } | 383 | } |
357 | } | 384 | } |
358 | 385 | ||
359 | return match; | 386 | pref = rinfo->route_pref; |
387 | if (pref == ICMPV6_ROUTER_PREF_INVALID) | ||
388 | pref = ICMPV6_ROUTER_PREF_MEDIUM; | ||
389 | |||
390 | lifetime = htonl(rinfo->lifetime); | ||
391 | if (lifetime == 0xffffffff) { | ||
392 | /* infinity */ | ||
393 | } else if (lifetime > 0x7fffffff/HZ) { | ||
394 | /* Avoid arithmetic overflow */ | ||
395 | lifetime = 0x7fffffff/HZ - 1; | ||
396 | } | ||
397 | |||
398 | if (rinfo->length == 3) | ||
399 | prefix = (struct in6_addr *)rinfo->prefix; | ||
400 | else { | ||
401 | /* this function is safe */ | ||
402 | ipv6_addr_prefix(&prefix_buf, | ||
403 | (struct in6_addr *)rinfo->prefix, | ||
404 | rinfo->prefix_len); | ||
405 | prefix = &prefix_buf; | ||
406 | } | ||
407 | |||
408 | rt = rt6_get_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex); | ||
409 | |||
410 | if (rt && !lifetime) { | ||
411 | ip6_del_rt(rt, NULL, NULL, NULL); | ||
412 | rt = NULL; | ||
413 | } | ||
414 | |||
415 | if (!rt && lifetime) | ||
416 | rt = rt6_add_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex, | ||
417 | pref); | ||
418 | else if (rt) | ||
419 | rt->rt6i_flags = RTF_ROUTEINFO | | ||
420 | (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); | ||
421 | |||
422 | if (rt) { | ||
423 | if (lifetime == 0xffffffff) { | ||
424 | rt->rt6i_flags &= ~RTF_EXPIRES; | ||
425 | } else { | ||
426 | rt->rt6i_expires = jiffies + HZ * lifetime; | ||
427 | rt->rt6i_flags |= RTF_EXPIRES; | ||
428 | } | ||
429 | dst_release(&rt->u.dst); | ||
430 | } | ||
431 | return 0; | ||
360 | } | 432 | } |
433 | #endif | ||
361 | 434 | ||
362 | struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, | 435 | struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, |
363 | int oif, int strict) | 436 | int oif, int strict) |
@@ -397,14 +470,9 @@ int ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh, | |||
397 | return err; | 470 | return err; |
398 | } | 471 | } |
399 | 472 | ||
400 | /* No rt6_lock! If COW failed, the function returns dead route entry | 473 | static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr, |
401 | with dst->error set to errno value. | 474 | struct in6_addr *saddr) |
402 | */ | ||
403 | |||
404 | static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr, | ||
405 | struct in6_addr *saddr, struct netlink_skb_parms *req) | ||
406 | { | 475 | { |
407 | int err; | ||
408 | struct rt6_info *rt; | 476 | struct rt6_info *rt; |
409 | 477 | ||
410 | /* | 478 | /* |
@@ -435,25 +503,30 @@ static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr, | |||
435 | 503 | ||
436 | rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); | 504 | rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); |
437 | 505 | ||
438 | dst_hold(&rt->u.dst); | 506 | } |
439 | |||
440 | err = ip6_ins_rt(rt, NULL, NULL, req); | ||
441 | if (err == 0) | ||
442 | return rt; | ||
443 | 507 | ||
444 | rt->u.dst.error = err; | 508 | return rt; |
509 | } | ||
445 | 510 | ||
446 | return rt; | 511 | static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *daddr) |
512 | { | ||
513 | struct rt6_info *rt = ip6_rt_copy(ort); | ||
514 | if (rt) { | ||
515 | ipv6_addr_copy(&rt->rt6i_dst.addr, daddr); | ||
516 | rt->rt6i_dst.plen = 128; | ||
517 | rt->rt6i_flags |= RTF_CACHE; | ||
518 | if (rt->rt6i_flags & RTF_REJECT) | ||
519 | rt->u.dst.error = ort->u.dst.error; | ||
520 | rt->u.dst.flags |= DST_HOST; | ||
521 | rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop); | ||
447 | } | 522 | } |
448 | dst_hold(&ip6_null_entry.u.dst); | 523 | return rt; |
449 | return &ip6_null_entry; | ||
450 | } | 524 | } |
451 | 525 | ||
452 | #define BACKTRACK() \ | 526 | #define BACKTRACK() \ |
453 | if (rt == &ip6_null_entry && strict) { \ | 527 | if (rt == &ip6_null_entry) { \ |
454 | while ((fn = fn->parent) != NULL) { \ | 528 | while ((fn = fn->parent) != NULL) { \ |
455 | if (fn->fn_flags & RTN_ROOT) { \ | 529 | if (fn->fn_flags & RTN_ROOT) { \ |
456 | dst_hold(&rt->u.dst); \ | ||
457 | goto out; \ | 530 | goto out; \ |
458 | } \ | 531 | } \ |
459 | if (fn->fn_flags & RTN_RTINFO) \ | 532 | if (fn->fn_flags & RTN_RTINFO) \ |
@@ -465,115 +538,138 @@ if (rt == &ip6_null_entry && strict) { \ | |||
465 | void ip6_route_input(struct sk_buff *skb) | 538 | void ip6_route_input(struct sk_buff *skb) |
466 | { | 539 | { |
467 | struct fib6_node *fn; | 540 | struct fib6_node *fn; |
468 | struct rt6_info *rt; | 541 | struct rt6_info *rt, *nrt; |
469 | int strict; | 542 | int strict; |
470 | int attempts = 3; | 543 | int attempts = 3; |
544 | int err; | ||
545 | int reachable = RT6_SELECT_F_REACHABLE; | ||
471 | 546 | ||
472 | strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL); | 547 | strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0; |
473 | 548 | ||
474 | relookup: | 549 | relookup: |
475 | read_lock_bh(&rt6_lock); | 550 | read_lock_bh(&rt6_lock); |
476 | 551 | ||
552 | restart_2: | ||
477 | fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr, | 553 | fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr, |
478 | &skb->nh.ipv6h->saddr); | 554 | &skb->nh.ipv6h->saddr); |
479 | 555 | ||
480 | restart: | 556 | restart: |
481 | rt = fn->leaf; | 557 | rt = rt6_select(&fn->leaf, skb->dev->ifindex, strict | reachable); |
482 | |||
483 | if ((rt->rt6i_flags & RTF_CACHE)) { | ||
484 | rt = rt6_device_match(rt, skb->dev->ifindex, strict); | ||
485 | BACKTRACK(); | ||
486 | dst_hold(&rt->u.dst); | ||
487 | goto out; | ||
488 | } | ||
489 | |||
490 | rt = rt6_device_match(rt, skb->dev->ifindex, strict); | ||
491 | BACKTRACK(); | 558 | BACKTRACK(); |
559 | if (rt == &ip6_null_entry || | ||
560 | rt->rt6i_flags & RTF_CACHE) | ||
561 | goto out; | ||
492 | 562 | ||
493 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { | 563 | dst_hold(&rt->u.dst); |
494 | struct rt6_info *nrt; | 564 | read_unlock_bh(&rt6_lock); |
495 | dst_hold(&rt->u.dst); | ||
496 | read_unlock_bh(&rt6_lock); | ||
497 | 565 | ||
498 | nrt = rt6_cow(rt, &skb->nh.ipv6h->daddr, | 566 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
499 | &skb->nh.ipv6h->saddr, | 567 | nrt = rt6_alloc_cow(rt, &skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr); |
500 | &NETLINK_CB(skb)); | 568 | else { |
569 | #if CLONE_OFFLINK_ROUTE | ||
570 | nrt = rt6_alloc_clone(rt, &skb->nh.ipv6h->daddr); | ||
571 | #else | ||
572 | goto out2; | ||
573 | #endif | ||
574 | } | ||
501 | 575 | ||
502 | dst_release(&rt->u.dst); | 576 | dst_release(&rt->u.dst); |
503 | rt = nrt; | 577 | rt = nrt ? : &ip6_null_entry; |
504 | 578 | ||
505 | if (rt->u.dst.error != -EEXIST || --attempts <= 0) | 579 | dst_hold(&rt->u.dst); |
580 | if (nrt) { | ||
581 | err = ip6_ins_rt(nrt, NULL, NULL, &NETLINK_CB(skb)); | ||
582 | if (!err) | ||
506 | goto out2; | 583 | goto out2; |
507 | |||
508 | /* Race condition! In the gap, when rt6_lock was | ||
509 | released someone could insert this route. Relookup. | ||
510 | */ | ||
511 | dst_release(&rt->u.dst); | ||
512 | goto relookup; | ||
513 | } | 584 | } |
514 | dst_hold(&rt->u.dst); | 585 | |
586 | if (--attempts <= 0) | ||
587 | goto out2; | ||
588 | |||
589 | /* | ||
590 | * Race condition! In the gap, when rt6_lock was | ||
591 | * released someone could insert this route. Relookup. | ||
592 | */ | ||
593 | dst_release(&rt->u.dst); | ||
594 | goto relookup; | ||
515 | 595 | ||
516 | out: | 596 | out: |
597 | if (reachable) { | ||
598 | reachable = 0; | ||
599 | goto restart_2; | ||
600 | } | ||
601 | dst_hold(&rt->u.dst); | ||
517 | read_unlock_bh(&rt6_lock); | 602 | read_unlock_bh(&rt6_lock); |
518 | out2: | 603 | out2: |
519 | rt->u.dst.lastuse = jiffies; | 604 | rt->u.dst.lastuse = jiffies; |
520 | rt->u.dst.__use++; | 605 | rt->u.dst.__use++; |
521 | skb->dst = (struct dst_entry *) rt; | 606 | skb->dst = (struct dst_entry *) rt; |
607 | return; | ||
522 | } | 608 | } |
523 | 609 | ||
524 | struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) | 610 | struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) |
525 | { | 611 | { |
526 | struct fib6_node *fn; | 612 | struct fib6_node *fn; |
527 | struct rt6_info *rt; | 613 | struct rt6_info *rt, *nrt; |
528 | int strict; | 614 | int strict; |
529 | int attempts = 3; | 615 | int attempts = 3; |
616 | int err; | ||
617 | int reachable = RT6_SELECT_F_REACHABLE; | ||
530 | 618 | ||
531 | strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL); | 619 | strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0; |
532 | 620 | ||
533 | relookup: | 621 | relookup: |
534 | read_lock_bh(&rt6_lock); | 622 | read_lock_bh(&rt6_lock); |
535 | 623 | ||
624 | restart_2: | ||
536 | fn = fib6_lookup(&ip6_routing_table, &fl->fl6_dst, &fl->fl6_src); | 625 | fn = fib6_lookup(&ip6_routing_table, &fl->fl6_dst, &fl->fl6_src); |
537 | 626 | ||
538 | restart: | 627 | restart: |
539 | rt = fn->leaf; | 628 | rt = rt6_select(&fn->leaf, fl->oif, strict | reachable); |
540 | 629 | BACKTRACK(); | |
541 | if ((rt->rt6i_flags & RTF_CACHE)) { | 630 | if (rt == &ip6_null_entry || |
542 | rt = rt6_device_match(rt, fl->oif, strict); | 631 | rt->rt6i_flags & RTF_CACHE) |
543 | BACKTRACK(); | ||
544 | dst_hold(&rt->u.dst); | ||
545 | goto out; | 632 | goto out; |
546 | } | ||
547 | if (rt->rt6i_flags & RTF_DEFAULT) { | ||
548 | if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF) | ||
549 | rt = rt6_best_dflt(rt, fl->oif); | ||
550 | } else { | ||
551 | rt = rt6_device_match(rt, fl->oif, strict); | ||
552 | BACKTRACK(); | ||
553 | } | ||
554 | 633 | ||
555 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { | 634 | dst_hold(&rt->u.dst); |
556 | struct rt6_info *nrt; | 635 | read_unlock_bh(&rt6_lock); |
557 | dst_hold(&rt->u.dst); | ||
558 | read_unlock_bh(&rt6_lock); | ||
559 | 636 | ||
560 | nrt = rt6_cow(rt, &fl->fl6_dst, &fl->fl6_src, NULL); | 637 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
638 | nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); | ||
639 | else { | ||
640 | #if CLONE_OFFLINK_ROUTE | ||
641 | nrt = rt6_alloc_clone(rt, &fl->fl6_dst); | ||
642 | #else | ||
643 | goto out2; | ||
644 | #endif | ||
645 | } | ||
561 | 646 | ||
562 | dst_release(&rt->u.dst); | 647 | dst_release(&rt->u.dst); |
563 | rt = nrt; | 648 | rt = nrt ? : &ip6_null_entry; |
564 | 649 | ||
565 | if (rt->u.dst.error != -EEXIST || --attempts <= 0) | 650 | dst_hold(&rt->u.dst); |
651 | if (nrt) { | ||
652 | err = ip6_ins_rt(nrt, NULL, NULL, NULL); | ||
653 | if (!err) | ||
566 | goto out2; | 654 | goto out2; |
567 | |||
568 | /* Race condition! In the gap, when rt6_lock was | ||
569 | released someone could insert this route. Relookup. | ||
570 | */ | ||
571 | dst_release(&rt->u.dst); | ||
572 | goto relookup; | ||
573 | } | 655 | } |
574 | dst_hold(&rt->u.dst); | 656 | |
657 | if (--attempts <= 0) | ||
658 | goto out2; | ||
659 | |||
660 | /* | ||
661 | * Race condition! In the gap, when rt6_lock was | ||
662 | * released someone could insert this route. Relookup. | ||
663 | */ | ||
664 | dst_release(&rt->u.dst); | ||
665 | goto relookup; | ||
575 | 666 | ||
576 | out: | 667 | out: |
668 | if (reachable) { | ||
669 | reachable = 0; | ||
670 | goto restart_2; | ||
671 | } | ||
672 | dst_hold(&rt->u.dst); | ||
577 | read_unlock_bh(&rt6_lock); | 673 | read_unlock_bh(&rt6_lock); |
578 | out2: | 674 | out2: |
579 | rt->u.dst.lastuse = jiffies; | 675 | rt->u.dst.lastuse = jiffies; |
@@ -999,8 +1095,6 @@ int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct | |||
999 | 1095 | ||
1000 | write_lock_bh(&rt6_lock); | 1096 | write_lock_bh(&rt6_lock); |
1001 | 1097 | ||
1002 | rt6_reset_dflt_pointer(NULL); | ||
1003 | |||
1004 | err = fib6_del(rt, nlh, _rtattr, req); | 1098 | err = fib6_del(rt, nlh, _rtattr, req); |
1005 | dst_release(&rt->u.dst); | 1099 | dst_release(&rt->u.dst); |
1006 | 1100 | ||
@@ -1050,59 +1144,63 @@ static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_r | |||
1050 | void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, | 1144 | void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, |
1051 | struct neighbour *neigh, u8 *lladdr, int on_link) | 1145 | struct neighbour *neigh, u8 *lladdr, int on_link) |
1052 | { | 1146 | { |
1053 | struct rt6_info *rt, *nrt; | 1147 | struct rt6_info *rt, *nrt = NULL; |
1054 | 1148 | int strict; | |
1055 | /* Locate old route to this destination. */ | 1149 | struct fib6_node *fn; |
1056 | rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1); | ||
1057 | |||
1058 | if (rt == NULL) | ||
1059 | return; | ||
1060 | |||
1061 | if (neigh->dev != rt->rt6i_dev) | ||
1062 | goto out; | ||
1063 | 1150 | ||
1064 | /* | 1151 | /* |
1065 | * Current route is on-link; redirect is always invalid. | 1152 | * Get the "current" route for this destination and |
1066 | * | 1153 | * check if the redirect has come from approriate router. |
1067 | * Seems, previous statement is not true. It could | 1154 | * |
1068 | * be node, which looks for us as on-link (f.e. proxy ndisc) | 1155 | * RFC 2461 specifies that redirects should only be |
1069 | * But then router serving it might decide, that we should | 1156 | * accepted if they come from the nexthop to the target. |
1070 | * know truth 8)8) --ANK (980726). | 1157 | * Due to the way the routes are chosen, this notion |
1158 | * is a bit fuzzy and one might need to check all possible | ||
1159 | * routes. | ||
1071 | */ | 1160 | */ |
1072 | if (!(rt->rt6i_flags&RTF_GATEWAY)) | 1161 | strict = ipv6_addr_type(dest) & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL); |
1073 | goto out; | ||
1074 | 1162 | ||
1075 | /* | 1163 | read_lock_bh(&rt6_lock); |
1076 | * RFC 2461 specifies that redirects should only be | 1164 | fn = fib6_lookup(&ip6_routing_table, dest, NULL); |
1077 | * accepted if they come from the nexthop to the target. | 1165 | restart: |
1078 | * Due to the way default routers are chosen, this notion | 1166 | for (rt = fn->leaf; rt; rt = rt->u.next) { |
1079 | * is a bit fuzzy and one might need to check all default | 1167 | /* |
1080 | * routers. | 1168 | * Current route is on-link; redirect is always invalid. |
1081 | */ | 1169 | * |
1082 | if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway)) { | 1170 | * Seems, previous statement is not true. It could |
1083 | if (rt->rt6i_flags & RTF_DEFAULT) { | 1171 | * be node, which looks for us as on-link (f.e. proxy ndisc) |
1084 | struct rt6_info *rt1; | 1172 | * But then router serving it might decide, that we should |
1085 | 1173 | * know truth 8)8) --ANK (980726). | |
1086 | read_lock(&rt6_lock); | 1174 | */ |
1087 | for (rt1 = ip6_routing_table.leaf; rt1; rt1 = rt1->u.next) { | 1175 | if (rt6_check_expired(rt)) |
1088 | if (ipv6_addr_equal(saddr, &rt1->rt6i_gateway)) { | 1176 | continue; |
1089 | dst_hold(&rt1->u.dst); | 1177 | if (!(rt->rt6i_flags & RTF_GATEWAY)) |
1090 | dst_release(&rt->u.dst); | 1178 | continue; |
1091 | read_unlock(&rt6_lock); | 1179 | if (neigh->dev != rt->rt6i_dev) |
1092 | rt = rt1; | 1180 | continue; |
1093 | goto source_ok; | 1181 | if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway)) |
1094 | } | 1182 | continue; |
1095 | } | 1183 | break; |
1096 | read_unlock(&rt6_lock); | 1184 | } |
1185 | if (rt) | ||
1186 | dst_hold(&rt->u.dst); | ||
1187 | else if (strict) { | ||
1188 | while ((fn = fn->parent) != NULL) { | ||
1189 | if (fn->fn_flags & RTN_ROOT) | ||
1190 | break; | ||
1191 | if (fn->fn_flags & RTN_RTINFO) | ||
1192 | goto restart; | ||
1097 | } | 1193 | } |
1194 | } | ||
1195 | read_unlock_bh(&rt6_lock); | ||
1196 | |||
1197 | if (!rt) { | ||
1098 | if (net_ratelimit()) | 1198 | if (net_ratelimit()) |
1099 | printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " | 1199 | printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " |
1100 | "for redirect target\n"); | 1200 | "for redirect target\n"); |
1101 | goto out; | 1201 | return; |
1102 | } | 1202 | } |
1103 | 1203 | ||
1104 | source_ok: | ||
1105 | |||
1106 | /* | 1204 | /* |
1107 | * We have finally decided to accept it. | 1205 | * We have finally decided to accept it. |
1108 | */ | 1206 | */ |
@@ -1210,38 +1308,27 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, | |||
1210 | 1. It is connected route. Action: COW | 1308 | 1. It is connected route. Action: COW |
1211 | 2. It is gatewayed route or NONEXTHOP route. Action: clone it. | 1309 | 2. It is gatewayed route or NONEXTHOP route. Action: clone it. |
1212 | */ | 1310 | */ |
1213 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { | 1311 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
1214 | nrt = rt6_cow(rt, daddr, saddr, NULL); | 1312 | nrt = rt6_alloc_cow(rt, daddr, saddr); |
1215 | if (!nrt->u.dst.error) { | 1313 | else |
1216 | nrt->u.dst.metrics[RTAX_MTU-1] = pmtu; | 1314 | nrt = rt6_alloc_clone(rt, daddr); |
1217 | if (allfrag) | 1315 | |
1218 | nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; | 1316 | if (nrt) { |
1219 | /* According to RFC 1981, detecting PMTU increase shouldn't be | ||
1220 | happened within 5 mins, the recommended timer is 10 mins. | ||
1221 | Here this route expiration time is set to ip6_rt_mtu_expires | ||
1222 | which is 10 mins. After 10 mins the decreased pmtu is expired | ||
1223 | and detecting PMTU increase will be automatically happened. | ||
1224 | */ | ||
1225 | dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); | ||
1226 | nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; | ||
1227 | } | ||
1228 | dst_release(&nrt->u.dst); | ||
1229 | } else { | ||
1230 | nrt = ip6_rt_copy(rt); | ||
1231 | if (nrt == NULL) | ||
1232 | goto out; | ||
1233 | ipv6_addr_copy(&nrt->rt6i_dst.addr, daddr); | ||
1234 | nrt->rt6i_dst.plen = 128; | ||
1235 | nrt->u.dst.flags |= DST_HOST; | ||
1236 | nrt->rt6i_nexthop = neigh_clone(rt->rt6i_nexthop); | ||
1237 | dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); | ||
1238 | nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES; | ||
1239 | nrt->u.dst.metrics[RTAX_MTU-1] = pmtu; | 1317 | nrt->u.dst.metrics[RTAX_MTU-1] = pmtu; |
1240 | if (allfrag) | 1318 | if (allfrag) |
1241 | nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; | 1319 | nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; |
1320 | |||
1321 | /* According to RFC 1981, detecting PMTU increase shouldn't be | ||
1322 | * happened within 5 mins, the recommended timer is 10 mins. | ||
1323 | * Here this route expiration time is set to ip6_rt_mtu_expires | ||
1324 | * which is 10 mins. After 10 mins the decreased pmtu is expired | ||
1325 | * and detecting PMTU increase will be automatically happened. | ||
1326 | */ | ||
1327 | dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); | ||
1328 | nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; | ||
1329 | |||
1242 | ip6_ins_rt(nrt, NULL, NULL, NULL); | 1330 | ip6_ins_rt(nrt, NULL, NULL, NULL); |
1243 | } | 1331 | } |
1244 | |||
1245 | out: | 1332 | out: |
1246 | dst_release(&rt->u.dst); | 1333 | dst_release(&rt->u.dst); |
1247 | } | 1334 | } |
@@ -1280,6 +1367,57 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) | |||
1280 | return rt; | 1367 | return rt; |
1281 | } | 1368 | } |
1282 | 1369 | ||
1370 | #ifdef CONFIG_IPV6_ROUTE_INFO | ||
1371 | static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen, | ||
1372 | struct in6_addr *gwaddr, int ifindex) | ||
1373 | { | ||
1374 | struct fib6_node *fn; | ||
1375 | struct rt6_info *rt = NULL; | ||
1376 | |||
1377 | write_lock_bh(&rt6_lock); | ||
1378 | fn = fib6_locate(&ip6_routing_table, prefix ,prefixlen, NULL, 0); | ||
1379 | if (!fn) | ||
1380 | goto out; | ||
1381 | |||
1382 | for (rt = fn->leaf; rt; rt = rt->u.next) { | ||
1383 | if (rt->rt6i_dev->ifindex != ifindex) | ||
1384 | continue; | ||
1385 | if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY)) | ||
1386 | continue; | ||
1387 | if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr)) | ||
1388 | continue; | ||
1389 | dst_hold(&rt->u.dst); | ||
1390 | break; | ||
1391 | } | ||
1392 | out: | ||
1393 | write_unlock_bh(&rt6_lock); | ||
1394 | return rt; | ||
1395 | } | ||
1396 | |||
1397 | static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen, | ||
1398 | struct in6_addr *gwaddr, int ifindex, | ||
1399 | unsigned pref) | ||
1400 | { | ||
1401 | struct in6_rtmsg rtmsg; | ||
1402 | |||
1403 | memset(&rtmsg, 0, sizeof(rtmsg)); | ||
1404 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | ||
1405 | ipv6_addr_copy(&rtmsg.rtmsg_dst, prefix); | ||
1406 | rtmsg.rtmsg_dst_len = prefixlen; | ||
1407 | ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); | ||
1408 | rtmsg.rtmsg_metric = 1024; | ||
1409 | rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | RTF_UP | RTF_PREF(pref); | ||
1410 | /* We should treat it as a default route if prefix length is 0. */ | ||
1411 | if (!prefixlen) | ||
1412 | rtmsg.rtmsg_flags |= RTF_DEFAULT; | ||
1413 | rtmsg.rtmsg_ifindex = ifindex; | ||
1414 | |||
1415 | ip6_route_add(&rtmsg, NULL, NULL, NULL); | ||
1416 | |||
1417 | return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex); | ||
1418 | } | ||
1419 | #endif | ||
1420 | |||
1283 | struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev) | 1421 | struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev) |
1284 | { | 1422 | { |
1285 | struct rt6_info *rt; | 1423 | struct rt6_info *rt; |
@@ -1290,6 +1428,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d | |||
1290 | write_lock_bh(&rt6_lock); | 1428 | write_lock_bh(&rt6_lock); |
1291 | for (rt = fn->leaf; rt; rt=rt->u.next) { | 1429 | for (rt = fn->leaf; rt; rt=rt->u.next) { |
1292 | if (dev == rt->rt6i_dev && | 1430 | if (dev == rt->rt6i_dev && |
1431 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && | ||
1293 | ipv6_addr_equal(&rt->rt6i_gateway, addr)) | 1432 | ipv6_addr_equal(&rt->rt6i_gateway, addr)) |
1294 | break; | 1433 | break; |
1295 | } | 1434 | } |
@@ -1300,7 +1439,8 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d | |||
1300 | } | 1439 | } |
1301 | 1440 | ||
1302 | struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, | 1441 | struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, |
1303 | struct net_device *dev) | 1442 | struct net_device *dev, |
1443 | unsigned int pref) | ||
1304 | { | 1444 | { |
1305 | struct in6_rtmsg rtmsg; | 1445 | struct in6_rtmsg rtmsg; |
1306 | 1446 | ||
@@ -1308,7 +1448,8 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, | |||
1308 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; | 1448 | rtmsg.rtmsg_type = RTMSG_NEWROUTE; |
1309 | ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); | 1449 | ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); |
1310 | rtmsg.rtmsg_metric = 1024; | 1450 | rtmsg.rtmsg_metric = 1024; |
1311 | rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES; | 1451 | rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES | |
1452 | RTF_PREF(pref); | ||
1312 | 1453 | ||
1313 | rtmsg.rtmsg_ifindex = dev->ifindex; | 1454 | rtmsg.rtmsg_ifindex = dev->ifindex; |
1314 | 1455 | ||
@@ -1326,8 +1467,6 @@ restart: | |||
1326 | if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { | 1467 | if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { |
1327 | dst_hold(&rt->u.dst); | 1468 | dst_hold(&rt->u.dst); |
1328 | 1469 | ||
1329 | rt6_reset_dflt_pointer(NULL); | ||
1330 | |||
1331 | read_unlock_bh(&rt6_lock); | 1470 | read_unlock_bh(&rt6_lock); |
1332 | 1471 | ||
1333 | ip6_del_rt(rt, NULL, NULL, NULL); | 1472 | ip6_del_rt(rt, NULL, NULL, NULL); |
@@ -1738,11 +1877,10 @@ int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | |||
1738 | /* | 1877 | /* |
1739 | * 2. allocate and initialize walker. | 1878 | * 2. allocate and initialize walker. |
1740 | */ | 1879 | */ |
1741 | w = kmalloc(sizeof(*w), GFP_ATOMIC); | 1880 | w = kzalloc(sizeof(*w), GFP_ATOMIC); |
1742 | if (w == NULL) | 1881 | if (w == NULL) |
1743 | return -ENOMEM; | 1882 | return -ENOMEM; |
1744 | RT6_TRACE("dump<%p", w); | 1883 | RT6_TRACE("dump<%p", w); |
1745 | memset(w, 0, sizeof(*w)); | ||
1746 | w->root = &ip6_routing_table; | 1884 | w->root = &ip6_routing_table; |
1747 | w->func = fib6_dump_node; | 1885 | w->func = fib6_dump_node; |
1748 | w->args = &arg; | 1886 | w->args = &arg; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index ca9cf6853755..301eee726b0f 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -987,6 +987,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
987 | inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + | 987 | inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + |
988 | newnp->opt->opt_flen); | 988 | newnp->opt->opt_flen); |
989 | 989 | ||
990 | tcp_mtup_init(newsk); | ||
990 | tcp_sync_mss(newsk, dst_mtu(dst)); | 991 | tcp_sync_mss(newsk, dst_mtu(dst)); |
991 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); | 992 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); |
992 | tcp_initialize_rcv_mss(newsk); | 993 | tcp_initialize_rcv_mss(newsk); |
@@ -1297,18 +1298,21 @@ static int tcp_v6_remember_stamp(struct sock *sk) | |||
1297 | } | 1298 | } |
1298 | 1299 | ||
1299 | static struct inet_connection_sock_af_ops ipv6_specific = { | 1300 | static struct inet_connection_sock_af_ops ipv6_specific = { |
1300 | .queue_xmit = inet6_csk_xmit, | 1301 | .queue_xmit = inet6_csk_xmit, |
1301 | .send_check = tcp_v6_send_check, | 1302 | .send_check = tcp_v6_send_check, |
1302 | .rebuild_header = inet6_sk_rebuild_header, | 1303 | .rebuild_header = inet6_sk_rebuild_header, |
1303 | .conn_request = tcp_v6_conn_request, | 1304 | .conn_request = tcp_v6_conn_request, |
1304 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1305 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
1305 | .remember_stamp = tcp_v6_remember_stamp, | 1306 | .remember_stamp = tcp_v6_remember_stamp, |
1306 | .net_header_len = sizeof(struct ipv6hdr), | 1307 | .net_header_len = sizeof(struct ipv6hdr), |
1307 | 1308 | .setsockopt = ipv6_setsockopt, | |
1308 | .setsockopt = ipv6_setsockopt, | 1309 | .getsockopt = ipv6_getsockopt, |
1309 | .getsockopt = ipv6_getsockopt, | 1310 | .addr2sockaddr = inet6_csk_addr2sockaddr, |
1310 | .addr2sockaddr = inet6_csk_addr2sockaddr, | 1311 | .sockaddr_len = sizeof(struct sockaddr_in6), |
1311 | .sockaddr_len = sizeof(struct sockaddr_in6) | 1312 | #ifdef CONFIG_COMPAT |
1313 | .compat_setsockopt = compat_ipv6_setsockopt, | ||
1314 | .compat_getsockopt = compat_ipv6_getsockopt, | ||
1315 | #endif | ||
1312 | }; | 1316 | }; |
1313 | 1317 | ||
1314 | /* | 1318 | /* |
@@ -1316,22 +1320,23 @@ static struct inet_connection_sock_af_ops ipv6_specific = { | |||
1316 | */ | 1320 | */ |
1317 | 1321 | ||
1318 | static struct inet_connection_sock_af_ops ipv6_mapped = { | 1322 | static struct inet_connection_sock_af_ops ipv6_mapped = { |
1319 | .queue_xmit = ip_queue_xmit, | 1323 | .queue_xmit = ip_queue_xmit, |
1320 | .send_check = tcp_v4_send_check, | 1324 | .send_check = tcp_v4_send_check, |
1321 | .rebuild_header = inet_sk_rebuild_header, | 1325 | .rebuild_header = inet_sk_rebuild_header, |
1322 | .conn_request = tcp_v6_conn_request, | 1326 | .conn_request = tcp_v6_conn_request, |
1323 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1327 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
1324 | .remember_stamp = tcp_v4_remember_stamp, | 1328 | .remember_stamp = tcp_v4_remember_stamp, |
1325 | .net_header_len = sizeof(struct iphdr), | 1329 | .net_header_len = sizeof(struct iphdr), |
1326 | 1330 | .setsockopt = ipv6_setsockopt, | |
1327 | .setsockopt = ipv6_setsockopt, | 1331 | .getsockopt = ipv6_getsockopt, |
1328 | .getsockopt = ipv6_getsockopt, | 1332 | .addr2sockaddr = inet6_csk_addr2sockaddr, |
1329 | .addr2sockaddr = inet6_csk_addr2sockaddr, | 1333 | .sockaddr_len = sizeof(struct sockaddr_in6), |
1330 | .sockaddr_len = sizeof(struct sockaddr_in6) | 1334 | #ifdef CONFIG_COMPAT |
1335 | .compat_setsockopt = compat_ipv6_setsockopt, | ||
1336 | .compat_getsockopt = compat_ipv6_getsockopt, | ||
1337 | #endif | ||
1331 | }; | 1338 | }; |
1332 | 1339 | ||
1333 | |||
1334 | |||
1335 | /* NOTE: A lot of things set to zero explicitly by call to | 1340 | /* NOTE: A lot of things set to zero explicitly by call to |
1336 | * sk_alloc() so need not be done here. | 1341 | * sk_alloc() so need not be done here. |
1337 | */ | 1342 | */ |
@@ -1583,6 +1588,10 @@ struct proto tcpv6_prot = { | |||
1583 | .obj_size = sizeof(struct tcp6_sock), | 1588 | .obj_size = sizeof(struct tcp6_sock), |
1584 | .twsk_prot = &tcp6_timewait_sock_ops, | 1589 | .twsk_prot = &tcp6_timewait_sock_ops, |
1585 | .rsk_prot = &tcp6_request_sock_ops, | 1590 | .rsk_prot = &tcp6_request_sock_ops, |
1591 | #ifdef CONFIG_COMPAT | ||
1592 | .compat_setsockopt = compat_tcp_setsockopt, | ||
1593 | .compat_getsockopt = compat_tcp_getsockopt, | ||
1594 | #endif | ||
1586 | }; | 1595 | }; |
1587 | 1596 | ||
1588 | static struct inet6_protocol tcpv6_protocol = { | 1597 | static struct inet6_protocol tcpv6_protocol = { |
@@ -1604,21 +1613,12 @@ static struct inet_protosw tcpv6_protosw = { | |||
1604 | 1613 | ||
1605 | void __init tcpv6_init(void) | 1614 | void __init tcpv6_init(void) |
1606 | { | 1615 | { |
1607 | int err; | ||
1608 | |||
1609 | /* register inet6 protocol */ | 1616 | /* register inet6 protocol */ |
1610 | if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0) | 1617 | if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0) |
1611 | printk(KERN_ERR "tcpv6_init: Could not register protocol\n"); | 1618 | printk(KERN_ERR "tcpv6_init: Could not register protocol\n"); |
1612 | inet6_register_protosw(&tcpv6_protosw); | 1619 | inet6_register_protosw(&tcpv6_protosw); |
1613 | 1620 | ||
1614 | err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_TCP, &tcp6_socket); | 1621 | if (inet_csk_ctl_sock_create(&tcp6_socket, PF_INET6, SOCK_RAW, |
1615 | if (err < 0) | 1622 | IPPROTO_TCP) < 0) |
1616 | panic("Failed to create the TCPv6 control socket.\n"); | 1623 | panic("Failed to create the TCPv6 control socket.\n"); |
1617 | tcp6_socket->sk->sk_allocation = GFP_ATOMIC; | ||
1618 | |||
1619 | /* Unhash it so that IP input processing does not even | ||
1620 | * see it, we do not wish this socket to see incoming | ||
1621 | * packets. | ||
1622 | */ | ||
1623 | tcp6_socket->sk->sk_prot->unhash(tcp6_socket->sk); | ||
1624 | } | 1624 | } |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index c47648892c04..8d3432a70f3a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -880,16 +880,13 @@ static int udpv6_destroy_sock(struct sock *sk) | |||
880 | /* | 880 | /* |
881 | * Socket option code for UDP | 881 | * Socket option code for UDP |
882 | */ | 882 | */ |
883 | static int udpv6_setsockopt(struct sock *sk, int level, int optname, | 883 | static int do_udpv6_setsockopt(struct sock *sk, int level, int optname, |
884 | char __user *optval, int optlen) | 884 | char __user *optval, int optlen) |
885 | { | 885 | { |
886 | struct udp_sock *up = udp_sk(sk); | 886 | struct udp_sock *up = udp_sk(sk); |
887 | int val; | 887 | int val; |
888 | int err = 0; | 888 | int err = 0; |
889 | 889 | ||
890 | if (level != SOL_UDP) | ||
891 | return ipv6_setsockopt(sk, level, optname, optval, optlen); | ||
892 | |||
893 | if(optlen<sizeof(int)) | 890 | if(optlen<sizeof(int)) |
894 | return -EINVAL; | 891 | return -EINVAL; |
895 | 892 | ||
@@ -927,15 +924,31 @@ static int udpv6_setsockopt(struct sock *sk, int level, int optname, | |||
927 | return err; | 924 | return err; |
928 | } | 925 | } |
929 | 926 | ||
930 | static int udpv6_getsockopt(struct sock *sk, int level, int optname, | 927 | static int udpv6_setsockopt(struct sock *sk, int level, int optname, |
928 | char __user *optval, int optlen) | ||
929 | { | ||
930 | if (level != SOL_UDP) | ||
931 | return ipv6_setsockopt(sk, level, optname, optval, optlen); | ||
932 | return do_udpv6_setsockopt(sk, level, optname, optval, optlen); | ||
933 | } | ||
934 | |||
935 | #ifdef CONFIG_COMPAT | ||
936 | static int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, | ||
937 | char __user *optval, int optlen) | ||
938 | { | ||
939 | if (level != SOL_UDP) | ||
940 | return compat_ipv6_setsockopt(sk, level, optname, | ||
941 | optval, optlen); | ||
942 | return do_udpv6_setsockopt(sk, level, optname, optval, optlen); | ||
943 | } | ||
944 | #endif | ||
945 | |||
946 | static int do_udpv6_getsockopt(struct sock *sk, int level, int optname, | ||
931 | char __user *optval, int __user *optlen) | 947 | char __user *optval, int __user *optlen) |
932 | { | 948 | { |
933 | struct udp_sock *up = udp_sk(sk); | 949 | struct udp_sock *up = udp_sk(sk); |
934 | int val, len; | 950 | int val, len; |
935 | 951 | ||
936 | if (level != SOL_UDP) | ||
937 | return ipv6_getsockopt(sk, level, optname, optval, optlen); | ||
938 | |||
939 | if(get_user(len,optlen)) | 952 | if(get_user(len,optlen)) |
940 | return -EFAULT; | 953 | return -EFAULT; |
941 | 954 | ||
@@ -964,6 +977,25 @@ static int udpv6_getsockopt(struct sock *sk, int level, int optname, | |||
964 | return 0; | 977 | return 0; |
965 | } | 978 | } |
966 | 979 | ||
980 | static int udpv6_getsockopt(struct sock *sk, int level, int optname, | ||
981 | char __user *optval, int __user *optlen) | ||
982 | { | ||
983 | if (level != SOL_UDP) | ||
984 | return ipv6_getsockopt(sk, level, optname, optval, optlen); | ||
985 | return do_udpv6_getsockopt(sk, level, optname, optval, optlen); | ||
986 | } | ||
987 | |||
988 | #ifdef CONFIG_COMPAT | ||
989 | static int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, | ||
990 | char __user *optval, int __user *optlen) | ||
991 | { | ||
992 | if (level != SOL_UDP) | ||
993 | return compat_ipv6_getsockopt(sk, level, optname, | ||
994 | optval, optlen); | ||
995 | return do_udpv6_getsockopt(sk, level, optname, optval, optlen); | ||
996 | } | ||
997 | #endif | ||
998 | |||
967 | static struct inet6_protocol udpv6_protocol = { | 999 | static struct inet6_protocol udpv6_protocol = { |
968 | .handler = udpv6_rcv, | 1000 | .handler = udpv6_rcv, |
969 | .err_handler = udpv6_err, | 1001 | .err_handler = udpv6_err, |
@@ -1037,22 +1069,26 @@ void udp6_proc_exit(void) { | |||
1037 | /* ------------------------------------------------------------------------ */ | 1069 | /* ------------------------------------------------------------------------ */ |
1038 | 1070 | ||
1039 | struct proto udpv6_prot = { | 1071 | struct proto udpv6_prot = { |
1040 | .name = "UDPv6", | 1072 | .name = "UDPv6", |
1041 | .owner = THIS_MODULE, | 1073 | .owner = THIS_MODULE, |
1042 | .close = udpv6_close, | 1074 | .close = udpv6_close, |
1043 | .connect = ip6_datagram_connect, | 1075 | .connect = ip6_datagram_connect, |
1044 | .disconnect = udp_disconnect, | 1076 | .disconnect = udp_disconnect, |
1045 | .ioctl = udp_ioctl, | 1077 | .ioctl = udp_ioctl, |
1046 | .destroy = udpv6_destroy_sock, | 1078 | .destroy = udpv6_destroy_sock, |
1047 | .setsockopt = udpv6_setsockopt, | 1079 | .setsockopt = udpv6_setsockopt, |
1048 | .getsockopt = udpv6_getsockopt, | 1080 | .getsockopt = udpv6_getsockopt, |
1049 | .sendmsg = udpv6_sendmsg, | 1081 | .sendmsg = udpv6_sendmsg, |
1050 | .recvmsg = udpv6_recvmsg, | 1082 | .recvmsg = udpv6_recvmsg, |
1051 | .backlog_rcv = udpv6_queue_rcv_skb, | 1083 | .backlog_rcv = udpv6_queue_rcv_skb, |
1052 | .hash = udp_v6_hash, | 1084 | .hash = udp_v6_hash, |
1053 | .unhash = udp_v6_unhash, | 1085 | .unhash = udp_v6_unhash, |
1054 | .get_port = udp_v6_get_port, | 1086 | .get_port = udp_v6_get_port, |
1055 | .obj_size = sizeof(struct udp6_sock), | 1087 | .obj_size = sizeof(struct udp6_sock), |
1088 | #ifdef CONFIG_COMPAT | ||
1089 | .compat_setsockopt = compat_udpv6_setsockopt, | ||
1090 | .compat_getsockopt = compat_udpv6_getsockopt, | ||
1091 | #endif | ||
1056 | }; | 1092 | }; |
1057 | 1093 | ||
1058 | static struct inet_protosw udpv6_protosw = { | 1094 | static struct inet_protosw udpv6_protosw = { |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 8cfc58b96fc2..08f9abbdf1d7 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <net/protocol.h> | 31 | #include <net/protocol.h> |
32 | #include <linux/ipv6.h> | 32 | #include <linux/ipv6.h> |
33 | #include <linux/icmpv6.h> | 33 | #include <linux/icmpv6.h> |
34 | #include <linux/mutex.h> | ||
34 | 35 | ||
35 | #ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG | 36 | #ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG |
36 | # define X6TDEBUG 3 | 37 | # define X6TDEBUG 3 |
@@ -357,19 +358,19 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct xfrm_decap_state *dec | |||
357 | } | 358 | } |
358 | 359 | ||
359 | static struct xfrm6_tunnel *xfrm6_tunnel_handler; | 360 | static struct xfrm6_tunnel *xfrm6_tunnel_handler; |
360 | static DECLARE_MUTEX(xfrm6_tunnel_sem); | 361 | static DEFINE_MUTEX(xfrm6_tunnel_mutex); |
361 | 362 | ||
362 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler) | 363 | int xfrm6_tunnel_register(struct xfrm6_tunnel *handler) |
363 | { | 364 | { |
364 | int ret; | 365 | int ret; |
365 | 366 | ||
366 | down(&xfrm6_tunnel_sem); | 367 | mutex_lock(&xfrm6_tunnel_mutex); |
367 | ret = 0; | 368 | ret = 0; |
368 | if (xfrm6_tunnel_handler != NULL) | 369 | if (xfrm6_tunnel_handler != NULL) |
369 | ret = -EINVAL; | 370 | ret = -EINVAL; |
370 | if (!ret) | 371 | if (!ret) |
371 | xfrm6_tunnel_handler = handler; | 372 | xfrm6_tunnel_handler = handler; |
372 | up(&xfrm6_tunnel_sem); | 373 | mutex_unlock(&xfrm6_tunnel_mutex); |
373 | 374 | ||
374 | return ret; | 375 | return ret; |
375 | } | 376 | } |
@@ -380,13 +381,13 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler) | |||
380 | { | 381 | { |
381 | int ret; | 382 | int ret; |
382 | 383 | ||
383 | down(&xfrm6_tunnel_sem); | 384 | mutex_lock(&xfrm6_tunnel_mutex); |
384 | ret = 0; | 385 | ret = 0; |
385 | if (xfrm6_tunnel_handler != handler) | 386 | if (xfrm6_tunnel_handler != handler) |
386 | ret = -EINVAL; | 387 | ret = -EINVAL; |
387 | if (!ret) | 388 | if (!ret) |
388 | xfrm6_tunnel_handler = NULL; | 389 | xfrm6_tunnel_handler = NULL; |
389 | up(&xfrm6_tunnel_sem); | 390 | mutex_unlock(&xfrm6_tunnel_mutex); |
390 | 391 | ||
391 | synchronize_net(); | 392 | synchronize_net(); |
392 | 393 | ||
diff --git a/net/key/af_key.c b/net/key/af_key.c index b2d4d1dd2116..859582275cab 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -2651,6 +2651,8 @@ static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c) | |||
2651 | return key_notify_sa(x, c); | 2651 | return key_notify_sa(x, c); |
2652 | case XFRM_MSG_FLUSHSA: | 2652 | case XFRM_MSG_FLUSHSA: |
2653 | return key_notify_sa_flush(c); | 2653 | return key_notify_sa_flush(c); |
2654 | case XFRM_MSG_NEWAE: /* not yet supported */ | ||
2655 | break; | ||
2654 | default: | 2656 | default: |
2655 | printk("pfkey: Unknown SA event %d\n", c->event); | 2657 | printk("pfkey: Unknown SA event %d\n", c->event); |
2656 | break; | 2658 | break; |
@@ -3078,9 +3080,9 @@ static int pfkey_sendmsg(struct kiocb *kiocb, | |||
3078 | if (!hdr) | 3080 | if (!hdr) |
3079 | goto out; | 3081 | goto out; |
3080 | 3082 | ||
3081 | down(&xfrm_cfg_sem); | 3083 | mutex_lock(&xfrm_cfg_mutex); |
3082 | err = pfkey_process(sk, skb, hdr); | 3084 | err = pfkey_process(sk, skb, hdr); |
3083 | up(&xfrm_cfg_sem); | 3085 | mutex_unlock(&xfrm_cfg_mutex); |
3084 | 3086 | ||
3085 | out: | 3087 | out: |
3086 | if (err && hdr && pfkey_error(hdr, err, sk) == 0) | 3088 | if (err && hdr && pfkey_error(hdr, err, sk) == 0) |
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 8171c53bc0ed..5a04db745c8d 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c | |||
@@ -54,7 +54,7 @@ static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout); | |||
54 | * | 54 | * |
55 | * Return the next unused link number for a given sap. | 55 | * Return the next unused link number for a given sap. |
56 | */ | 56 | */ |
57 | static __inline__ u16 llc_ui_next_link_no(int sap) | 57 | static inline u16 llc_ui_next_link_no(int sap) |
58 | { | 58 | { |
59 | return llc_ui_sap_link_no_max[sap]++; | 59 | return llc_ui_sap_link_no_max[sap]++; |
60 | } | 60 | } |
@@ -65,7 +65,7 @@ static __inline__ u16 llc_ui_next_link_no(int sap) | |||
65 | * | 65 | * |
66 | * Given an ARP header type return the corresponding ethernet protocol. | 66 | * Given an ARP header type return the corresponding ethernet protocol. |
67 | */ | 67 | */ |
68 | static __inline__ u16 llc_proto_type(u16 arphrd) | 68 | static inline u16 llc_proto_type(u16 arphrd) |
69 | { | 69 | { |
70 | return arphrd == ARPHRD_IEEE802_TR ? | 70 | return arphrd == ARPHRD_IEEE802_TR ? |
71 | htons(ETH_P_TR_802_2) : htons(ETH_P_802_2); | 71 | htons(ETH_P_TR_802_2) : htons(ETH_P_802_2); |
@@ -75,7 +75,7 @@ static __inline__ u16 llc_proto_type(u16 arphrd) | |||
75 | * llc_ui_addr_null - determines if a address structure is null | 75 | * llc_ui_addr_null - determines if a address structure is null |
76 | * @addr: Address to test if null. | 76 | * @addr: Address to test if null. |
77 | */ | 77 | */ |
78 | static __inline__ u8 llc_ui_addr_null(struct sockaddr_llc *addr) | 78 | static inline u8 llc_ui_addr_null(struct sockaddr_llc *addr) |
79 | { | 79 | { |
80 | return !memcmp(addr, &llc_ui_addrnull, sizeof(*addr)); | 80 | return !memcmp(addr, &llc_ui_addrnull, sizeof(*addr)); |
81 | } | 81 | } |
@@ -89,8 +89,7 @@ static __inline__ u8 llc_ui_addr_null(struct sockaddr_llc *addr) | |||
89 | * operation the user would like to perform and the type of socket. | 89 | * operation the user would like to perform and the type of socket. |
90 | * Returns the correct llc header length. | 90 | * Returns the correct llc header length. |
91 | */ | 91 | */ |
92 | static __inline__ u8 llc_ui_header_len(struct sock *sk, | 92 | static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr) |
93 | struct sockaddr_llc *addr) | ||
94 | { | 93 | { |
95 | u8 rc = LLC_PDU_LEN_U; | 94 | u8 rc = LLC_PDU_LEN_U; |
96 | 95 | ||
@@ -138,7 +137,7 @@ static void llc_ui_sk_init(struct socket *sock, struct sock *sk) | |||
138 | } | 137 | } |
139 | 138 | ||
140 | static struct proto llc_proto = { | 139 | static struct proto llc_proto = { |
141 | .name = "DDP", | 140 | .name = "LLC", |
142 | .owner = THIS_MODULE, | 141 | .owner = THIS_MODULE, |
143 | .obj_size = sizeof(struct llc_sock), | 142 | .obj_size = sizeof(struct llc_sock), |
144 | }; | 143 | }; |
@@ -188,8 +187,10 @@ static int llc_ui_release(struct socket *sock) | |||
188 | llc->laddr.lsap, llc->daddr.lsap); | 187 | llc->laddr.lsap, llc->daddr.lsap); |
189 | if (!llc_send_disc(sk)) | 188 | if (!llc_send_disc(sk)) |
190 | llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); | 189 | llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); |
191 | if (!sock_flag(sk, SOCK_ZAPPED)) | 190 | if (!sock_flag(sk, SOCK_ZAPPED)) { |
191 | llc_sap_put(llc->sap); | ||
192 | llc_sap_remove_socket(llc->sap, sk); | 192 | llc_sap_remove_socket(llc->sap, sk); |
193 | } | ||
193 | release_sock(sk); | 194 | release_sock(sk); |
194 | if (llc->dev) | 195 | if (llc->dev) |
195 | dev_put(llc->dev); | 196 | dev_put(llc->dev); |
diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c index 8169f24ed33e..860140caa6e0 100644 --- a/net/llc/llc_c_ac.c +++ b/net/llc/llc_c_ac.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <net/llc_pdu.h> | 27 | #include <net/llc_pdu.h> |
28 | #include <net/llc.h> | 28 | #include <net/llc.h> |
29 | 29 | ||
30 | #include "llc_output.h" | ||
31 | 30 | ||
32 | static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb); | 31 | static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb); |
33 | static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb); | 32 | static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb); |
diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c index ab0fcd32fd84..bd242a49514a 100644 --- a/net/llc/llc_core.c +++ b/net/llc/llc_core.c | |||
@@ -127,7 +127,6 @@ struct llc_sap *llc_sap_open(unsigned char lsap, | |||
127 | goto out; | 127 | goto out; |
128 | sap->laddr.lsap = lsap; | 128 | sap->laddr.lsap = lsap; |
129 | sap->rcv_func = func; | 129 | sap->rcv_func = func; |
130 | llc_sap_hold(sap); | ||
131 | llc_add_sap(sap); | 130 | llc_add_sap(sap); |
132 | out: | 131 | out: |
133 | write_unlock_bh(&llc_sap_list_lock); | 132 | write_unlock_bh(&llc_sap_list_lock); |
diff --git a/net/llc/llc_output.c b/net/llc/llc_output.c index b4d55b6abb67..b4e668e0e12c 100644 --- a/net/llc/llc_output.c +++ b/net/llc/llc_output.c | |||
@@ -30,7 +30,8 @@ | |||
30 | * Fills MAC header fields, depending on MAC type. Returns 0, If MAC type | 30 | * Fills MAC header fields, depending on MAC type. Returns 0, If MAC type |
31 | * is a valid type and initialization completes correctly 1, otherwise. | 31 | * is a valid type and initialization completes correctly 1, otherwise. |
32 | */ | 32 | */ |
33 | int llc_mac_hdr_init(struct sk_buff *skb, unsigned char *sa, unsigned char *da) | 33 | int llc_mac_hdr_init(struct sk_buff *skb, |
34 | const unsigned char *sa, const unsigned char *da) | ||
34 | { | 35 | { |
35 | int rc = 0; | 36 | int rc = 0; |
36 | 37 | ||
diff --git a/net/llc/llc_output.h b/net/llc/llc_output.h deleted file mode 100644 index 179edf753f00..000000000000 --- a/net/llc/llc_output.h +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | #ifndef LLC_OUTPUT_H | ||
2 | #define LLC_OUTPUT_H | ||
3 | /* | ||
4 | * Copyright (c) 1997 by Procom Technology, Inc. | ||
5 | * 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> | ||
6 | * | ||
7 | * This program can be redistributed or modified under the terms of the | ||
8 | * GNU General Public License version 2 as published by the Free Software | ||
9 | * Foundation. | ||
10 | * This program is distributed without any warranty or implied warranty | ||
11 | * of merchantability or fitness for a particular purpose. | ||
12 | * | ||
13 | * See the GNU General Public License version 2 for more details. | ||
14 | */ | ||
15 | |||
16 | struct sk_buff; | ||
17 | |||
18 | int llc_mac_hdr_init(struct sk_buff *skb, unsigned char *sa, unsigned char *da); | ||
19 | |||
20 | #endif /* LLC_OUTPUT_H */ | ||
diff --git a/net/llc/llc_s_ac.c b/net/llc/llc_s_ac.c index bb3580fb8cfe..ac3d93b210d2 100644 --- a/net/llc/llc_s_ac.c +++ b/net/llc/llc_s_ac.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <net/llc_s_ac.h> | 24 | #include <net/llc_s_ac.h> |
25 | #include <net/llc_s_ev.h> | 25 | #include <net/llc_s_ev.h> |
26 | #include <net/llc_sap.h> | 26 | #include <net/llc_sap.h> |
27 | #include "llc_output.h" | 27 | |
28 | 28 | ||
29 | /** | 29 | /** |
30 | * llc_sap_action_unit_data_ind - forward UI PDU to network layer | 30 | * llc_sap_action_unit_data_ind - forward UI PDU to network layer |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index a8e5544da93e..332acb37b385 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -11,7 +11,7 @@ config NETFILTER_NETLINK_QUEUE | |||
11 | tristate "Netfilter NFQUEUE over NFNETLINK interface" | 11 | tristate "Netfilter NFQUEUE over NFNETLINK interface" |
12 | depends on NETFILTER_NETLINK | 12 | depends on NETFILTER_NETLINK |
13 | help | 13 | help |
14 | If this option isenabled, the kernel will include support | 14 | If this option is enabled, the kernel will include support |
15 | for queueing packets via NFNETLINK. | 15 | for queueing packets via NFNETLINK. |
16 | 16 | ||
17 | config NETFILTER_NETLINK_LOG | 17 | config NETFILTER_NETLINK_LOG |
@@ -66,7 +66,7 @@ config NF_CONNTRACK_EVENTS | |||
66 | help | 66 | help |
67 | If this option is enabled, the connection tracking code will | 67 | If this option is enabled, the connection tracking code will |
68 | provide a notifier chain that can be used by other kernel code | 68 | provide a notifier chain that can be used by other kernel code |
69 | to get notified aboutchanges in the connection tracking state. | 69 | to get notified about changes in the connection tracking state. |
70 | 70 | ||
71 | If unsure, say `N'. | 71 | If unsure, say `N'. |
72 | 72 | ||
@@ -153,7 +153,7 @@ config NETFILTER_XT_TARGET_NFQUEUE | |||
153 | tristate '"NFQUEUE" target Support' | 153 | tristate '"NFQUEUE" target Support' |
154 | depends on NETFILTER_XTABLES | 154 | depends on NETFILTER_XTABLES |
155 | help | 155 | help |
156 | This Target replaced the old obsolete QUEUE target. | 156 | This target replaced the old obsolete QUEUE target. |
157 | 157 | ||
158 | As opposed to QUEUE, it supports 65535 different queues, | 158 | As opposed to QUEUE, it supports 65535 different queues, |
159 | not just one. | 159 | not just one. |
@@ -279,6 +279,16 @@ config NETFILTER_XT_MATCH_MARK | |||
279 | 279 | ||
280 | To compile it as a module, choose M here. If unsure, say N. | 280 | To compile it as a module, choose M here. If unsure, say N. |
281 | 281 | ||
282 | config NETFILTER_XT_MATCH_POLICY | ||
283 | tristate 'IPsec "policy" match support' | ||
284 | depends on NETFILTER_XTABLES && XFRM | ||
285 | help | ||
286 | Policy matching allows you to match packets based on the | ||
287 | IPsec policy that was used during decapsulation/will | ||
288 | be used during encapsulation. | ||
289 | |||
290 | To compile it as a module, choose M here. If unsure, say N. | ||
291 | |||
282 | config NETFILTER_XT_MATCH_PHYSDEV | 292 | config NETFILTER_XT_MATCH_PHYSDEV |
283 | tristate '"physdev" match support' | 293 | tristate '"physdev" match support' |
284 | depends on NETFILTER_XTABLES && BRIDGE_NETFILTER | 294 | depends on NETFILTER_XTABLES && BRIDGE_NETFILTER |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 746172ebc91b..9558727f5e79 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -40,6 +40,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o | |||
40 | obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o | 40 | obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o |
41 | obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o | 41 | obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o |
42 | obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o | 42 | obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o |
43 | obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o | ||
43 | obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o | 44 | obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o |
44 | obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o | 45 | obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o |
45 | obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o | 46 | obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index d622ddf08bb0..0ae281d9bfc3 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -3,7 +3,7 @@ | |||
3 | extension. */ | 3 | extension. */ |
4 | 4 | ||
5 | /* (C) 1999-2001 Paul `Rusty' Russell | 5 | /* (C) 1999-2001 Paul `Rusty' Russell |
6 | * (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.org> | 6 | * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> |
7 | * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org> | 7 | * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
@@ -20,6 +20,11 @@ | |||
20 | * - generalize L3 protocol denendent part. | 20 | * - generalize L3 protocol denendent part. |
21 | * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> | 21 | * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> |
22 | * - add support various size of conntrack structures. | 22 | * - add support various size of conntrack structures. |
23 | * 26 Jan 2006: Harald Welte <laforge@netfilter.org> | ||
24 | * - restructure nf_conn (introduce nf_conn_help) | ||
25 | * - redesign 'features' how they were originally intended | ||
26 | * 26 Feb 2006: Pablo Neira Ayuso <pablo@eurodev.net> | ||
27 | * - add support for L3 protocol module load on demand. | ||
23 | * | 28 | * |
24 | * Derived from net/ipv4/netfilter/ip_conntrack_core.c | 29 | * Derived from net/ipv4/netfilter/ip_conntrack_core.c |
25 | */ | 30 | */ |
@@ -55,7 +60,7 @@ | |||
55 | #include <net/netfilter/nf_conntrack_core.h> | 60 | #include <net/netfilter/nf_conntrack_core.h> |
56 | #include <linux/netfilter_ipv4/listhelp.h> | 61 | #include <linux/netfilter_ipv4/listhelp.h> |
57 | 62 | ||
58 | #define NF_CONNTRACK_VERSION "0.4.1" | 63 | #define NF_CONNTRACK_VERSION "0.5.0" |
59 | 64 | ||
60 | #if 0 | 65 | #if 0 |
61 | #define DEBUGP printk | 66 | #define DEBUGP printk |
@@ -82,8 +87,8 @@ unsigned int nf_ct_log_invalid; | |||
82 | static LIST_HEAD(unconfirmed); | 87 | static LIST_HEAD(unconfirmed); |
83 | static int nf_conntrack_vmalloc; | 88 | static int nf_conntrack_vmalloc; |
84 | 89 | ||
85 | static unsigned int nf_conntrack_next_id = 1; | 90 | static unsigned int nf_conntrack_next_id; |
86 | static unsigned int nf_conntrack_expect_next_id = 1; | 91 | static unsigned int nf_conntrack_expect_next_id; |
87 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | 92 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
88 | struct notifier_block *nf_conntrack_chain; | 93 | struct notifier_block *nf_conntrack_chain; |
89 | struct notifier_block *nf_conntrack_expect_chain; | 94 | struct notifier_block *nf_conntrack_expect_chain; |
@@ -182,7 +187,7 @@ static struct { | |||
182 | DEFINE_RWLOCK(nf_ct_cache_lock); | 187 | DEFINE_RWLOCK(nf_ct_cache_lock); |
183 | 188 | ||
184 | /* This avoids calling kmem_cache_create() with same name simultaneously */ | 189 | /* This avoids calling kmem_cache_create() with same name simultaneously */ |
185 | DECLARE_MUTEX(nf_ct_cache_mutex); | 190 | static DEFINE_MUTEX(nf_ct_cache_mutex); |
186 | 191 | ||
187 | extern struct nf_conntrack_protocol nf_conntrack_generic_protocol; | 192 | extern struct nf_conntrack_protocol nf_conntrack_generic_protocol; |
188 | struct nf_conntrack_protocol * | 193 | struct nf_conntrack_protocol * |
@@ -238,6 +243,35 @@ void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p) | |||
238 | module_put(p->me); | 243 | module_put(p->me); |
239 | } | 244 | } |
240 | 245 | ||
246 | int | ||
247 | nf_ct_l3proto_try_module_get(unsigned short l3proto) | ||
248 | { | ||
249 | int ret; | ||
250 | struct nf_conntrack_l3proto *p; | ||
251 | |||
252 | retry: p = nf_ct_l3proto_find_get(l3proto); | ||
253 | if (p == &nf_conntrack_generic_l3proto) { | ||
254 | ret = request_module("nf_conntrack-%d", l3proto); | ||
255 | if (!ret) | ||
256 | goto retry; | ||
257 | |||
258 | return -EPROTOTYPE; | ||
259 | } | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | void nf_ct_l3proto_module_put(unsigned short l3proto) | ||
265 | { | ||
266 | struct nf_conntrack_l3proto *p; | ||
267 | |||
268 | preempt_disable(); | ||
269 | p = __nf_ct_l3proto_find(l3proto); | ||
270 | preempt_enable(); | ||
271 | |||
272 | module_put(p->me); | ||
273 | } | ||
274 | |||
241 | static int nf_conntrack_hash_rnd_initted; | 275 | static int nf_conntrack_hash_rnd_initted; |
242 | static unsigned int nf_conntrack_hash_rnd; | 276 | static unsigned int nf_conntrack_hash_rnd; |
243 | 277 | ||
@@ -259,21 +293,8 @@ static inline u_int32_t hash_conntrack(const struct nf_conntrack_tuple *tuple) | |||
259 | nf_conntrack_hash_rnd); | 293 | nf_conntrack_hash_rnd); |
260 | } | 294 | } |
261 | 295 | ||
262 | /* Initialize "struct nf_conn" which has spaces for helper */ | ||
263 | static int | ||
264 | init_conntrack_for_helper(struct nf_conn *conntrack, u_int32_t features) | ||
265 | { | ||
266 | |||
267 | conntrack->help = (union nf_conntrack_help *) | ||
268 | (((unsigned long)conntrack->data | ||
269 | + (__alignof__(union nf_conntrack_help) - 1)) | ||
270 | & (~((unsigned long)(__alignof__(union nf_conntrack_help) -1)))); | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | int nf_conntrack_register_cache(u_int32_t features, const char *name, | 296 | int nf_conntrack_register_cache(u_int32_t features, const char *name, |
275 | size_t size, | 297 | size_t size) |
276 | int (*init)(struct nf_conn *, u_int32_t)) | ||
277 | { | 298 | { |
278 | int ret = 0; | 299 | int ret = 0; |
279 | char *cache_name; | 300 | char *cache_name; |
@@ -288,7 +309,7 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name, | |||
288 | return -EINVAL; | 309 | return -EINVAL; |
289 | } | 310 | } |
290 | 311 | ||
291 | down(&nf_ct_cache_mutex); | 312 | mutex_lock(&nf_ct_cache_mutex); |
292 | 313 | ||
293 | write_lock_bh(&nf_ct_cache_lock); | 314 | write_lock_bh(&nf_ct_cache_lock); |
294 | /* e.g: multiple helpers are loaded */ | 315 | /* e.g: multiple helpers are loaded */ |
@@ -296,8 +317,7 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name, | |||
296 | DEBUGP("nf_conntrack_register_cache: already resisterd.\n"); | 317 | DEBUGP("nf_conntrack_register_cache: already resisterd.\n"); |
297 | if ((!strncmp(nf_ct_cache[features].name, name, | 318 | if ((!strncmp(nf_ct_cache[features].name, name, |
298 | NF_CT_FEATURES_NAMELEN)) | 319 | NF_CT_FEATURES_NAMELEN)) |
299 | && nf_ct_cache[features].size == size | 320 | && nf_ct_cache[features].size == size) { |
300 | && nf_ct_cache[features].init_conntrack == init) { | ||
301 | DEBUGP("nf_conntrack_register_cache: reusing.\n"); | 321 | DEBUGP("nf_conntrack_register_cache: reusing.\n"); |
302 | nf_ct_cache[features].use++; | 322 | nf_ct_cache[features].use++; |
303 | ret = 0; | 323 | ret = 0; |
@@ -305,7 +325,7 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name, | |||
305 | ret = -EBUSY; | 325 | ret = -EBUSY; |
306 | 326 | ||
307 | write_unlock_bh(&nf_ct_cache_lock); | 327 | write_unlock_bh(&nf_ct_cache_lock); |
308 | up(&nf_ct_cache_mutex); | 328 | mutex_unlock(&nf_ct_cache_mutex); |
309 | return ret; | 329 | return ret; |
310 | } | 330 | } |
311 | write_unlock_bh(&nf_ct_cache_lock); | 331 | write_unlock_bh(&nf_ct_cache_lock); |
@@ -340,7 +360,6 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name, | |||
340 | write_lock_bh(&nf_ct_cache_lock); | 360 | write_lock_bh(&nf_ct_cache_lock); |
341 | nf_ct_cache[features].use = 1; | 361 | nf_ct_cache[features].use = 1; |
342 | nf_ct_cache[features].size = size; | 362 | nf_ct_cache[features].size = size; |
343 | nf_ct_cache[features].init_conntrack = init; | ||
344 | nf_ct_cache[features].cachep = cachep; | 363 | nf_ct_cache[features].cachep = cachep; |
345 | nf_ct_cache[features].name = cache_name; | 364 | nf_ct_cache[features].name = cache_name; |
346 | write_unlock_bh(&nf_ct_cache_lock); | 365 | write_unlock_bh(&nf_ct_cache_lock); |
@@ -350,7 +369,7 @@ int nf_conntrack_register_cache(u_int32_t features, const char *name, | |||
350 | out_free_name: | 369 | out_free_name: |
351 | kfree(cache_name); | 370 | kfree(cache_name); |
352 | out_up_mutex: | 371 | out_up_mutex: |
353 | up(&nf_ct_cache_mutex); | 372 | mutex_unlock(&nf_ct_cache_mutex); |
354 | return ret; | 373 | return ret; |
355 | } | 374 | } |
356 | 375 | ||
@@ -365,19 +384,18 @@ void nf_conntrack_unregister_cache(u_int32_t features) | |||
365 | * slab cache. | 384 | * slab cache. |
366 | */ | 385 | */ |
367 | DEBUGP("nf_conntrack_unregister_cache: 0x%04x\n", features); | 386 | DEBUGP("nf_conntrack_unregister_cache: 0x%04x\n", features); |
368 | down(&nf_ct_cache_mutex); | 387 | mutex_lock(&nf_ct_cache_mutex); |
369 | 388 | ||
370 | write_lock_bh(&nf_ct_cache_lock); | 389 | write_lock_bh(&nf_ct_cache_lock); |
371 | if (--nf_ct_cache[features].use > 0) { | 390 | if (--nf_ct_cache[features].use > 0) { |
372 | write_unlock_bh(&nf_ct_cache_lock); | 391 | write_unlock_bh(&nf_ct_cache_lock); |
373 | up(&nf_ct_cache_mutex); | 392 | mutex_unlock(&nf_ct_cache_mutex); |
374 | return; | 393 | return; |
375 | } | 394 | } |
376 | cachep = nf_ct_cache[features].cachep; | 395 | cachep = nf_ct_cache[features].cachep; |
377 | name = nf_ct_cache[features].name; | 396 | name = nf_ct_cache[features].name; |
378 | nf_ct_cache[features].cachep = NULL; | 397 | nf_ct_cache[features].cachep = NULL; |
379 | nf_ct_cache[features].name = NULL; | 398 | nf_ct_cache[features].name = NULL; |
380 | nf_ct_cache[features].init_conntrack = NULL; | ||
381 | nf_ct_cache[features].size = 0; | 399 | nf_ct_cache[features].size = 0; |
382 | write_unlock_bh(&nf_ct_cache_lock); | 400 | write_unlock_bh(&nf_ct_cache_lock); |
383 | 401 | ||
@@ -386,7 +404,7 @@ void nf_conntrack_unregister_cache(u_int32_t features) | |||
386 | kmem_cache_destroy(cachep); | 404 | kmem_cache_destroy(cachep); |
387 | kfree(name); | 405 | kfree(name); |
388 | 406 | ||
389 | up(&nf_ct_cache_mutex); | 407 | mutex_unlock(&nf_ct_cache_mutex); |
390 | } | 408 | } |
391 | 409 | ||
392 | int | 410 | int |
@@ -432,11 +450,15 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, | |||
432 | /* nf_conntrack_expect helper functions */ | 450 | /* nf_conntrack_expect helper functions */ |
433 | void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) | 451 | void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) |
434 | { | 452 | { |
453 | struct nf_conn_help *master_help = nfct_help(exp->master); | ||
454 | |||
455 | NF_CT_ASSERT(master_help); | ||
435 | ASSERT_WRITE_LOCK(&nf_conntrack_lock); | 456 | ASSERT_WRITE_LOCK(&nf_conntrack_lock); |
436 | NF_CT_ASSERT(!timer_pending(&exp->timeout)); | 457 | NF_CT_ASSERT(!timer_pending(&exp->timeout)); |
458 | |||
437 | list_del(&exp->list); | 459 | list_del(&exp->list); |
438 | NF_CT_STAT_INC(expect_delete); | 460 | NF_CT_STAT_INC(expect_delete); |
439 | exp->master->expecting--; | 461 | master_help->expecting--; |
440 | nf_conntrack_expect_put(exp); | 462 | nf_conntrack_expect_put(exp); |
441 | } | 463 | } |
442 | 464 | ||
@@ -508,9 +530,10 @@ find_expectation(const struct nf_conntrack_tuple *tuple) | |||
508 | void nf_ct_remove_expectations(struct nf_conn *ct) | 530 | void nf_ct_remove_expectations(struct nf_conn *ct) |
509 | { | 531 | { |
510 | struct nf_conntrack_expect *i, *tmp; | 532 | struct nf_conntrack_expect *i, *tmp; |
533 | struct nf_conn_help *help = nfct_help(ct); | ||
511 | 534 | ||
512 | /* Optimization: most connection never expect any others. */ | 535 | /* Optimization: most connection never expect any others. */ |
513 | if (ct->expecting == 0) | 536 | if (!help || help->expecting == 0) |
514 | return; | 537 | return; |
515 | 538 | ||
516 | list_for_each_entry_safe(i, tmp, &nf_conntrack_expect_list, list) { | 539 | list_for_each_entry_safe(i, tmp, &nf_conntrack_expect_list, list) { |
@@ -713,6 +736,7 @@ __nf_conntrack_confirm(struct sk_buff **pskb) | |||
713 | conntrack_tuple_cmp, | 736 | conntrack_tuple_cmp, |
714 | struct nf_conntrack_tuple_hash *, | 737 | struct nf_conntrack_tuple_hash *, |
715 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) { | 738 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) { |
739 | struct nf_conn_help *help; | ||
716 | /* Remove from unconfirmed list */ | 740 | /* Remove from unconfirmed list */ |
717 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | 741 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); |
718 | 742 | ||
@@ -726,7 +750,8 @@ __nf_conntrack_confirm(struct sk_buff **pskb) | |||
726 | set_bit(IPS_CONFIRMED_BIT, &ct->status); | 750 | set_bit(IPS_CONFIRMED_BIT, &ct->status); |
727 | NF_CT_STAT_INC(insert); | 751 | NF_CT_STAT_INC(insert); |
728 | write_unlock_bh(&nf_conntrack_lock); | 752 | write_unlock_bh(&nf_conntrack_lock); |
729 | if (ct->helper) | 753 | help = nfct_help(ct); |
754 | if (help && help->helper) | ||
730 | nf_conntrack_event_cache(IPCT_HELPER, *pskb); | 755 | nf_conntrack_event_cache(IPCT_HELPER, *pskb); |
731 | #ifdef CONFIG_NF_NAT_NEEDED | 756 | #ifdef CONFIG_NF_NAT_NEEDED |
732 | if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) || | 757 | if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) || |
@@ -842,8 +867,9 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | |||
842 | { | 867 | { |
843 | struct nf_conn *conntrack = NULL; | 868 | struct nf_conn *conntrack = NULL; |
844 | u_int32_t features = 0; | 869 | u_int32_t features = 0; |
870 | struct nf_conntrack_helper *helper; | ||
845 | 871 | ||
846 | if (!nf_conntrack_hash_rnd_initted) { | 872 | if (unlikely(!nf_conntrack_hash_rnd_initted)) { |
847 | get_random_bytes(&nf_conntrack_hash_rnd, 4); | 873 | get_random_bytes(&nf_conntrack_hash_rnd, 4); |
848 | nf_conntrack_hash_rnd_initted = 1; | 874 | nf_conntrack_hash_rnd_initted = 1; |
849 | } | 875 | } |
@@ -863,8 +889,11 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | |||
863 | 889 | ||
864 | /* find features needed by this conntrack. */ | 890 | /* find features needed by this conntrack. */ |
865 | features = l3proto->get_features(orig); | 891 | features = l3proto->get_features(orig); |
892 | |||
893 | /* FIXME: protect helper list per RCU */ | ||
866 | read_lock_bh(&nf_conntrack_lock); | 894 | read_lock_bh(&nf_conntrack_lock); |
867 | if (__nf_ct_helper_find(repl) != NULL) | 895 | helper = __nf_ct_helper_find(repl); |
896 | if (helper) | ||
868 | features |= NF_CT_F_HELP; | 897 | features |= NF_CT_F_HELP; |
869 | read_unlock_bh(&nf_conntrack_lock); | 898 | read_unlock_bh(&nf_conntrack_lock); |
870 | 899 | ||
@@ -872,7 +901,7 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | |||
872 | 901 | ||
873 | read_lock_bh(&nf_ct_cache_lock); | 902 | read_lock_bh(&nf_ct_cache_lock); |
874 | 903 | ||
875 | if (!nf_ct_cache[features].use) { | 904 | if (unlikely(!nf_ct_cache[features].use)) { |
876 | DEBUGP("nf_conntrack_alloc: not supported features = 0x%x\n", | 905 | DEBUGP("nf_conntrack_alloc: not supported features = 0x%x\n", |
877 | features); | 906 | features); |
878 | goto out; | 907 | goto out; |
@@ -886,12 +915,10 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | |||
886 | 915 | ||
887 | memset(conntrack, 0, nf_ct_cache[features].size); | 916 | memset(conntrack, 0, nf_ct_cache[features].size); |
888 | conntrack->features = features; | 917 | conntrack->features = features; |
889 | if (nf_ct_cache[features].init_conntrack && | 918 | if (helper) { |
890 | nf_ct_cache[features].init_conntrack(conntrack, features) < 0) { | 919 | struct nf_conn_help *help = nfct_help(conntrack); |
891 | DEBUGP("nf_conntrack_alloc: failed to init\n"); | 920 | NF_CT_ASSERT(help); |
892 | kmem_cache_free(nf_ct_cache[features].cachep, conntrack); | 921 | help->helper = helper; |
893 | conntrack = NULL; | ||
894 | goto out; | ||
895 | } | 922 | } |
896 | 923 | ||
897 | atomic_set(&conntrack->ct_general.use, 1); | 924 | atomic_set(&conntrack->ct_general.use, 1); |
@@ -972,11 +999,8 @@ init_conntrack(const struct nf_conntrack_tuple *tuple, | |||
972 | #endif | 999 | #endif |
973 | nf_conntrack_get(&conntrack->master->ct_general); | 1000 | nf_conntrack_get(&conntrack->master->ct_general); |
974 | NF_CT_STAT_INC(expect_new); | 1001 | NF_CT_STAT_INC(expect_new); |
975 | } else { | 1002 | } else |
976 | conntrack->helper = __nf_ct_helper_find(&repl_tuple); | ||
977 | |||
978 | NF_CT_STAT_INC(new); | 1003 | NF_CT_STAT_INC(new); |
979 | } | ||
980 | 1004 | ||
981 | /* Overload tuple linked list to put us in unconfirmed list. */ | 1005 | /* Overload tuple linked list to put us in unconfirmed list. */ |
982 | list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed); | 1006 | list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed); |
@@ -1206,14 +1230,16 @@ void nf_conntrack_expect_put(struct nf_conntrack_expect *exp) | |||
1206 | 1230 | ||
1207 | static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp) | 1231 | static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp) |
1208 | { | 1232 | { |
1233 | struct nf_conn_help *master_help = nfct_help(exp->master); | ||
1234 | |||
1209 | atomic_inc(&exp->use); | 1235 | atomic_inc(&exp->use); |
1210 | exp->master->expecting++; | 1236 | master_help->expecting++; |
1211 | list_add(&exp->list, &nf_conntrack_expect_list); | 1237 | list_add(&exp->list, &nf_conntrack_expect_list); |
1212 | 1238 | ||
1213 | init_timer(&exp->timeout); | 1239 | init_timer(&exp->timeout); |
1214 | exp->timeout.data = (unsigned long)exp; | 1240 | exp->timeout.data = (unsigned long)exp; |
1215 | exp->timeout.function = expectation_timed_out; | 1241 | exp->timeout.function = expectation_timed_out; |
1216 | exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ; | 1242 | exp->timeout.expires = jiffies + master_help->helper->timeout * HZ; |
1217 | add_timer(&exp->timeout); | 1243 | add_timer(&exp->timeout); |
1218 | 1244 | ||
1219 | exp->id = ++nf_conntrack_expect_next_id; | 1245 | exp->id = ++nf_conntrack_expect_next_id; |
@@ -1239,10 +1265,12 @@ static void evict_oldest_expect(struct nf_conn *master) | |||
1239 | 1265 | ||
1240 | static inline int refresh_timer(struct nf_conntrack_expect *i) | 1266 | static inline int refresh_timer(struct nf_conntrack_expect *i) |
1241 | { | 1267 | { |
1268 | struct nf_conn_help *master_help = nfct_help(i->master); | ||
1269 | |||
1242 | if (!del_timer(&i->timeout)) | 1270 | if (!del_timer(&i->timeout)) |
1243 | return 0; | 1271 | return 0; |
1244 | 1272 | ||
1245 | i->timeout.expires = jiffies + i->master->helper->timeout*HZ; | 1273 | i->timeout.expires = jiffies + master_help->helper->timeout*HZ; |
1246 | add_timer(&i->timeout); | 1274 | add_timer(&i->timeout); |
1247 | return 1; | 1275 | return 1; |
1248 | } | 1276 | } |
@@ -1251,8 +1279,11 @@ int nf_conntrack_expect_related(struct nf_conntrack_expect *expect) | |||
1251 | { | 1279 | { |
1252 | struct nf_conntrack_expect *i; | 1280 | struct nf_conntrack_expect *i; |
1253 | struct nf_conn *master = expect->master; | 1281 | struct nf_conn *master = expect->master; |
1282 | struct nf_conn_help *master_help = nfct_help(master); | ||
1254 | int ret; | 1283 | int ret; |
1255 | 1284 | ||
1285 | NF_CT_ASSERT(master_help); | ||
1286 | |||
1256 | DEBUGP("nf_conntrack_expect_related %p\n", related_to); | 1287 | DEBUGP("nf_conntrack_expect_related %p\n", related_to); |
1257 | DEBUGP("tuple: "); NF_CT_DUMP_TUPLE(&expect->tuple); | 1288 | DEBUGP("tuple: "); NF_CT_DUMP_TUPLE(&expect->tuple); |
1258 | DEBUGP("mask: "); NF_CT_DUMP_TUPLE(&expect->mask); | 1289 | DEBUGP("mask: "); NF_CT_DUMP_TUPLE(&expect->mask); |
@@ -1271,8 +1302,8 @@ int nf_conntrack_expect_related(struct nf_conntrack_expect *expect) | |||
1271 | } | 1302 | } |
1272 | } | 1303 | } |
1273 | /* Will be over limit? */ | 1304 | /* Will be over limit? */ |
1274 | if (master->helper->max_expected && | 1305 | if (master_help->helper->max_expected && |
1275 | master->expecting >= master->helper->max_expected) | 1306 | master_help->expecting >= master_help->helper->max_expected) |
1276 | evict_oldest_expect(master); | 1307 | evict_oldest_expect(master); |
1277 | 1308 | ||
1278 | nf_conntrack_expect_insert(expect); | 1309 | nf_conntrack_expect_insert(expect); |
@@ -1283,24 +1314,6 @@ out: | |||
1283 | return ret; | 1314 | return ret; |
1284 | } | 1315 | } |
1285 | 1316 | ||
1286 | /* Alter reply tuple (maybe alter helper). This is for NAT, and is | ||
1287 | implicitly racy: see __nf_conntrack_confirm */ | ||
1288 | void nf_conntrack_alter_reply(struct nf_conn *conntrack, | ||
1289 | const struct nf_conntrack_tuple *newreply) | ||
1290 | { | ||
1291 | write_lock_bh(&nf_conntrack_lock); | ||
1292 | /* Should be unconfirmed, so not in hash table yet */ | ||
1293 | NF_CT_ASSERT(!nf_ct_is_confirmed(conntrack)); | ||
1294 | |||
1295 | DEBUGP("Altering reply tuple of %p to ", conntrack); | ||
1296 | NF_CT_DUMP_TUPLE(newreply); | ||
1297 | |||
1298 | conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; | ||
1299 | if (!conntrack->master && conntrack->expecting == 0) | ||
1300 | conntrack->helper = __nf_ct_helper_find(newreply); | ||
1301 | write_unlock_bh(&nf_conntrack_lock); | ||
1302 | } | ||
1303 | |||
1304 | int nf_conntrack_helper_register(struct nf_conntrack_helper *me) | 1317 | int nf_conntrack_helper_register(struct nf_conntrack_helper *me) |
1305 | { | 1318 | { |
1306 | int ret; | 1319 | int ret; |
@@ -1308,9 +1321,8 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me) | |||
1308 | 1321 | ||
1309 | ret = nf_conntrack_register_cache(NF_CT_F_HELP, "nf_conntrack:help", | 1322 | ret = nf_conntrack_register_cache(NF_CT_F_HELP, "nf_conntrack:help", |
1310 | sizeof(struct nf_conn) | 1323 | sizeof(struct nf_conn) |
1311 | + sizeof(union nf_conntrack_help) | 1324 | + sizeof(struct nf_conn_help) |
1312 | + __alignof__(union nf_conntrack_help), | 1325 | + __alignof__(struct nf_conn_help)); |
1313 | init_conntrack_for_helper); | ||
1314 | if (ret < 0) { | 1326 | if (ret < 0) { |
1315 | printk(KERN_ERR "nf_conntrack_helper_reigster: Unable to create slab cache for conntracks\n"); | 1327 | printk(KERN_ERR "nf_conntrack_helper_reigster: Unable to create slab cache for conntracks\n"); |
1316 | return ret; | 1328 | return ret; |
@@ -1338,9 +1350,12 @@ __nf_conntrack_helper_find_byname(const char *name) | |||
1338 | static inline int unhelp(struct nf_conntrack_tuple_hash *i, | 1350 | static inline int unhelp(struct nf_conntrack_tuple_hash *i, |
1339 | const struct nf_conntrack_helper *me) | 1351 | const struct nf_conntrack_helper *me) |
1340 | { | 1352 | { |
1341 | if (nf_ct_tuplehash_to_ctrack(i)->helper == me) { | 1353 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i); |
1342 | nf_conntrack_event(IPCT_HELPER, nf_ct_tuplehash_to_ctrack(i)); | 1354 | struct nf_conn_help *help = nfct_help(ct); |
1343 | nf_ct_tuplehash_to_ctrack(i)->helper = NULL; | 1355 | |
1356 | if (help && help->helper == me) { | ||
1357 | nf_conntrack_event(IPCT_HELPER, ct); | ||
1358 | help->helper = NULL; | ||
1344 | } | 1359 | } |
1345 | return 0; | 1360 | return 0; |
1346 | } | 1361 | } |
@@ -1356,7 +1371,8 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) | |||
1356 | 1371 | ||
1357 | /* Get rid of expectations */ | 1372 | /* Get rid of expectations */ |
1358 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) { | 1373 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) { |
1359 | if (exp->master->helper == me && del_timer(&exp->timeout)) { | 1374 | struct nf_conn_help *help = nfct_help(exp->master); |
1375 | if (help->helper == me && del_timer(&exp->timeout)) { | ||
1360 | nf_ct_unlink_expect(exp); | 1376 | nf_ct_unlink_expect(exp); |
1361 | nf_conntrack_expect_put(exp); | 1377 | nf_conntrack_expect_put(exp); |
1362 | } | 1378 | } |
@@ -1423,6 +1439,8 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, | |||
1423 | 1439 | ||
1424 | #include <linux/netfilter/nfnetlink.h> | 1440 | #include <linux/netfilter/nfnetlink.h> |
1425 | #include <linux/netfilter/nfnetlink_conntrack.h> | 1441 | #include <linux/netfilter/nfnetlink_conntrack.h> |
1442 | #include <linux/mutex.h> | ||
1443 | |||
1426 | 1444 | ||
1427 | /* Generic function for tcp/udp/sctp/dccp and alike. This needs to be | 1445 | /* Generic function for tcp/udp/sctp/dccp and alike. This needs to be |
1428 | * in ip_conntrack_core, since we don't want the protocols to autoload | 1446 | * in ip_conntrack_core, since we don't want the protocols to autoload |
@@ -1697,7 +1715,7 @@ int __init nf_conntrack_init(void) | |||
1697 | } | 1715 | } |
1698 | 1716 | ||
1699 | ret = nf_conntrack_register_cache(NF_CT_F_BASIC, "nf_conntrack:basic", | 1717 | ret = nf_conntrack_register_cache(NF_CT_F_BASIC, "nf_conntrack:basic", |
1700 | sizeof(struct nf_conn), NULL); | 1718 | sizeof(struct nf_conn)); |
1701 | if (ret < 0) { | 1719 | if (ret < 0) { |
1702 | printk(KERN_ERR "Unable to create nf_conn slab cache\n"); | 1720 | printk(KERN_ERR "Unable to create nf_conn slab cache\n"); |
1703 | goto err_free_hash; | 1721 | goto err_free_hash; |
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index 6f210f399762..cd191b0d4ac7 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c | |||
@@ -440,7 +440,7 @@ static int help(struct sk_buff **pskb, | |||
440 | u32 seq; | 440 | u32 seq; |
441 | int dir = CTINFO2DIR(ctinfo); | 441 | int dir = CTINFO2DIR(ctinfo); |
442 | unsigned int matchlen, matchoff; | 442 | unsigned int matchlen, matchoff; |
443 | struct ip_ct_ftp_master *ct_ftp_info = &ct->help->ct_ftp_info; | 443 | struct ip_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info; |
444 | struct nf_conntrack_expect *exp; | 444 | struct nf_conntrack_expect *exp; |
445 | struct nf_conntrack_man cmd = {}; | 445 | struct nf_conntrack_man cmd = {}; |
446 | 446 | ||
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 9ff3463037e1..0e0e9d7b34c8 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -2,9 +2,9 @@ | |||
2 | * protocol helpers and general trouble making from userspace. | 2 | * protocol helpers and general trouble making from userspace. |
3 | * | 3 | * |
4 | * (C) 2001 by Jay Schulist <jschlst@samba.org> | 4 | * (C) 2001 by Jay Schulist <jschlst@samba.org> |
5 | * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org> | 5 | * (C) 2002-2006 by Harald Welte <laforge@gnumonks.org> |
6 | * (C) 2003 by Patrick Mchardy <kaber@trash.net> | 6 | * (C) 2003 by Patrick Mchardy <kaber@trash.net> |
7 | * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net> | 7 | * (C) 2005-2006 by Pablo Neira Ayuso <pablo@eurodev.net> |
8 | * | 8 | * |
9 | * I've reworked this stuff to use attributes instead of conntrack | 9 | * I've reworked this stuff to use attributes instead of conntrack |
10 | * structures. 5.44 am. I need more tea. --pablo 05/07/11. | 10 | * structures. 5.44 am. I need more tea. --pablo 05/07/11. |
@@ -44,7 +44,7 @@ | |||
44 | 44 | ||
45 | MODULE_LICENSE("GPL"); | 45 | MODULE_LICENSE("GPL"); |
46 | 46 | ||
47 | static char __initdata version[] = "0.92"; | 47 | static char __initdata version[] = "0.93"; |
48 | 48 | ||
49 | #if 0 | 49 | #if 0 |
50 | #define DEBUGP printk | 50 | #define DEBUGP printk |
@@ -55,20 +55,18 @@ static char __initdata version[] = "0.92"; | |||
55 | 55 | ||
56 | static inline int | 56 | static inline int |
57 | ctnetlink_dump_tuples_proto(struct sk_buff *skb, | 57 | ctnetlink_dump_tuples_proto(struct sk_buff *skb, |
58 | const struct nf_conntrack_tuple *tuple) | 58 | const struct nf_conntrack_tuple *tuple, |
59 | struct nf_conntrack_protocol *proto) | ||
59 | { | 60 | { |
60 | struct nf_conntrack_protocol *proto; | ||
61 | int ret = 0; | 61 | int ret = 0; |
62 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); | ||
62 | 63 | ||
63 | NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); | 64 | NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); |
64 | 65 | ||
65 | /* If no protocol helper is found, this function will return the | ||
66 | * generic protocol helper, so proto won't *ever* be NULL */ | ||
67 | proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum); | ||
68 | if (likely(proto->tuple_to_nfattr)) | 66 | if (likely(proto->tuple_to_nfattr)) |
69 | ret = proto->tuple_to_nfattr(skb, tuple); | 67 | ret = proto->tuple_to_nfattr(skb, tuple); |
70 | 68 | ||
71 | nf_ct_proto_put(proto); | 69 | NFA_NEST_END(skb, nest_parms); |
72 | 70 | ||
73 | return ret; | 71 | return ret; |
74 | 72 | ||
@@ -77,33 +75,44 @@ nfattr_failure: | |||
77 | } | 75 | } |
78 | 76 | ||
79 | static inline int | 77 | static inline int |
80 | ctnetlink_dump_tuples(struct sk_buff *skb, | 78 | ctnetlink_dump_tuples_ip(struct sk_buff *skb, |
81 | const struct nf_conntrack_tuple *tuple) | 79 | const struct nf_conntrack_tuple *tuple, |
80 | struct nf_conntrack_l3proto *l3proto) | ||
82 | { | 81 | { |
83 | struct nfattr *nest_parms; | ||
84 | struct nf_conntrack_l3proto *l3proto; | ||
85 | int ret = 0; | 82 | int ret = 0; |
86 | 83 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); | |
87 | l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); | 84 | |
88 | |||
89 | nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); | ||
90 | if (likely(l3proto->tuple_to_nfattr)) | 85 | if (likely(l3proto->tuple_to_nfattr)) |
91 | ret = l3proto->tuple_to_nfattr(skb, tuple); | 86 | ret = l3proto->tuple_to_nfattr(skb, tuple); |
87 | |||
92 | NFA_NEST_END(skb, nest_parms); | 88 | NFA_NEST_END(skb, nest_parms); |
93 | 89 | ||
90 | return ret; | ||
91 | |||
92 | nfattr_failure: | ||
93 | return -1; | ||
94 | } | ||
95 | |||
96 | static inline int | ||
97 | ctnetlink_dump_tuples(struct sk_buff *skb, | ||
98 | const struct nf_conntrack_tuple *tuple) | ||
99 | { | ||
100 | int ret; | ||
101 | struct nf_conntrack_l3proto *l3proto; | ||
102 | struct nf_conntrack_protocol *proto; | ||
103 | |||
104 | l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); | ||
105 | ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto); | ||
94 | nf_ct_l3proto_put(l3proto); | 106 | nf_ct_l3proto_put(l3proto); |
95 | 107 | ||
96 | if (unlikely(ret < 0)) | 108 | if (unlikely(ret < 0)) |
97 | return ret; | 109 | return ret; |
98 | 110 | ||
99 | nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); | 111 | proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum); |
100 | ret = ctnetlink_dump_tuples_proto(skb, tuple); | 112 | ret = ctnetlink_dump_tuples_proto(skb, tuple, proto); |
101 | NFA_NEST_END(skb, nest_parms); | 113 | nf_ct_proto_put(proto); |
102 | 114 | ||
103 | return ret; | 115 | return ret; |
104 | |||
105 | nfattr_failure: | ||
106 | return -1; | ||
107 | } | 116 | } |
108 | 117 | ||
109 | static inline int | 118 | static inline int |
@@ -165,15 +174,16 @@ static inline int | |||
165 | ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) | 174 | ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) |
166 | { | 175 | { |
167 | struct nfattr *nest_helper; | 176 | struct nfattr *nest_helper; |
177 | const struct nf_conn_help *help = nfct_help(ct); | ||
168 | 178 | ||
169 | if (!ct->helper) | 179 | if (!help || !help->helper) |
170 | return 0; | 180 | return 0; |
171 | 181 | ||
172 | nest_helper = NFA_NEST(skb, CTA_HELP); | 182 | nest_helper = NFA_NEST(skb, CTA_HELP); |
173 | NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name); | 183 | NFA_PUT(skb, CTA_HELP_NAME, strlen(help->helper->name), help->helper->name); |
174 | 184 | ||
175 | if (ct->helper->to_nfattr) | 185 | if (help->helper->to_nfattr) |
176 | ct->helper->to_nfattr(skb, ct); | 186 | help->helper->to_nfattr(skb, ct); |
177 | 187 | ||
178 | NFA_NEST_END(skb, nest_helper); | 188 | NFA_NEST_END(skb, nest_helper); |
179 | 189 | ||
@@ -337,9 +347,10 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, | |||
337 | group = NFNLGRP_CONNTRACK_UPDATE; | 347 | group = NFNLGRP_CONNTRACK_UPDATE; |
338 | } else | 348 | } else |
339 | return NOTIFY_DONE; | 349 | return NOTIFY_DONE; |
340 | 350 | ||
341 | /* FIXME: Check if there are any listeners before, don't hurt performance */ | 351 | if (!nfnetlink_has_listeners(group)) |
342 | 352 | return NOTIFY_DONE; | |
353 | |||
343 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | 354 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); |
344 | if (!skb) | 355 | if (!skb) |
345 | return NOTIFY_DONE; | 356 | return NOTIFY_DONE; |
@@ -903,11 +914,17 @@ static inline int | |||
903 | ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) | 914 | ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) |
904 | { | 915 | { |
905 | struct nf_conntrack_helper *helper; | 916 | struct nf_conntrack_helper *helper; |
917 | struct nf_conn_help *help = nfct_help(ct); | ||
906 | char *helpname; | 918 | char *helpname; |
907 | int err; | 919 | int err; |
908 | 920 | ||
909 | DEBUGP("entered %s\n", __FUNCTION__); | 921 | DEBUGP("entered %s\n", __FUNCTION__); |
910 | 922 | ||
923 | if (!help) { | ||
924 | /* FIXME: we need to reallocate and rehash */ | ||
925 | return -EBUSY; | ||
926 | } | ||
927 | |||
911 | /* don't change helper of sibling connections */ | 928 | /* don't change helper of sibling connections */ |
912 | if (ct->master) | 929 | if (ct->master) |
913 | return -EINVAL; | 930 | return -EINVAL; |
@@ -924,18 +941,18 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) | |||
924 | return -EINVAL; | 941 | return -EINVAL; |
925 | } | 942 | } |
926 | 943 | ||
927 | if (ct->helper) { | 944 | if (help->helper) { |
928 | if (!helper) { | 945 | if (!helper) { |
929 | /* we had a helper before ... */ | 946 | /* we had a helper before ... */ |
930 | nf_ct_remove_expectations(ct); | 947 | nf_ct_remove_expectations(ct); |
931 | ct->helper = NULL; | 948 | help->helper = NULL; |
932 | } else { | 949 | } else { |
933 | /* need to zero data of old helper */ | 950 | /* need to zero data of old helper */ |
934 | memset(&ct->help, 0, sizeof(ct->help)); | 951 | memset(&help->help, 0, sizeof(help->help)); |
935 | } | 952 | } |
936 | } | 953 | } |
937 | 954 | ||
938 | ct->helper = helper; | 955 | help->helper = helper; |
939 | 956 | ||
940 | return 0; | 957 | return 0; |
941 | } | 958 | } |
@@ -1050,14 +1067,9 @@ ctnetlink_create_conntrack(struct nfattr *cda[], | |||
1050 | ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); | 1067 | ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); |
1051 | #endif | 1068 | #endif |
1052 | 1069 | ||
1053 | ct->helper = nf_ct_helper_find_get(rtuple); | ||
1054 | |||
1055 | add_timer(&ct->timeout); | 1070 | add_timer(&ct->timeout); |
1056 | nf_conntrack_hash_insert(ct); | 1071 | nf_conntrack_hash_insert(ct); |
1057 | 1072 | ||
1058 | if (ct->helper) | ||
1059 | nf_ct_helper_put(ct->helper); | ||
1060 | |||
1061 | DEBUGP("conntrack with id %u inserted\n", ct->id); | 1073 | DEBUGP("conntrack with id %u inserted\n", ct->id); |
1062 | return 0; | 1074 | return 0; |
1063 | 1075 | ||
@@ -1150,6 +1162,37 @@ nfattr_failure: | |||
1150 | } | 1162 | } |
1151 | 1163 | ||
1152 | static inline int | 1164 | static inline int |
1165 | ctnetlink_exp_dump_mask(struct sk_buff *skb, | ||
1166 | const struct nf_conntrack_tuple *tuple, | ||
1167 | const struct nf_conntrack_tuple *mask) | ||
1168 | { | ||
1169 | int ret; | ||
1170 | struct nf_conntrack_l3proto *l3proto; | ||
1171 | struct nf_conntrack_protocol *proto; | ||
1172 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_EXPECT_MASK); | ||
1173 | |||
1174 | l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); | ||
1175 | ret = ctnetlink_dump_tuples_ip(skb, mask, l3proto); | ||
1176 | nf_ct_l3proto_put(l3proto); | ||
1177 | |||
1178 | if (unlikely(ret < 0)) | ||
1179 | goto nfattr_failure; | ||
1180 | |||
1181 | proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum); | ||
1182 | ret = ctnetlink_dump_tuples_proto(skb, mask, proto); | ||
1183 | nf_ct_proto_put(proto); | ||
1184 | if (unlikely(ret < 0)) | ||
1185 | goto nfattr_failure; | ||
1186 | |||
1187 | NFA_NEST_END(skb, nest_parms); | ||
1188 | |||
1189 | return 0; | ||
1190 | |||
1191 | nfattr_failure: | ||
1192 | return -1; | ||
1193 | } | ||
1194 | |||
1195 | static inline int | ||
1153 | ctnetlink_exp_dump_expect(struct sk_buff *skb, | 1196 | ctnetlink_exp_dump_expect(struct sk_buff *skb, |
1154 | const struct nf_conntrack_expect *exp) | 1197 | const struct nf_conntrack_expect *exp) |
1155 | { | 1198 | { |
@@ -1159,7 +1202,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, | |||
1159 | 1202 | ||
1160 | if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) | 1203 | if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) |
1161 | goto nfattr_failure; | 1204 | goto nfattr_failure; |
1162 | if (ctnetlink_exp_dump_tuple(skb, &exp->mask, CTA_EXPECT_MASK) < 0) | 1205 | if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0) |
1163 | goto nfattr_failure; | 1206 | goto nfattr_failure; |
1164 | if (ctnetlink_exp_dump_tuple(skb, | 1207 | if (ctnetlink_exp_dump_tuple(skb, |
1165 | &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | 1208 | &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
@@ -1417,7 +1460,8 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, | |||
1417 | } | 1460 | } |
1418 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, | 1461 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, |
1419 | list) { | 1462 | list) { |
1420 | if (exp->master->helper == h | 1463 | struct nf_conn_help *m_help = nfct_help(exp->master); |
1464 | if (m_help->helper == h | ||
1421 | && del_timer(&exp->timeout)) { | 1465 | && del_timer(&exp->timeout)) { |
1422 | nf_ct_unlink_expect(exp); | 1466 | nf_ct_unlink_expect(exp); |
1423 | nf_conntrack_expect_put(exp); | 1467 | nf_conntrack_expect_put(exp); |
@@ -1452,6 +1496,7 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3) | |||
1452 | struct nf_conntrack_tuple_hash *h = NULL; | 1496 | struct nf_conntrack_tuple_hash *h = NULL; |
1453 | struct nf_conntrack_expect *exp; | 1497 | struct nf_conntrack_expect *exp; |
1454 | struct nf_conn *ct; | 1498 | struct nf_conn *ct; |
1499 | struct nf_conn_help *help; | ||
1455 | int err = 0; | 1500 | int err = 0; |
1456 | 1501 | ||
1457 | DEBUGP("entered %s\n", __FUNCTION__); | 1502 | DEBUGP("entered %s\n", __FUNCTION__); |
@@ -1472,8 +1517,9 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3) | |||
1472 | if (!h) | 1517 | if (!h) |
1473 | return -ENOENT; | 1518 | return -ENOENT; |
1474 | ct = nf_ct_tuplehash_to_ctrack(h); | 1519 | ct = nf_ct_tuplehash_to_ctrack(h); |
1520 | help = nfct_help(ct); | ||
1475 | 1521 | ||
1476 | if (!ct->helper) { | 1522 | if (!help || !help->helper) { |
1477 | /* such conntrack hasn't got any helper, abort */ | 1523 | /* such conntrack hasn't got any helper, abort */ |
1478 | err = -EINVAL; | 1524 | err = -EINVAL; |
1479 | goto out; | 1525 | goto out; |
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 617599aeeead..75577e175b35 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c | |||
@@ -834,12 +834,13 @@ EXPORT_SYMBOL_GPL(__nf_ct_event_cache_init); | |||
834 | EXPORT_PER_CPU_SYMBOL_GPL(nf_conntrack_ecache); | 834 | EXPORT_PER_CPU_SYMBOL_GPL(nf_conntrack_ecache); |
835 | EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); | 835 | EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events); |
836 | #endif | 836 | #endif |
837 | EXPORT_SYMBOL(nf_ct_l3proto_try_module_get); | ||
838 | EXPORT_SYMBOL(nf_ct_l3proto_module_put); | ||
837 | EXPORT_SYMBOL(nf_conntrack_l3proto_register); | 839 | EXPORT_SYMBOL(nf_conntrack_l3proto_register); |
838 | EXPORT_SYMBOL(nf_conntrack_l3proto_unregister); | 840 | EXPORT_SYMBOL(nf_conntrack_l3proto_unregister); |
839 | EXPORT_SYMBOL(nf_conntrack_protocol_register); | 841 | EXPORT_SYMBOL(nf_conntrack_protocol_register); |
840 | EXPORT_SYMBOL(nf_conntrack_protocol_unregister); | 842 | EXPORT_SYMBOL(nf_conntrack_protocol_unregister); |
841 | EXPORT_SYMBOL(nf_ct_invert_tuplepr); | 843 | EXPORT_SYMBOL(nf_ct_invert_tuplepr); |
842 | EXPORT_SYMBOL(nf_conntrack_alter_reply); | ||
843 | EXPORT_SYMBOL(nf_conntrack_destroyed); | 844 | EXPORT_SYMBOL(nf_conntrack_destroyed); |
844 | EXPORT_SYMBOL(need_conntrack); | 845 | EXPORT_SYMBOL(need_conntrack); |
845 | EXPORT_SYMBOL(nf_conntrack_helper_register); | 846 | EXPORT_SYMBOL(nf_conntrack_helper_register); |
diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c index 61a833a9caa6..0a63d7dac7be 100644 --- a/net/netfilter/nf_sockopt.c +++ b/net/netfilter/nf_sockopt.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/module.h> | 4 | #include <linux/module.h> |
5 | #include <linux/skbuff.h> | 5 | #include <linux/skbuff.h> |
6 | #include <linux/netfilter.h> | 6 | #include <linux/netfilter.h> |
7 | #include <linux/mutex.h> | ||
7 | #include <net/sock.h> | 8 | #include <net/sock.h> |
8 | 9 | ||
9 | #include "nf_internals.h" | 10 | #include "nf_internals.h" |
@@ -11,7 +12,7 @@ | |||
11 | /* Sockopts only registered and called from user context, so | 12 | /* Sockopts only registered and called from user context, so |
12 | net locking would be overkill. Also, [gs]etsockopt calls may | 13 | net locking would be overkill. Also, [gs]etsockopt calls may |
13 | sleep. */ | 14 | sleep. */ |
14 | static DECLARE_MUTEX(nf_sockopt_mutex); | 15 | static DEFINE_MUTEX(nf_sockopt_mutex); |
15 | static LIST_HEAD(nf_sockopts); | 16 | static LIST_HEAD(nf_sockopts); |
16 | 17 | ||
17 | /* Do exclusive ranges overlap? */ | 18 | /* Do exclusive ranges overlap? */ |
@@ -26,7 +27,7 @@ int nf_register_sockopt(struct nf_sockopt_ops *reg) | |||
26 | struct list_head *i; | 27 | struct list_head *i; |
27 | int ret = 0; | 28 | int ret = 0; |
28 | 29 | ||
29 | if (down_interruptible(&nf_sockopt_mutex) != 0) | 30 | if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) |
30 | return -EINTR; | 31 | return -EINTR; |
31 | 32 | ||
32 | list_for_each(i, &nf_sockopts) { | 33 | list_for_each(i, &nf_sockopts) { |
@@ -48,7 +49,7 @@ int nf_register_sockopt(struct nf_sockopt_ops *reg) | |||
48 | 49 | ||
49 | list_add(®->list, &nf_sockopts); | 50 | list_add(®->list, &nf_sockopts); |
50 | out: | 51 | out: |
51 | up(&nf_sockopt_mutex); | 52 | mutex_unlock(&nf_sockopt_mutex); |
52 | return ret; | 53 | return ret; |
53 | } | 54 | } |
54 | EXPORT_SYMBOL(nf_register_sockopt); | 55 | EXPORT_SYMBOL(nf_register_sockopt); |
@@ -57,18 +58,18 @@ void nf_unregister_sockopt(struct nf_sockopt_ops *reg) | |||
57 | { | 58 | { |
58 | /* No point being interruptible: we're probably in cleanup_module() */ | 59 | /* No point being interruptible: we're probably in cleanup_module() */ |
59 | restart: | 60 | restart: |
60 | down(&nf_sockopt_mutex); | 61 | mutex_lock(&nf_sockopt_mutex); |
61 | if (reg->use != 0) { | 62 | if (reg->use != 0) { |
62 | /* To be woken by nf_sockopt call... */ | 63 | /* To be woken by nf_sockopt call... */ |
63 | /* FIXME: Stuart Young's name appears gratuitously. */ | 64 | /* FIXME: Stuart Young's name appears gratuitously. */ |
64 | set_current_state(TASK_UNINTERRUPTIBLE); | 65 | set_current_state(TASK_UNINTERRUPTIBLE); |
65 | reg->cleanup_task = current; | 66 | reg->cleanup_task = current; |
66 | up(&nf_sockopt_mutex); | 67 | mutex_unlock(&nf_sockopt_mutex); |
67 | schedule(); | 68 | schedule(); |
68 | goto restart; | 69 | goto restart; |
69 | } | 70 | } |
70 | list_del(®->list); | 71 | list_del(®->list); |
71 | up(&nf_sockopt_mutex); | 72 | mutex_unlock(&nf_sockopt_mutex); |
72 | } | 73 | } |
73 | EXPORT_SYMBOL(nf_unregister_sockopt); | 74 | EXPORT_SYMBOL(nf_unregister_sockopt); |
74 | 75 | ||
@@ -80,7 +81,7 @@ static int nf_sockopt(struct sock *sk, int pf, int val, | |||
80 | struct nf_sockopt_ops *ops; | 81 | struct nf_sockopt_ops *ops; |
81 | int ret; | 82 | int ret; |
82 | 83 | ||
83 | if (down_interruptible(&nf_sockopt_mutex) != 0) | 84 | if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) |
84 | return -EINTR; | 85 | return -EINTR; |
85 | 86 | ||
86 | list_for_each(i, &nf_sockopts) { | 87 | list_for_each(i, &nf_sockopts) { |
@@ -90,7 +91,7 @@ static int nf_sockopt(struct sock *sk, int pf, int val, | |||
90 | if (val >= ops->get_optmin | 91 | if (val >= ops->get_optmin |
91 | && val < ops->get_optmax) { | 92 | && val < ops->get_optmax) { |
92 | ops->use++; | 93 | ops->use++; |
93 | up(&nf_sockopt_mutex); | 94 | mutex_unlock(&nf_sockopt_mutex); |
94 | ret = ops->get(sk, val, opt, len); | 95 | ret = ops->get(sk, val, opt, len); |
95 | goto out; | 96 | goto out; |
96 | } | 97 | } |
@@ -98,22 +99,22 @@ static int nf_sockopt(struct sock *sk, int pf, int val, | |||
98 | if (val >= ops->set_optmin | 99 | if (val >= ops->set_optmin |
99 | && val < ops->set_optmax) { | 100 | && val < ops->set_optmax) { |
100 | ops->use++; | 101 | ops->use++; |
101 | up(&nf_sockopt_mutex); | 102 | mutex_unlock(&nf_sockopt_mutex); |
102 | ret = ops->set(sk, val, opt, *len); | 103 | ret = ops->set(sk, val, opt, *len); |
103 | goto out; | 104 | goto out; |
104 | } | 105 | } |
105 | } | 106 | } |
106 | } | 107 | } |
107 | } | 108 | } |
108 | up(&nf_sockopt_mutex); | 109 | mutex_unlock(&nf_sockopt_mutex); |
109 | return -ENOPROTOOPT; | 110 | return -ENOPROTOOPT; |
110 | 111 | ||
111 | out: | 112 | out: |
112 | down(&nf_sockopt_mutex); | 113 | mutex_lock(&nf_sockopt_mutex); |
113 | ops->use--; | 114 | ops->use--; |
114 | if (ops->cleanup_task) | 115 | if (ops->cleanup_task) |
115 | wake_up_process(ops->cleanup_task); | 116 | wake_up_process(ops->cleanup_task); |
116 | up(&nf_sockopt_mutex); | 117 | mutex_unlock(&nf_sockopt_mutex); |
117 | return ret; | 118 | return ret; |
118 | } | 119 | } |
119 | 120 | ||
@@ -130,3 +131,72 @@ int nf_getsockopt(struct sock *sk, int pf, int val, char __user *opt, int *len) | |||
130 | } | 131 | } |
131 | EXPORT_SYMBOL(nf_getsockopt); | 132 | EXPORT_SYMBOL(nf_getsockopt); |
132 | 133 | ||
134 | #ifdef CONFIG_COMPAT | ||
135 | static int compat_nf_sockopt(struct sock *sk, int pf, int val, | ||
136 | char __user *opt, int *len, int get) | ||
137 | { | ||
138 | struct list_head *i; | ||
139 | struct nf_sockopt_ops *ops; | ||
140 | int ret; | ||
141 | |||
142 | if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) | ||
143 | return -EINTR; | ||
144 | |||
145 | list_for_each(i, &nf_sockopts) { | ||
146 | ops = (struct nf_sockopt_ops *)i; | ||
147 | if (ops->pf == pf) { | ||
148 | if (get) { | ||
149 | if (val >= ops->get_optmin | ||
150 | && val < ops->get_optmax) { | ||
151 | ops->use++; | ||
152 | mutex_unlock(&nf_sockopt_mutex); | ||
153 | if (ops->compat_get) | ||
154 | ret = ops->compat_get(sk, | ||
155 | val, opt, len); | ||
156 | else | ||
157 | ret = ops->get(sk, | ||
158 | val, opt, len); | ||
159 | goto out; | ||
160 | } | ||
161 | } else { | ||
162 | if (val >= ops->set_optmin | ||
163 | && val < ops->set_optmax) { | ||
164 | ops->use++; | ||
165 | mutex_unlock(&nf_sockopt_mutex); | ||
166 | if (ops->compat_set) | ||
167 | ret = ops->compat_set(sk, | ||
168 | val, opt, *len); | ||
169 | else | ||
170 | ret = ops->set(sk, | ||
171 | val, opt, *len); | ||
172 | goto out; | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | mutex_unlock(&nf_sockopt_mutex); | ||
178 | return -ENOPROTOOPT; | ||
179 | |||
180 | out: | ||
181 | mutex_lock(&nf_sockopt_mutex); | ||
182 | ops->use--; | ||
183 | if (ops->cleanup_task) | ||
184 | wake_up_process(ops->cleanup_task); | ||
185 | mutex_unlock(&nf_sockopt_mutex); | ||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | int compat_nf_setsockopt(struct sock *sk, int pf, | ||
190 | int val, char __user *opt, int len) | ||
191 | { | ||
192 | return compat_nf_sockopt(sk, pf, val, opt, &len, 0); | ||
193 | } | ||
194 | EXPORT_SYMBOL(compat_nf_setsockopt); | ||
195 | |||
196 | int compat_nf_getsockopt(struct sock *sk, int pf, | ||
197 | int val, char __user *opt, int *len) | ||
198 | { | ||
199 | return compat_nf_sockopt(sk, pf, val, opt, len, 1); | ||
200 | } | ||
201 | EXPORT_SYMBOL(compat_nf_getsockopt); | ||
202 | #endif | ||
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index f6063e8f0050..b88e82a1a987 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c | |||
@@ -191,6 +191,12 @@ nfnetlink_check_attributes(struct nfnetlink_subsystem *subsys, | |||
191 | return 0; | 191 | return 0; |
192 | } | 192 | } |
193 | 193 | ||
194 | int nfnetlink_has_listeners(unsigned int group) | ||
195 | { | ||
196 | return netlink_has_listeners(nfnl, group); | ||
197 | } | ||
198 | EXPORT_SYMBOL_GPL(nfnetlink_has_listeners); | ||
199 | |||
194 | int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) | 200 | int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) |
195 | { | 201 | { |
196 | gfp_t allocation = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; | 202 | gfp_t allocation = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; |
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 3b3c781b40c0..54cbbaa712dc 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c | |||
@@ -11,6 +11,10 @@ | |||
11 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | * | 13 | * |
14 | * 2006-01-26 Harald Welte <laforge@netfilter.org> | ||
15 | * - Add optional local and global sequence number to detect lost | ||
16 | * events from userspace | ||
17 | * | ||
14 | */ | 18 | */ |
15 | #include <linux/module.h> | 19 | #include <linux/module.h> |
16 | #include <linux/skbuff.h> | 20 | #include <linux/skbuff.h> |
@@ -68,11 +72,14 @@ struct nfulnl_instance { | |||
68 | unsigned int nlbufsiz; /* netlink buffer allocation size */ | 72 | unsigned int nlbufsiz; /* netlink buffer allocation size */ |
69 | unsigned int qthreshold; /* threshold of the queue */ | 73 | unsigned int qthreshold; /* threshold of the queue */ |
70 | u_int32_t copy_range; | 74 | u_int32_t copy_range; |
75 | u_int32_t seq; /* instance-local sequential counter */ | ||
71 | u_int16_t group_num; /* number of this queue */ | 76 | u_int16_t group_num; /* number of this queue */ |
77 | u_int16_t flags; | ||
72 | u_int8_t copy_mode; | 78 | u_int8_t copy_mode; |
73 | }; | 79 | }; |
74 | 80 | ||
75 | static DEFINE_RWLOCK(instances_lock); | 81 | static DEFINE_RWLOCK(instances_lock); |
82 | static atomic_t global_seq; | ||
76 | 83 | ||
77 | #define INSTANCE_BUCKETS 16 | 84 | #define INSTANCE_BUCKETS 16 |
78 | static struct hlist_head instance_table[INSTANCE_BUCKETS]; | 85 | static struct hlist_head instance_table[INSTANCE_BUCKETS]; |
@@ -310,6 +317,16 @@ nfulnl_set_qthresh(struct nfulnl_instance *inst, u_int32_t qthresh) | |||
310 | return 0; | 317 | return 0; |
311 | } | 318 | } |
312 | 319 | ||
320 | static int | ||
321 | nfulnl_set_flags(struct nfulnl_instance *inst, u_int16_t flags) | ||
322 | { | ||
323 | spin_lock_bh(&inst->lock); | ||
324 | inst->flags = ntohs(flags); | ||
325 | spin_unlock_bh(&inst->lock); | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
313 | static struct sk_buff *nfulnl_alloc_skb(unsigned int inst_size, | 330 | static struct sk_buff *nfulnl_alloc_skb(unsigned int inst_size, |
314 | unsigned int pkt_size) | 331 | unsigned int pkt_size) |
315 | { | 332 | { |
@@ -377,6 +394,8 @@ static void nfulnl_timer(unsigned long data) | |||
377 | spin_unlock_bh(&inst->lock); | 394 | spin_unlock_bh(&inst->lock); |
378 | } | 395 | } |
379 | 396 | ||
397 | /* This is an inline function, we don't really care about a long | ||
398 | * list of arguments */ | ||
380 | static inline int | 399 | static inline int |
381 | __build_packet_message(struct nfulnl_instance *inst, | 400 | __build_packet_message(struct nfulnl_instance *inst, |
382 | const struct sk_buff *skb, | 401 | const struct sk_buff *skb, |
@@ -515,6 +534,17 @@ __build_packet_message(struct nfulnl_instance *inst, | |||
515 | read_unlock_bh(&skb->sk->sk_callback_lock); | 534 | read_unlock_bh(&skb->sk->sk_callback_lock); |
516 | } | 535 | } |
517 | 536 | ||
537 | /* local sequence number */ | ||
538 | if (inst->flags & NFULNL_CFG_F_SEQ) { | ||
539 | tmp_uint = htonl(inst->seq++); | ||
540 | NFA_PUT(inst->skb, NFULA_SEQ, sizeof(tmp_uint), &tmp_uint); | ||
541 | } | ||
542 | /* global sequence number */ | ||
543 | if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) { | ||
544 | tmp_uint = atomic_inc_return(&global_seq); | ||
545 | NFA_PUT(inst->skb, NFULA_SEQ_GLOBAL, sizeof(tmp_uint), &tmp_uint); | ||
546 | } | ||
547 | |||
518 | if (data_len) { | 548 | if (data_len) { |
519 | struct nfattr *nfa; | 549 | struct nfattr *nfa; |
520 | int size = NFA_LENGTH(data_len); | 550 | int size = NFA_LENGTH(data_len); |
@@ -607,6 +637,11 @@ nfulnl_log_packet(unsigned int pf, | |||
607 | 637 | ||
608 | spin_lock_bh(&inst->lock); | 638 | spin_lock_bh(&inst->lock); |
609 | 639 | ||
640 | if (inst->flags & NFULNL_CFG_F_SEQ) | ||
641 | size += NFA_SPACE(sizeof(u_int32_t)); | ||
642 | if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) | ||
643 | size += NFA_SPACE(sizeof(u_int32_t)); | ||
644 | |||
610 | qthreshold = inst->qthreshold; | 645 | qthreshold = inst->qthreshold; |
611 | /* per-rule qthreshold overrides per-instance */ | 646 | /* per-rule qthreshold overrides per-instance */ |
612 | if (qthreshold > li->u.ulog.qthreshold) | 647 | if (qthreshold > li->u.ulog.qthreshold) |
@@ -736,10 +771,14 @@ static const int nfula_min[NFULA_MAX] = { | |||
736 | [NFULA_TIMESTAMP-1] = sizeof(struct nfulnl_msg_packet_timestamp), | 771 | [NFULA_TIMESTAMP-1] = sizeof(struct nfulnl_msg_packet_timestamp), |
737 | [NFULA_IFINDEX_INDEV-1] = sizeof(u_int32_t), | 772 | [NFULA_IFINDEX_INDEV-1] = sizeof(u_int32_t), |
738 | [NFULA_IFINDEX_OUTDEV-1]= sizeof(u_int32_t), | 773 | [NFULA_IFINDEX_OUTDEV-1]= sizeof(u_int32_t), |
774 | [NFULA_IFINDEX_PHYSINDEV-1] = sizeof(u_int32_t), | ||
775 | [NFULA_IFINDEX_PHYSOUTDEV-1] = sizeof(u_int32_t), | ||
739 | [NFULA_HWADDR-1] = sizeof(struct nfulnl_msg_packet_hw), | 776 | [NFULA_HWADDR-1] = sizeof(struct nfulnl_msg_packet_hw), |
740 | [NFULA_PAYLOAD-1] = 0, | 777 | [NFULA_PAYLOAD-1] = 0, |
741 | [NFULA_PREFIX-1] = 0, | 778 | [NFULA_PREFIX-1] = 0, |
742 | [NFULA_UID-1] = sizeof(u_int32_t), | 779 | [NFULA_UID-1] = sizeof(u_int32_t), |
780 | [NFULA_SEQ-1] = sizeof(u_int32_t), | ||
781 | [NFULA_SEQ_GLOBAL-1] = sizeof(u_int32_t), | ||
743 | }; | 782 | }; |
744 | 783 | ||
745 | static const int nfula_cfg_min[NFULA_CFG_MAX] = { | 784 | static const int nfula_cfg_min[NFULA_CFG_MAX] = { |
@@ -748,6 +787,7 @@ static const int nfula_cfg_min[NFULA_CFG_MAX] = { | |||
748 | [NFULA_CFG_TIMEOUT-1] = sizeof(u_int32_t), | 787 | [NFULA_CFG_TIMEOUT-1] = sizeof(u_int32_t), |
749 | [NFULA_CFG_QTHRESH-1] = sizeof(u_int32_t), | 788 | [NFULA_CFG_QTHRESH-1] = sizeof(u_int32_t), |
750 | [NFULA_CFG_NLBUFSIZ-1] = sizeof(u_int32_t), | 789 | [NFULA_CFG_NLBUFSIZ-1] = sizeof(u_int32_t), |
790 | [NFULA_CFG_FLAGS-1] = sizeof(u_int16_t), | ||
751 | }; | 791 | }; |
752 | 792 | ||
753 | static int | 793 | static int |
@@ -859,6 +899,12 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, | |||
859 | nfulnl_set_qthresh(inst, ntohl(qthresh)); | 899 | nfulnl_set_qthresh(inst, ntohl(qthresh)); |
860 | } | 900 | } |
861 | 901 | ||
902 | if (nfula[NFULA_CFG_FLAGS-1]) { | ||
903 | u_int16_t flags = | ||
904 | *(u_int16_t *)NFA_DATA(nfula[NFULA_CFG_FLAGS-1]); | ||
905 | nfulnl_set_flags(inst, ntohl(flags)); | ||
906 | } | ||
907 | |||
862 | out_put: | 908 | out_put: |
863 | instance_put(inst); | 909 | instance_put(inst); |
864 | return ret; | 910 | return ret; |
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 2cf5fb8322c4..b5701662182e 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c | |||
@@ -354,16 +354,17 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
354 | QDEBUG("entered\n"); | 354 | QDEBUG("entered\n"); |
355 | 355 | ||
356 | /* all macros expand to constant values at compile time */ | 356 | /* all macros expand to constant values at compile time */ |
357 | size = NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_hdr)) | 357 | size = NLMSG_SPACE(sizeof(struct nfgenmsg)) + |
358 | + NLMSG_SPACE(sizeof(u_int32_t)) /* ifindex */ | 358 | + NFA_SPACE(sizeof(struct nfqnl_msg_packet_hdr)) |
359 | + NLMSG_SPACE(sizeof(u_int32_t)) /* ifindex */ | 359 | + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ |
360 | + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ | ||
360 | #ifdef CONFIG_BRIDGE_NETFILTER | 361 | #ifdef CONFIG_BRIDGE_NETFILTER |
361 | + NLMSG_SPACE(sizeof(u_int32_t)) /* ifindex */ | 362 | + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ |
362 | + NLMSG_SPACE(sizeof(u_int32_t)) /* ifindex */ | 363 | + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */ |
363 | #endif | 364 | #endif |
364 | + NLMSG_SPACE(sizeof(u_int32_t)) /* mark */ | 365 | + NFA_SPACE(sizeof(u_int32_t)) /* mark */ |
365 | + NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_hw)) | 366 | + NFA_SPACE(sizeof(struct nfqnl_msg_packet_hw)) |
366 | + NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_timestamp)); | 367 | + NFA_SPACE(sizeof(struct nfqnl_msg_packet_timestamp)); |
367 | 368 | ||
368 | outdev = entinf->outdev; | 369 | outdev = entinf->outdev; |
369 | 370 | ||
@@ -388,7 +389,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
388 | else | 389 | else |
389 | data_len = queue->copy_range; | 390 | data_len = queue->copy_range; |
390 | 391 | ||
391 | size += NLMSG_SPACE(data_len); | 392 | size += NFA_SPACE(data_len); |
392 | break; | 393 | break; |
393 | 394 | ||
394 | default: | 395 | default: |
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index d7817afc6b96..0a29a24d9a72 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c | |||
@@ -52,11 +52,17 @@ enum { | |||
52 | MATCH, | 52 | MATCH, |
53 | }; | 53 | }; |
54 | 54 | ||
55 | static const char *xt_prefix[NPROTO] = { | ||
56 | [AF_INET] = "ip", | ||
57 | [AF_INET6] = "ip6", | ||
58 | [NF_ARP] = "arp", | ||
59 | }; | ||
60 | |||
55 | /* Registration hooks for targets. */ | 61 | /* Registration hooks for targets. */ |
56 | int | 62 | int |
57 | xt_register_target(int af, struct xt_target *target) | 63 | xt_register_target(struct xt_target *target) |
58 | { | 64 | { |
59 | int ret; | 65 | int ret, af = target->family; |
60 | 66 | ||
61 | ret = down_interruptible(&xt[af].mutex); | 67 | ret = down_interruptible(&xt[af].mutex); |
62 | if (ret != 0) | 68 | if (ret != 0) |
@@ -68,8 +74,10 @@ xt_register_target(int af, struct xt_target *target) | |||
68 | EXPORT_SYMBOL(xt_register_target); | 74 | EXPORT_SYMBOL(xt_register_target); |
69 | 75 | ||
70 | void | 76 | void |
71 | xt_unregister_target(int af, struct xt_target *target) | 77 | xt_unregister_target(struct xt_target *target) |
72 | { | 78 | { |
79 | int af = target->family; | ||
80 | |||
73 | down(&xt[af].mutex); | 81 | down(&xt[af].mutex); |
74 | LIST_DELETE(&xt[af].target, target); | 82 | LIST_DELETE(&xt[af].target, target); |
75 | up(&xt[af].mutex); | 83 | up(&xt[af].mutex); |
@@ -77,9 +85,9 @@ xt_unregister_target(int af, struct xt_target *target) | |||
77 | EXPORT_SYMBOL(xt_unregister_target); | 85 | EXPORT_SYMBOL(xt_unregister_target); |
78 | 86 | ||
79 | int | 87 | int |
80 | xt_register_match(int af, struct xt_match *match) | 88 | xt_register_match(struct xt_match *match) |
81 | { | 89 | { |
82 | int ret; | 90 | int ret, af = match->family; |
83 | 91 | ||
84 | ret = down_interruptible(&xt[af].mutex); | 92 | ret = down_interruptible(&xt[af].mutex); |
85 | if (ret != 0) | 93 | if (ret != 0) |
@@ -93,8 +101,10 @@ xt_register_match(int af, struct xt_match *match) | |||
93 | EXPORT_SYMBOL(xt_register_match); | 101 | EXPORT_SYMBOL(xt_register_match); |
94 | 102 | ||
95 | void | 103 | void |
96 | xt_unregister_match(int af, struct xt_match *match) | 104 | xt_unregister_match(struct xt_match *match) |
97 | { | 105 | { |
106 | int af = match->family; | ||
107 | |||
98 | down(&xt[af].mutex); | 108 | down(&xt[af].mutex); |
99 | LIST_DELETE(&xt[af].match, match); | 109 | LIST_DELETE(&xt[af].match, match); |
100 | up(&xt[af].mutex); | 110 | up(&xt[af].mutex); |
@@ -158,18 +168,12 @@ struct xt_target *xt_find_target(int af, const char *name, u8 revision) | |||
158 | } | 168 | } |
159 | EXPORT_SYMBOL(xt_find_target); | 169 | EXPORT_SYMBOL(xt_find_target); |
160 | 170 | ||
161 | static const char *xt_prefix[NPROTO] = { | ||
162 | [AF_INET] = "ipt_%s", | ||
163 | [AF_INET6] = "ip6t_%s", | ||
164 | [NF_ARP] = "arpt_%s", | ||
165 | }; | ||
166 | |||
167 | struct xt_target *xt_request_find_target(int af, const char *name, u8 revision) | 171 | struct xt_target *xt_request_find_target(int af, const char *name, u8 revision) |
168 | { | 172 | { |
169 | struct xt_target *target; | 173 | struct xt_target *target; |
170 | 174 | ||
171 | target = try_then_request_module(xt_find_target(af, name, revision), | 175 | target = try_then_request_module(xt_find_target(af, name, revision), |
172 | xt_prefix[af], name); | 176 | "%st_%s", xt_prefix[af], name); |
173 | if (IS_ERR(target) || !target) | 177 | if (IS_ERR(target) || !target) |
174 | return NULL; | 178 | return NULL; |
175 | return target; | 179 | return target; |
@@ -237,6 +241,64 @@ int xt_find_revision(int af, const char *name, u8 revision, int target, | |||
237 | } | 241 | } |
238 | EXPORT_SYMBOL_GPL(xt_find_revision); | 242 | EXPORT_SYMBOL_GPL(xt_find_revision); |
239 | 243 | ||
244 | int xt_check_match(const struct xt_match *match, unsigned short family, | ||
245 | unsigned int size, const char *table, unsigned int hook_mask, | ||
246 | unsigned short proto, int inv_proto) | ||
247 | { | ||
248 | if (XT_ALIGN(match->matchsize) != size) { | ||
249 | printk("%s_tables: %s match: invalid size %Zu != %u\n", | ||
250 | xt_prefix[family], match->name, | ||
251 | XT_ALIGN(match->matchsize), size); | ||
252 | return -EINVAL; | ||
253 | } | ||
254 | if (match->table && strcmp(match->table, table)) { | ||
255 | printk("%s_tables: %s match: only valid in %s table, not %s\n", | ||
256 | xt_prefix[family], match->name, match->table, table); | ||
257 | return -EINVAL; | ||
258 | } | ||
259 | if (match->hooks && (hook_mask & ~match->hooks) != 0) { | ||
260 | printk("%s_tables: %s match: bad hook_mask %u\n", | ||
261 | xt_prefix[family], match->name, hook_mask); | ||
262 | return -EINVAL; | ||
263 | } | ||
264 | if (match->proto && (match->proto != proto || inv_proto)) { | ||
265 | printk("%s_tables: %s match: only valid for protocol %u\n", | ||
266 | xt_prefix[family], match->name, match->proto); | ||
267 | return -EINVAL; | ||
268 | } | ||
269 | return 0; | ||
270 | } | ||
271 | EXPORT_SYMBOL_GPL(xt_check_match); | ||
272 | |||
273 | int xt_check_target(const struct xt_target *target, unsigned short family, | ||
274 | unsigned int size, const char *table, unsigned int hook_mask, | ||
275 | unsigned short proto, int inv_proto) | ||
276 | { | ||
277 | if (XT_ALIGN(target->targetsize) != size) { | ||
278 | printk("%s_tables: %s target: invalid size %Zu != %u\n", | ||
279 | xt_prefix[family], target->name, | ||
280 | XT_ALIGN(target->targetsize), size); | ||
281 | return -EINVAL; | ||
282 | } | ||
283 | if (target->table && strcmp(target->table, table)) { | ||
284 | printk("%s_tables: %s target: only valid in %s table, not %s\n", | ||
285 | xt_prefix[family], target->name, target->table, table); | ||
286 | return -EINVAL; | ||
287 | } | ||
288 | if (target->hooks && (hook_mask & ~target->hooks) != 0) { | ||
289 | printk("%s_tables: %s target: bad hook_mask %u\n", | ||
290 | xt_prefix[family], target->name, hook_mask); | ||
291 | return -EINVAL; | ||
292 | } | ||
293 | if (target->proto && (target->proto != proto || inv_proto)) { | ||
294 | printk("%s_tables: %s target: only valid for protocol %u\n", | ||
295 | xt_prefix[family], target->name, target->proto); | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | return 0; | ||
299 | } | ||
300 | EXPORT_SYMBOL_GPL(xt_check_target); | ||
301 | |||
240 | struct xt_table_info *xt_alloc_table_info(unsigned int size) | 302 | struct xt_table_info *xt_alloc_table_info(unsigned int size) |
241 | { | 303 | { |
242 | struct xt_table_info *newinfo; | 304 | struct xt_table_info *newinfo; |
diff --git a/net/netfilter/xt_CLASSIFY.c b/net/netfilter/xt_CLASSIFY.c index 78ee266a12ee..3cd2ac90a25b 100644 --- a/net/netfilter/xt_CLASSIFY.c +++ b/net/netfilter/xt_CLASSIFY.c | |||
@@ -28,6 +28,7 @@ target(struct sk_buff **pskb, | |||
28 | const struct net_device *in, | 28 | const struct net_device *in, |
29 | const struct net_device *out, | 29 | const struct net_device *out, |
30 | unsigned int hooknum, | 30 | unsigned int hooknum, |
31 | const struct xt_target *target, | ||
31 | const void *targinfo, | 32 | const void *targinfo, |
32 | void *userinfo) | 33 | void *userinfo) |
33 | { | 34 | { |
@@ -39,47 +40,24 @@ target(struct sk_buff **pskb, | |||
39 | return XT_CONTINUE; | 40 | return XT_CONTINUE; |
40 | } | 41 | } |
41 | 42 | ||
42 | static int | ||
43 | checkentry(const char *tablename, | ||
44 | const void *e, | ||
45 | void *targinfo, | ||
46 | unsigned int targinfosize, | ||
47 | unsigned int hook_mask) | ||
48 | { | ||
49 | if (targinfosize != XT_ALIGN(sizeof(struct xt_classify_target_info))){ | ||
50 | printk(KERN_ERR "CLASSIFY: invalid size (%u != %Zu).\n", | ||
51 | targinfosize, | ||
52 | XT_ALIGN(sizeof(struct xt_classify_target_info))); | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | if (hook_mask & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) | | ||
57 | (1 << NF_IP_POST_ROUTING))) { | ||
58 | printk(KERN_ERR "CLASSIFY: only valid in LOCAL_OUT, FORWARD " | ||
59 | "and POST_ROUTING.\n"); | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | if (strcmp(tablename, "mangle") != 0) { | ||
64 | printk(KERN_ERR "CLASSIFY: can only be called from " | ||
65 | "\"mangle\" table, not \"%s\".\n", | ||
66 | tablename); | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | return 1; | ||
71 | } | ||
72 | |||
73 | static struct xt_target classify_reg = { | 43 | static struct xt_target classify_reg = { |
74 | .name = "CLASSIFY", | 44 | .name = "CLASSIFY", |
75 | .target = target, | 45 | .target = target, |
76 | .checkentry = checkentry, | 46 | .targetsize = sizeof(struct xt_classify_target_info), |
47 | .table = "mangle", | ||
48 | .hooks = (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) | | ||
49 | (1 << NF_IP_POST_ROUTING), | ||
50 | .family = AF_INET, | ||
77 | .me = THIS_MODULE, | 51 | .me = THIS_MODULE, |
78 | }; | 52 | }; |
79 | static struct xt_target classify6_reg = { | 53 | static struct xt_target classify6_reg = { |
80 | .name = "CLASSIFY", | 54 | .name = "CLASSIFY", |
81 | .target = target, | 55 | .target = target, |
82 | .checkentry = checkentry, | 56 | .targetsize = sizeof(struct xt_classify_target_info), |
57 | .table = "mangle", | ||
58 | .hooks = (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) | | ||
59 | (1 << NF_IP_POST_ROUTING), | ||
60 | .family = AF_INET6, | ||
83 | .me = THIS_MODULE, | 61 | .me = THIS_MODULE, |
84 | }; | 62 | }; |
85 | 63 | ||
@@ -88,21 +66,21 @@ static int __init init(void) | |||
88 | { | 66 | { |
89 | int ret; | 67 | int ret; |
90 | 68 | ||
91 | ret = xt_register_target(AF_INET, &classify_reg); | 69 | ret = xt_register_target(&classify_reg); |
92 | if (ret) | 70 | if (ret) |
93 | return ret; | 71 | return ret; |
94 | 72 | ||
95 | ret = xt_register_target(AF_INET6, &classify6_reg); | 73 | ret = xt_register_target(&classify6_reg); |
96 | if (ret) | 74 | if (ret) |
97 | xt_unregister_target(AF_INET, &classify_reg); | 75 | xt_unregister_target(&classify_reg); |
98 | 76 | ||
99 | return ret; | 77 | return ret; |
100 | } | 78 | } |
101 | 79 | ||
102 | static void __exit fini(void) | 80 | static void __exit fini(void) |
103 | { | 81 | { |
104 | xt_unregister_target(AF_INET, &classify_reg); | 82 | xt_unregister_target(&classify_reg); |
105 | xt_unregister_target(AF_INET6, &classify6_reg); | 83 | xt_unregister_target(&classify6_reg); |
106 | } | 84 | } |
107 | 85 | ||
108 | module_init(init); | 86 | module_init(init); |
diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c index 22506e376be5..35448b8e6883 100644 --- a/net/netfilter/xt_CONNMARK.c +++ b/net/netfilter/xt_CONNMARK.c | |||
@@ -37,6 +37,7 @@ target(struct sk_buff **pskb, | |||
37 | const struct net_device *in, | 37 | const struct net_device *in, |
38 | const struct net_device *out, | 38 | const struct net_device *out, |
39 | unsigned int hooknum, | 39 | unsigned int hooknum, |
40 | const struct xt_target *target, | ||
40 | const void *targinfo, | 41 | const void *targinfo, |
41 | void *userinfo) | 42 | void *userinfo) |
42 | { | 43 | { |
@@ -74,17 +75,12 @@ target(struct sk_buff **pskb, | |||
74 | static int | 75 | static int |
75 | checkentry(const char *tablename, | 76 | checkentry(const char *tablename, |
76 | const void *entry, | 77 | const void *entry, |
78 | const struct xt_target *target, | ||
77 | void *targinfo, | 79 | void *targinfo, |
78 | unsigned int targinfosize, | 80 | unsigned int targinfosize, |
79 | unsigned int hook_mask) | 81 | unsigned int hook_mask) |
80 | { | 82 | { |
81 | struct xt_connmark_target_info *matchinfo = targinfo; | 83 | struct xt_connmark_target_info *matchinfo = targinfo; |
82 | if (targinfosize != XT_ALIGN(sizeof(struct xt_connmark_target_info))) { | ||
83 | printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n", | ||
84 | targinfosize, | ||
85 | XT_ALIGN(sizeof(struct xt_connmark_target_info))); | ||
86 | return 0; | ||
87 | } | ||
88 | 84 | ||
89 | if (matchinfo->mode == XT_CONNMARK_RESTORE) { | 85 | if (matchinfo->mode == XT_CONNMARK_RESTORE) { |
90 | if (strcmp(tablename, "mangle") != 0) { | 86 | if (strcmp(tablename, "mangle") != 0) { |
@@ -102,16 +98,21 @@ checkentry(const char *tablename, | |||
102 | } | 98 | } |
103 | 99 | ||
104 | static struct xt_target connmark_reg = { | 100 | static struct xt_target connmark_reg = { |
105 | .name = "CONNMARK", | 101 | .name = "CONNMARK", |
106 | .target = &target, | 102 | .target = target, |
107 | .checkentry = &checkentry, | 103 | .targetsize = sizeof(struct xt_connmark_target_info), |
108 | .me = THIS_MODULE | 104 | .checkentry = checkentry, |
105 | .family = AF_INET, | ||
106 | .me = THIS_MODULE | ||
109 | }; | 107 | }; |
108 | |||
110 | static struct xt_target connmark6_reg = { | 109 | static struct xt_target connmark6_reg = { |
111 | .name = "CONNMARK", | 110 | .name = "CONNMARK", |
112 | .target = &target, | 111 | .target = target, |
113 | .checkentry = &checkentry, | 112 | .targetsize = sizeof(struct xt_connmark_target_info), |
114 | .me = THIS_MODULE | 113 | .checkentry = checkentry, |
114 | .family = AF_INET6, | ||
115 | .me = THIS_MODULE | ||
115 | }; | 116 | }; |
116 | 117 | ||
117 | static int __init init(void) | 118 | static int __init init(void) |
@@ -120,21 +121,21 @@ static int __init init(void) | |||
120 | 121 | ||
121 | need_conntrack(); | 122 | need_conntrack(); |
122 | 123 | ||
123 | ret = xt_register_target(AF_INET, &connmark_reg); | 124 | ret = xt_register_target(&connmark_reg); |
124 | if (ret) | 125 | if (ret) |
125 | return ret; | 126 | return ret; |
126 | 127 | ||
127 | ret = xt_register_target(AF_INET6, &connmark6_reg); | 128 | ret = xt_register_target(&connmark6_reg); |
128 | if (ret) | 129 | if (ret) |
129 | xt_unregister_target(AF_INET, &connmark_reg); | 130 | xt_unregister_target(&connmark_reg); |
130 | 131 | ||
131 | return ret; | 132 | return ret; |
132 | } | 133 | } |
133 | 134 | ||
134 | static void __exit fini(void) | 135 | static void __exit fini(void) |
135 | { | 136 | { |
136 | xt_unregister_target(AF_INET, &connmark_reg); | 137 | xt_unregister_target(&connmark_reg); |
137 | xt_unregister_target(AF_INET6, &connmark6_reg); | 138 | xt_unregister_target(&connmark6_reg); |
138 | } | 139 | } |
139 | 140 | ||
140 | module_init(init); | 141 | module_init(init); |
diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c index 0c11ee9550f3..73bdd5c80e17 100644 --- a/net/netfilter/xt_MARK.c +++ b/net/netfilter/xt_MARK.c | |||
@@ -26,6 +26,7 @@ target_v0(struct sk_buff **pskb, | |||
26 | const struct net_device *in, | 26 | const struct net_device *in, |
27 | const struct net_device *out, | 27 | const struct net_device *out, |
28 | unsigned int hooknum, | 28 | unsigned int hooknum, |
29 | const struct xt_target *target, | ||
29 | const void *targinfo, | 30 | const void *targinfo, |
30 | void *userinfo) | 31 | void *userinfo) |
31 | { | 32 | { |
@@ -42,6 +43,7 @@ target_v1(struct sk_buff **pskb, | |||
42 | const struct net_device *in, | 43 | const struct net_device *in, |
43 | const struct net_device *out, | 44 | const struct net_device *out, |
44 | unsigned int hooknum, | 45 | unsigned int hooknum, |
46 | const struct xt_target *target, | ||
45 | const void *targinfo, | 47 | const void *targinfo, |
46 | void *userinfo) | 48 | void *userinfo) |
47 | { | 49 | { |
@@ -72,53 +74,30 @@ target_v1(struct sk_buff **pskb, | |||
72 | static int | 74 | static int |
73 | checkentry_v0(const char *tablename, | 75 | checkentry_v0(const char *tablename, |
74 | const void *entry, | 76 | const void *entry, |
77 | const struct xt_target *target, | ||
75 | void *targinfo, | 78 | void *targinfo, |
76 | unsigned int targinfosize, | 79 | unsigned int targinfosize, |
77 | unsigned int hook_mask) | 80 | unsigned int hook_mask) |
78 | { | 81 | { |
79 | struct xt_mark_target_info *markinfo = targinfo; | 82 | struct xt_mark_target_info *markinfo = targinfo; |
80 | 83 | ||
81 | if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info))) { | ||
82 | printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n", | ||
83 | targinfosize, | ||
84 | XT_ALIGN(sizeof(struct xt_mark_target_info))); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | if (strcmp(tablename, "mangle") != 0) { | ||
89 | printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename); | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | if (markinfo->mark > 0xffffffff) { | 84 | if (markinfo->mark > 0xffffffff) { |
94 | printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n"); | 85 | printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n"); |
95 | return 0; | 86 | return 0; |
96 | } | 87 | } |
97 | |||
98 | return 1; | 88 | return 1; |
99 | } | 89 | } |
100 | 90 | ||
101 | static int | 91 | static int |
102 | checkentry_v1(const char *tablename, | 92 | checkentry_v1(const char *tablename, |
103 | const void *entry, | 93 | const void *entry, |
94 | const struct xt_target *target, | ||
104 | void *targinfo, | 95 | void *targinfo, |
105 | unsigned int targinfosize, | 96 | unsigned int targinfosize, |
106 | unsigned int hook_mask) | 97 | unsigned int hook_mask) |
107 | { | 98 | { |
108 | struct xt_mark_target_info_v1 *markinfo = targinfo; | 99 | struct xt_mark_target_info_v1 *markinfo = targinfo; |
109 | 100 | ||
110 | if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info_v1))){ | ||
111 | printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n", | ||
112 | targinfosize, | ||
113 | XT_ALIGN(sizeof(struct xt_mark_target_info_v1))); | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | if (strcmp(tablename, "mangle") != 0) { | ||
118 | printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename); | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | if (markinfo->mode != XT_MARK_SET | 101 | if (markinfo->mode != XT_MARK_SET |
123 | && markinfo->mode != XT_MARK_AND | 102 | && markinfo->mode != XT_MARK_AND |
124 | && markinfo->mode != XT_MARK_OR) { | 103 | && markinfo->mode != XT_MARK_OR) { |
@@ -126,36 +105,43 @@ checkentry_v1(const char *tablename, | |||
126 | markinfo->mode); | 105 | markinfo->mode); |
127 | return 0; | 106 | return 0; |
128 | } | 107 | } |
129 | |||
130 | if (markinfo->mark > 0xffffffff) { | 108 | if (markinfo->mark > 0xffffffff) { |
131 | printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n"); | 109 | printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n"); |
132 | return 0; | 110 | return 0; |
133 | } | 111 | } |
134 | |||
135 | return 1; | 112 | return 1; |
136 | } | 113 | } |
137 | 114 | ||
138 | static struct xt_target ipt_mark_reg_v0 = { | 115 | static struct xt_target ipt_mark_reg_v0 = { |
139 | .name = "MARK", | 116 | .name = "MARK", |
140 | .target = target_v0, | 117 | .target = target_v0, |
118 | .targetsize = sizeof(struct xt_mark_target_info), | ||
119 | .table = "mangle", | ||
141 | .checkentry = checkentry_v0, | 120 | .checkentry = checkentry_v0, |
142 | .me = THIS_MODULE, | 121 | .me = THIS_MODULE, |
122 | .family = AF_INET, | ||
143 | .revision = 0, | 123 | .revision = 0, |
144 | }; | 124 | }; |
145 | 125 | ||
146 | static struct xt_target ipt_mark_reg_v1 = { | 126 | static struct xt_target ipt_mark_reg_v1 = { |
147 | .name = "MARK", | 127 | .name = "MARK", |
148 | .target = target_v1, | 128 | .target = target_v1, |
129 | .targetsize = sizeof(struct xt_mark_target_info_v1), | ||
130 | .table = "mangle", | ||
149 | .checkentry = checkentry_v1, | 131 | .checkentry = checkentry_v1, |
150 | .me = THIS_MODULE, | 132 | .me = THIS_MODULE, |
133 | .family = AF_INET, | ||
151 | .revision = 1, | 134 | .revision = 1, |
152 | }; | 135 | }; |
153 | 136 | ||
154 | static struct xt_target ip6t_mark_reg_v0 = { | 137 | static struct xt_target ip6t_mark_reg_v0 = { |
155 | .name = "MARK", | 138 | .name = "MARK", |
156 | .target = target_v0, | 139 | .target = target_v0, |
140 | .targetsize = sizeof(struct xt_mark_target_info), | ||
141 | .table = "mangle", | ||
157 | .checkentry = checkentry_v0, | 142 | .checkentry = checkentry_v0, |
158 | .me = THIS_MODULE, | 143 | .me = THIS_MODULE, |
144 | .family = AF_INET6, | ||
159 | .revision = 0, | 145 | .revision = 0, |
160 | }; | 146 | }; |
161 | 147 | ||
@@ -163,18 +149,18 @@ static int __init init(void) | |||
163 | { | 149 | { |
164 | int err; | 150 | int err; |
165 | 151 | ||
166 | err = xt_register_target(AF_INET, &ipt_mark_reg_v0); | 152 | err = xt_register_target(&ipt_mark_reg_v0); |
167 | if (err) | 153 | if (err) |
168 | return err; | 154 | return err; |
169 | 155 | ||
170 | err = xt_register_target(AF_INET, &ipt_mark_reg_v1); | 156 | err = xt_register_target(&ipt_mark_reg_v1); |
171 | if (err) | 157 | if (err) |
172 | xt_unregister_target(AF_INET, &ipt_mark_reg_v0); | 158 | xt_unregister_target(&ipt_mark_reg_v0); |
173 | 159 | ||
174 | err = xt_register_target(AF_INET6, &ip6t_mark_reg_v0); | 160 | err = xt_register_target(&ip6t_mark_reg_v0); |
175 | if (err) { | 161 | if (err) { |
176 | xt_unregister_target(AF_INET, &ipt_mark_reg_v0); | 162 | xt_unregister_target(&ipt_mark_reg_v0); |
177 | xt_unregister_target(AF_INET, &ipt_mark_reg_v1); | 163 | xt_unregister_target(&ipt_mark_reg_v1); |
178 | } | 164 | } |
179 | 165 | ||
180 | return err; | 166 | return err; |
@@ -182,9 +168,9 @@ static int __init init(void) | |||
182 | 168 | ||
183 | static void __exit fini(void) | 169 | static void __exit fini(void) |
184 | { | 170 | { |
185 | xt_unregister_target(AF_INET, &ipt_mark_reg_v0); | 171 | xt_unregister_target(&ipt_mark_reg_v0); |
186 | xt_unregister_target(AF_INET, &ipt_mark_reg_v1); | 172 | xt_unregister_target(&ipt_mark_reg_v1); |
187 | xt_unregister_target(AF_INET6, &ip6t_mark_reg_v0); | 173 | xt_unregister_target(&ip6t_mark_reg_v0); |
188 | } | 174 | } |
189 | 175 | ||
190 | module_init(init); | 176 | module_init(init); |
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c index 8b76b6f8d1e4..2873e1c60f68 100644 --- a/net/netfilter/xt_NFQUEUE.c +++ b/net/netfilter/xt_NFQUEUE.c | |||
@@ -28,6 +28,7 @@ target(struct sk_buff **pskb, | |||
28 | const struct net_device *in, | 28 | const struct net_device *in, |
29 | const struct net_device *out, | 29 | const struct net_device *out, |
30 | unsigned int hooknum, | 30 | unsigned int hooknum, |
31 | const struct xt_target *target, | ||
31 | const void *targinfo, | 32 | const void *targinfo, |
32 | void *userinfo) | 33 | void *userinfo) |
33 | { | 34 | { |
@@ -36,71 +37,57 @@ target(struct sk_buff **pskb, | |||
36 | return NF_QUEUE_NR(tinfo->queuenum); | 37 | return NF_QUEUE_NR(tinfo->queuenum); |
37 | } | 38 | } |
38 | 39 | ||
39 | static int | ||
40 | checkentry(const char *tablename, | ||
41 | const void *entry, | ||
42 | void *targinfo, | ||
43 | unsigned int targinfosize, | ||
44 | unsigned int hook_mask) | ||
45 | { | ||
46 | if (targinfosize != XT_ALIGN(sizeof(struct xt_NFQ_info))) { | ||
47 | printk(KERN_WARNING "NFQUEUE: targinfosize %u != %Zu\n", | ||
48 | targinfosize, | ||
49 | XT_ALIGN(sizeof(struct xt_NFQ_info))); | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | return 1; | ||
54 | } | ||
55 | |||
56 | static struct xt_target ipt_NFQ_reg = { | 40 | static struct xt_target ipt_NFQ_reg = { |
57 | .name = "NFQUEUE", | 41 | .name = "NFQUEUE", |
58 | .target = target, | 42 | .target = target, |
59 | .checkentry = checkentry, | 43 | .targetsize = sizeof(struct xt_NFQ_info), |
44 | .family = AF_INET, | ||
60 | .me = THIS_MODULE, | 45 | .me = THIS_MODULE, |
61 | }; | 46 | }; |
62 | 47 | ||
63 | static struct xt_target ip6t_NFQ_reg = { | 48 | static struct xt_target ip6t_NFQ_reg = { |
64 | .name = "NFQUEUE", | 49 | .name = "NFQUEUE", |
65 | .target = target, | 50 | .target = target, |
66 | .checkentry = checkentry, | 51 | .targetsize = sizeof(struct xt_NFQ_info), |
52 | .family = AF_INET6, | ||
67 | .me = THIS_MODULE, | 53 | .me = THIS_MODULE, |
68 | }; | 54 | }; |
69 | 55 | ||
70 | static struct xt_target arpt_NFQ_reg = { | 56 | static struct xt_target arpt_NFQ_reg = { |
71 | .name = "NFQUEUE", | 57 | .name = "NFQUEUE", |
72 | .target = target, | 58 | .target = target, |
73 | .checkentry = checkentry, | 59 | .targetsize = sizeof(struct xt_NFQ_info), |
60 | .family = NF_ARP, | ||
74 | .me = THIS_MODULE, | 61 | .me = THIS_MODULE, |
75 | }; | 62 | }; |
76 | 63 | ||
77 | static int __init init(void) | 64 | static int __init init(void) |
78 | { | 65 | { |
79 | int ret; | 66 | int ret; |
80 | ret = xt_register_target(AF_INET, &ipt_NFQ_reg); | 67 | ret = xt_register_target(&ipt_NFQ_reg); |
81 | if (ret) | 68 | if (ret) |
82 | return ret; | 69 | return ret; |
83 | ret = xt_register_target(AF_INET6, &ip6t_NFQ_reg); | 70 | ret = xt_register_target(&ip6t_NFQ_reg); |
84 | if (ret) | 71 | if (ret) |
85 | goto out_ip; | 72 | goto out_ip; |
86 | ret = xt_register_target(NF_ARP, &arpt_NFQ_reg); | 73 | ret = xt_register_target(&arpt_NFQ_reg); |
87 | if (ret) | 74 | if (ret) |
88 | goto out_ip6; | 75 | goto out_ip6; |
89 | 76 | ||
90 | return ret; | 77 | return ret; |
91 | out_ip6: | 78 | out_ip6: |
92 | xt_unregister_target(AF_INET6, &ip6t_NFQ_reg); | 79 | xt_unregister_target(&ip6t_NFQ_reg); |
93 | out_ip: | 80 | out_ip: |
94 | xt_unregister_target(AF_INET, &ipt_NFQ_reg); | 81 | xt_unregister_target(&ipt_NFQ_reg); |
95 | 82 | ||
96 | return ret; | 83 | return ret; |
97 | } | 84 | } |
98 | 85 | ||
99 | static void __exit fini(void) | 86 | static void __exit fini(void) |
100 | { | 87 | { |
101 | xt_unregister_target(NF_ARP, &arpt_NFQ_reg); | 88 | xt_unregister_target(&arpt_NFQ_reg); |
102 | xt_unregister_target(AF_INET6, &ip6t_NFQ_reg); | 89 | xt_unregister_target(&ip6t_NFQ_reg); |
103 | xt_unregister_target(AF_INET, &ipt_NFQ_reg); | 90 | xt_unregister_target(&ipt_NFQ_reg); |
104 | } | 91 | } |
105 | 92 | ||
106 | module_init(init); | 93 | module_init(init); |
diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c index 24d477afa939..cf2ebd76fd6f 100644 --- a/net/netfilter/xt_NOTRACK.c +++ b/net/netfilter/xt_NOTRACK.c | |||
@@ -15,6 +15,7 @@ target(struct sk_buff **pskb, | |||
15 | const struct net_device *in, | 15 | const struct net_device *in, |
16 | const struct net_device *out, | 16 | const struct net_device *out, |
17 | unsigned int hooknum, | 17 | unsigned int hooknum, |
18 | const struct xt_target *target, | ||
18 | const void *targinfo, | 19 | const void *targinfo, |
19 | void *userinfo) | 20 | void *userinfo) |
20 | { | 21 | { |
@@ -33,59 +34,43 @@ target(struct sk_buff **pskb, | |||
33 | return XT_CONTINUE; | 34 | return XT_CONTINUE; |
34 | } | 35 | } |
35 | 36 | ||
36 | static int | 37 | static struct xt_target notrack_reg = { |
37 | checkentry(const char *tablename, | 38 | .name = "NOTRACK", |
38 | const void *entry, | 39 | .target = target, |
39 | void *targinfo, | 40 | .targetsize = 0, |
40 | unsigned int targinfosize, | 41 | .table = "raw", |
41 | unsigned int hook_mask) | 42 | .family = AF_INET, |
42 | { | 43 | .me = THIS_MODULE, |
43 | if (targinfosize != 0) { | ||
44 | printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n", | ||
45 | targinfosize); | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | if (strcmp(tablename, "raw") != 0) { | ||
50 | printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename); | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | return 1; | ||
55 | } | ||
56 | |||
57 | static struct xt_target notrack_reg = { | ||
58 | .name = "NOTRACK", | ||
59 | .target = target, | ||
60 | .checkentry = checkentry, | ||
61 | .me = THIS_MODULE, | ||
62 | }; | 44 | }; |
63 | static struct xt_target notrack6_reg = { | 45 | |
64 | .name = "NOTRACK", | 46 | static struct xt_target notrack6_reg = { |
65 | .target = target, | 47 | .name = "NOTRACK", |
66 | .checkentry = checkentry, | 48 | .target = target, |
67 | .me = THIS_MODULE, | 49 | .targetsize = 0, |
50 | .table = "raw", | ||
51 | .family = AF_INET6, | ||
52 | .me = THIS_MODULE, | ||
68 | }; | 53 | }; |
69 | 54 | ||
70 | static int __init init(void) | 55 | static int __init init(void) |
71 | { | 56 | { |
72 | int ret; | 57 | int ret; |
73 | 58 | ||
74 | ret = xt_register_target(AF_INET, ¬rack_reg); | 59 | ret = xt_register_target(¬rack_reg); |
75 | if (ret) | 60 | if (ret) |
76 | return ret; | 61 | return ret; |
77 | 62 | ||
78 | ret = xt_register_target(AF_INET6, ¬rack6_reg); | 63 | ret = xt_register_target(¬rack6_reg); |
79 | if (ret) | 64 | if (ret) |
80 | xt_unregister_target(AF_INET, ¬rack_reg); | 65 | xt_unregister_target(¬rack_reg); |
81 | 66 | ||
82 | return ret; | 67 | return ret; |
83 | } | 68 | } |
84 | 69 | ||
85 | static void __exit fini(void) | 70 | static void __exit fini(void) |
86 | { | 71 | { |
87 | xt_unregister_target(AF_INET6, ¬rack6_reg); | 72 | xt_unregister_target(¬rack6_reg); |
88 | xt_unregister_target(AF_INET, ¬rack_reg); | 73 | xt_unregister_target(¬rack_reg); |
89 | } | 74 | } |
90 | 75 | ||
91 | module_init(init); | 76 | module_init(init); |
diff --git a/net/netfilter/xt_comment.c b/net/netfilter/xt_comment.c index 4ba6fd65c6e9..2637724b498d 100644 --- a/net/netfilter/xt_comment.c +++ b/net/netfilter/xt_comment.c | |||
@@ -19,6 +19,7 @@ static int | |||
19 | match(const struct sk_buff *skb, | 19 | match(const struct sk_buff *skb, |
20 | const struct net_device *in, | 20 | const struct net_device *in, |
21 | const struct net_device *out, | 21 | const struct net_device *out, |
22 | const struct xt_match *match, | ||
22 | const void *matchinfo, | 23 | const void *matchinfo, |
23 | int offset, | 24 | int offset, |
24 | unsigned int protooff, | 25 | unsigned int protooff, |
@@ -28,30 +29,19 @@ match(const struct sk_buff *skb, | |||
28 | return 1; | 29 | return 1; |
29 | } | 30 | } |
30 | 31 | ||
31 | static int | ||
32 | checkentry(const char *tablename, | ||
33 | const void *ip, | ||
34 | void *matchinfo, | ||
35 | unsigned int matchsize, | ||
36 | unsigned int hook_mask) | ||
37 | { | ||
38 | /* Check the size */ | ||
39 | if (matchsize != XT_ALIGN(sizeof(struct xt_comment_info))) | ||
40 | return 0; | ||
41 | return 1; | ||
42 | } | ||
43 | |||
44 | static struct xt_match comment_match = { | 32 | static struct xt_match comment_match = { |
45 | .name = "comment", | 33 | .name = "comment", |
46 | .match = match, | 34 | .match = match, |
47 | .checkentry = checkentry, | 35 | .matchsize = sizeof(struct xt_comment_info), |
36 | .family = AF_INET, | ||
48 | .me = THIS_MODULE | 37 | .me = THIS_MODULE |
49 | }; | 38 | }; |
50 | 39 | ||
51 | static struct xt_match comment6_match = { | 40 | static struct xt_match comment6_match = { |
52 | .name = "comment", | 41 | .name = "comment", |
53 | .match = match, | 42 | .match = match, |
54 | .checkentry = checkentry, | 43 | .matchsize = sizeof(struct xt_comment_info), |
44 | .family = AF_INET6, | ||
55 | .me = THIS_MODULE | 45 | .me = THIS_MODULE |
56 | }; | 46 | }; |
57 | 47 | ||
@@ -59,21 +49,21 @@ static int __init init(void) | |||
59 | { | 49 | { |
60 | int ret; | 50 | int ret; |
61 | 51 | ||
62 | ret = xt_register_match(AF_INET, &comment_match); | 52 | ret = xt_register_match(&comment_match); |
63 | if (ret) | 53 | if (ret) |
64 | return ret; | 54 | return ret; |
65 | 55 | ||
66 | ret = xt_register_match(AF_INET6, &comment6_match); | 56 | ret = xt_register_match(&comment6_match); |
67 | if (ret) | 57 | if (ret) |
68 | xt_unregister_match(AF_INET, &comment_match); | 58 | xt_unregister_match(&comment_match); |
69 | 59 | ||
70 | return ret; | 60 | return ret; |
71 | } | 61 | } |
72 | 62 | ||
73 | static void __exit fini(void) | 63 | static void __exit fini(void) |
74 | { | 64 | { |
75 | xt_unregister_match(AF_INET, &comment_match); | 65 | xt_unregister_match(&comment_match); |
76 | xt_unregister_match(AF_INET6, &comment6_match); | 66 | xt_unregister_match(&comment6_match); |
77 | } | 67 | } |
78 | 68 | ||
79 | module_init(init); | 69 | module_init(init); |
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c index 150d2a4b0f71..4985f5ec58ca 100644 --- a/net/netfilter/xt_connbytes.c +++ b/net/netfilter/xt_connbytes.c | |||
@@ -44,6 +44,7 @@ static int | |||
44 | match(const struct sk_buff *skb, | 44 | match(const struct sk_buff *skb, |
45 | const struct net_device *in, | 45 | const struct net_device *in, |
46 | const struct net_device *out, | 46 | const struct net_device *out, |
47 | const struct xt_match *match, | ||
47 | const void *matchinfo, | 48 | const void *matchinfo, |
48 | int offset, | 49 | int offset, |
49 | unsigned int protoff, | 50 | unsigned int protoff, |
@@ -122,15 +123,13 @@ match(const struct sk_buff *skb, | |||
122 | 123 | ||
123 | static int check(const char *tablename, | 124 | static int check(const char *tablename, |
124 | const void *ip, | 125 | const void *ip, |
126 | const struct xt_match *match, | ||
125 | void *matchinfo, | 127 | void *matchinfo, |
126 | unsigned int matchsize, | 128 | unsigned int matchsize, |
127 | unsigned int hook_mask) | 129 | unsigned int hook_mask) |
128 | { | 130 | { |
129 | const struct xt_connbytes_info *sinfo = matchinfo; | 131 | const struct xt_connbytes_info *sinfo = matchinfo; |
130 | 132 | ||
131 | if (matchsize != XT_ALIGN(sizeof(struct xt_connbytes_info))) | ||
132 | return 0; | ||
133 | |||
134 | if (sinfo->what != XT_CONNBYTES_PKTS && | 133 | if (sinfo->what != XT_CONNBYTES_PKTS && |
135 | sinfo->what != XT_CONNBYTES_BYTES && | 134 | sinfo->what != XT_CONNBYTES_BYTES && |
136 | sinfo->what != XT_CONNBYTES_AVGPKT) | 135 | sinfo->what != XT_CONNBYTES_AVGPKT) |
@@ -146,34 +145,38 @@ static int check(const char *tablename, | |||
146 | 145 | ||
147 | static struct xt_match connbytes_match = { | 146 | static struct xt_match connbytes_match = { |
148 | .name = "connbytes", | 147 | .name = "connbytes", |
149 | .match = &match, | 148 | .match = match, |
150 | .checkentry = &check, | 149 | .checkentry = check, |
150 | .matchsize = sizeof(struct xt_connbytes_info), | ||
151 | .family = AF_INET, | ||
151 | .me = THIS_MODULE | 152 | .me = THIS_MODULE |
152 | }; | 153 | }; |
153 | static struct xt_match connbytes6_match = { | 154 | static struct xt_match connbytes6_match = { |
154 | .name = "connbytes", | 155 | .name = "connbytes", |
155 | .match = &match, | 156 | .match = match, |
156 | .checkentry = &check, | 157 | .checkentry = check, |
158 | .matchsize = sizeof(struct xt_connbytes_info), | ||
159 | .family = AF_INET6, | ||
157 | .me = THIS_MODULE | 160 | .me = THIS_MODULE |
158 | }; | 161 | }; |
159 | 162 | ||
160 | static int __init init(void) | 163 | static int __init init(void) |
161 | { | 164 | { |
162 | int ret; | 165 | int ret; |
163 | ret = xt_register_match(AF_INET, &connbytes_match); | 166 | ret = xt_register_match(&connbytes_match); |
164 | if (ret) | 167 | if (ret) |
165 | return ret; | 168 | return ret; |
166 | 169 | ||
167 | ret = xt_register_match(AF_INET6, &connbytes6_match); | 170 | ret = xt_register_match(&connbytes6_match); |
168 | if (ret) | 171 | if (ret) |
169 | xt_unregister_match(AF_INET, &connbytes_match); | 172 | xt_unregister_match(&connbytes_match); |
170 | return ret; | 173 | return ret; |
171 | } | 174 | } |
172 | 175 | ||
173 | static void __exit fini(void) | 176 | static void __exit fini(void) |
174 | { | 177 | { |
175 | xt_unregister_match(AF_INET, &connbytes_match); | 178 | xt_unregister_match(&connbytes_match); |
176 | xt_unregister_match(AF_INET6, &connbytes6_match); | 179 | xt_unregister_match(&connbytes6_match); |
177 | } | 180 | } |
178 | 181 | ||
179 | module_init(init); | 182 | module_init(init); |
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c index d06e925032da..7b16f1ee16b4 100644 --- a/net/netfilter/xt_connmark.c +++ b/net/netfilter/xt_connmark.c | |||
@@ -35,6 +35,7 @@ static int | |||
35 | match(const struct sk_buff *skb, | 35 | match(const struct sk_buff *skb, |
36 | const struct net_device *in, | 36 | const struct net_device *in, |
37 | const struct net_device *out, | 37 | const struct net_device *out, |
38 | const struct xt_match *match, | ||
38 | const void *matchinfo, | 39 | const void *matchinfo, |
39 | int offset, | 40 | int offset, |
40 | unsigned int protoff, | 41 | unsigned int protoff, |
@@ -52,57 +53,75 @@ match(const struct sk_buff *skb, | |||
52 | static int | 53 | static int |
53 | checkentry(const char *tablename, | 54 | checkentry(const char *tablename, |
54 | const void *ip, | 55 | const void *ip, |
56 | const struct xt_match *match, | ||
55 | void *matchinfo, | 57 | void *matchinfo, |
56 | unsigned int matchsize, | 58 | unsigned int matchsize, |
57 | unsigned int hook_mask) | 59 | unsigned int hook_mask) |
58 | { | 60 | { |
59 | struct xt_connmark_info *cm = | 61 | struct xt_connmark_info *cm = (struct xt_connmark_info *)matchinfo; |
60 | (struct xt_connmark_info *)matchinfo; | ||
61 | if (matchsize != XT_ALIGN(sizeof(struct xt_connmark_info))) | ||
62 | return 0; | ||
63 | 62 | ||
64 | if (cm->mark > 0xffffffff || cm->mask > 0xffffffff) { | 63 | if (cm->mark > 0xffffffff || cm->mask > 0xffffffff) { |
65 | printk(KERN_WARNING "connmark: only support 32bit mark\n"); | 64 | printk(KERN_WARNING "connmark: only support 32bit mark\n"); |
66 | return 0; | 65 | return 0; |
67 | } | 66 | } |
68 | 67 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | |
68 | if (nf_ct_l3proto_try_module_get(match->family) < 0) { | ||
69 | printk(KERN_WARNING "can't load nf_conntrack support for " | ||
70 | "proto=%d\n", match->family); | ||
71 | return 0; | ||
72 | } | ||
73 | #endif | ||
69 | return 1; | 74 | return 1; |
70 | } | 75 | } |
71 | 76 | ||
77 | static void | ||
78 | destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize) | ||
79 | { | ||
80 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
81 | nf_ct_l3proto_module_put(match->family); | ||
82 | #endif | ||
83 | } | ||
84 | |||
72 | static struct xt_match connmark_match = { | 85 | static struct xt_match connmark_match = { |
73 | .name = "connmark", | 86 | .name = "connmark", |
74 | .match = &match, | 87 | .match = match, |
75 | .checkentry = &checkentry, | 88 | .matchsize = sizeof(struct xt_connmark_info), |
76 | .me = THIS_MODULE | 89 | .checkentry = checkentry, |
90 | .destroy = destroy, | ||
91 | .family = AF_INET, | ||
92 | .me = THIS_MODULE | ||
77 | }; | 93 | }; |
94 | |||
78 | static struct xt_match connmark6_match = { | 95 | static struct xt_match connmark6_match = { |
79 | .name = "connmark", | 96 | .name = "connmark", |
80 | .match = &match, | 97 | .match = match, |
81 | .checkentry = &checkentry, | 98 | .matchsize = sizeof(struct xt_connmark_info), |
82 | .me = THIS_MODULE | 99 | .checkentry = checkentry, |
100 | .destroy = destroy, | ||
101 | .family = AF_INET6, | ||
102 | .me = THIS_MODULE | ||
83 | }; | 103 | }; |
84 | 104 | ||
85 | |||
86 | static int __init init(void) | 105 | static int __init init(void) |
87 | { | 106 | { |
88 | int ret; | 107 | int ret; |
89 | 108 | ||
90 | need_conntrack(); | 109 | need_conntrack(); |
91 | 110 | ||
92 | ret = xt_register_match(AF_INET, &connmark_match); | 111 | ret = xt_register_match(&connmark_match); |
93 | if (ret) | 112 | if (ret) |
94 | return ret; | 113 | return ret; |
95 | 114 | ||
96 | ret = xt_register_match(AF_INET6, &connmark6_match); | 115 | ret = xt_register_match(&connmark6_match); |
97 | if (ret) | 116 | if (ret) |
98 | xt_unregister_match(AF_INET, &connmark_match); | 117 | xt_unregister_match(&connmark_match); |
99 | return ret; | 118 | return ret; |
100 | } | 119 | } |
101 | 120 | ||
102 | static void __exit fini(void) | 121 | static void __exit fini(void) |
103 | { | 122 | { |
104 | xt_unregister_match(AF_INET6, &connmark6_match); | 123 | xt_unregister_match(&connmark6_match); |
105 | xt_unregister_match(AF_INET, &connmark_match); | 124 | xt_unregister_match(&connmark_match); |
106 | } | 125 | } |
107 | 126 | ||
108 | module_init(init); | 127 | module_init(init); |
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c index ffdebc95eb95..65a84809fd30 100644 --- a/net/netfilter/xt_conntrack.c +++ b/net/netfilter/xt_conntrack.c | |||
@@ -32,6 +32,7 @@ static int | |||
32 | match(const struct sk_buff *skb, | 32 | match(const struct sk_buff *skb, |
33 | const struct net_device *in, | 33 | const struct net_device *in, |
34 | const struct net_device *out, | 34 | const struct net_device *out, |
35 | const struct xt_match *match, | ||
35 | const void *matchinfo, | 36 | const void *matchinfo, |
36 | int offset, | 37 | int offset, |
37 | unsigned int protoff, | 38 | unsigned int protoff, |
@@ -118,6 +119,7 @@ static int | |||
118 | match(const struct sk_buff *skb, | 119 | match(const struct sk_buff *skb, |
119 | const struct net_device *in, | 120 | const struct net_device *in, |
120 | const struct net_device *out, | 121 | const struct net_device *out, |
122 | const struct xt_match *match, | ||
121 | const void *matchinfo, | 123 | const void *matchinfo, |
122 | int offset, | 124 | int offset, |
123 | unsigned int protoff, | 125 | unsigned int protoff, |
@@ -201,22 +203,39 @@ match(const struct sk_buff *skb, | |||
201 | 203 | ||
202 | #endif /* CONFIG_NF_IP_CONNTRACK */ | 204 | #endif /* CONFIG_NF_IP_CONNTRACK */ |
203 | 205 | ||
204 | static int check(const char *tablename, | 206 | static int |
205 | const void *ip, | 207 | checkentry(const char *tablename, |
206 | void *matchinfo, | 208 | const void *ip, |
207 | unsigned int matchsize, | 209 | const struct xt_match *match, |
208 | unsigned int hook_mask) | 210 | void *matchinfo, |
211 | unsigned int matchsize, | ||
212 | unsigned int hook_mask) | ||
209 | { | 213 | { |
210 | if (matchsize != XT_ALIGN(sizeof(struct xt_conntrack_info))) | 214 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
215 | if (nf_ct_l3proto_try_module_get(match->family) < 0) { | ||
216 | printk(KERN_WARNING "can't load nf_conntrack support for " | ||
217 | "proto=%d\n", match->family); | ||
211 | return 0; | 218 | return 0; |
212 | 219 | } | |
220 | #endif | ||
213 | return 1; | 221 | return 1; |
214 | } | 222 | } |
215 | 223 | ||
224 | static void | ||
225 | destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize) | ||
226 | { | ||
227 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
228 | nf_ct_l3proto_module_put(match->family); | ||
229 | #endif | ||
230 | } | ||
231 | |||
216 | static struct xt_match conntrack_match = { | 232 | static struct xt_match conntrack_match = { |
217 | .name = "conntrack", | 233 | .name = "conntrack", |
218 | .match = &match, | 234 | .match = match, |
219 | .checkentry = &check, | 235 | .checkentry = checkentry, |
236 | .destroy = destroy, | ||
237 | .matchsize = sizeof(struct xt_conntrack_info), | ||
238 | .family = AF_INET, | ||
220 | .me = THIS_MODULE, | 239 | .me = THIS_MODULE, |
221 | }; | 240 | }; |
222 | 241 | ||
@@ -224,14 +243,14 @@ static int __init init(void) | |||
224 | { | 243 | { |
225 | int ret; | 244 | int ret; |
226 | need_conntrack(); | 245 | need_conntrack(); |
227 | ret = xt_register_match(AF_INET, &conntrack_match); | 246 | ret = xt_register_match(&conntrack_match); |
228 | 247 | ||
229 | return ret; | 248 | return ret; |
230 | } | 249 | } |
231 | 250 | ||
232 | static void __exit fini(void) | 251 | static void __exit fini(void) |
233 | { | 252 | { |
234 | xt_unregister_match(AF_INET, &conntrack_match); | 253 | xt_unregister_match(&conntrack_match); |
235 | } | 254 | } |
236 | 255 | ||
237 | module_init(init); | 256 | module_init(init); |
diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c index 779f42fc9524..2f331decd151 100644 --- a/net/netfilter/xt_dccp.c +++ b/net/netfilter/xt_dccp.c | |||
@@ -95,6 +95,7 @@ static int | |||
95 | match(const struct sk_buff *skb, | 95 | match(const struct sk_buff *skb, |
96 | const struct net_device *in, | 96 | const struct net_device *in, |
97 | const struct net_device *out, | 97 | const struct net_device *out, |
98 | const struct xt_match *match, | ||
98 | const void *matchinfo, | 99 | const void *matchinfo, |
99 | int offset, | 100 | int offset, |
100 | unsigned int protoff, | 101 | unsigned int protoff, |
@@ -129,56 +130,36 @@ match(const struct sk_buff *skb, | |||
129 | static int | 130 | static int |
130 | checkentry(const char *tablename, | 131 | checkentry(const char *tablename, |
131 | const void *inf, | 132 | const void *inf, |
133 | const struct xt_match *match, | ||
132 | void *matchinfo, | 134 | void *matchinfo, |
133 | unsigned int matchsize, | 135 | unsigned int matchsize, |
134 | unsigned int hook_mask) | 136 | unsigned int hook_mask) |
135 | { | 137 | { |
136 | const struct ipt_ip *ip = inf; | 138 | const struct xt_dccp_info *info = matchinfo; |
137 | const struct xt_dccp_info *info; | ||
138 | 139 | ||
139 | info = (const struct xt_dccp_info *)matchinfo; | 140 | return !(info->flags & ~XT_DCCP_VALID_FLAGS) |
140 | |||
141 | return ip->proto == IPPROTO_DCCP | ||
142 | && !(ip->invflags & XT_INV_PROTO) | ||
143 | && matchsize == XT_ALIGN(sizeof(struct xt_dccp_info)) | ||
144 | && !(info->flags & ~XT_DCCP_VALID_FLAGS) | ||
145 | && !(info->invflags & ~XT_DCCP_VALID_FLAGS) | ||
146 | && !(info->invflags & ~info->flags); | ||
147 | } | ||
148 | |||
149 | static int | ||
150 | checkentry6(const char *tablename, | ||
151 | const void *inf, | ||
152 | void *matchinfo, | ||
153 | unsigned int matchsize, | ||
154 | unsigned int hook_mask) | ||
155 | { | ||
156 | const struct ip6t_ip6 *ip = inf; | ||
157 | const struct xt_dccp_info *info; | ||
158 | |||
159 | info = (const struct xt_dccp_info *)matchinfo; | ||
160 | |||
161 | return ip->proto == IPPROTO_DCCP | ||
162 | && !(ip->invflags & XT_INV_PROTO) | ||
163 | && matchsize == XT_ALIGN(sizeof(struct xt_dccp_info)) | ||
164 | && !(info->flags & ~XT_DCCP_VALID_FLAGS) | ||
165 | && !(info->invflags & ~XT_DCCP_VALID_FLAGS) | 141 | && !(info->invflags & ~XT_DCCP_VALID_FLAGS) |
166 | && !(info->invflags & ~info->flags); | 142 | && !(info->invflags & ~info->flags); |
167 | } | 143 | } |
168 | 144 | ||
169 | |||
170 | static struct xt_match dccp_match = | 145 | static struct xt_match dccp_match = |
171 | { | 146 | { |
172 | .name = "dccp", | 147 | .name = "dccp", |
173 | .match = &match, | 148 | .match = match, |
174 | .checkentry = &checkentry, | 149 | .matchsize = sizeof(struct xt_dccp_info), |
150 | .proto = IPPROTO_DCCP, | ||
151 | .checkentry = checkentry, | ||
152 | .family = AF_INET, | ||
175 | .me = THIS_MODULE, | 153 | .me = THIS_MODULE, |
176 | }; | 154 | }; |
177 | static struct xt_match dccp6_match = | 155 | static struct xt_match dccp6_match = |
178 | { | 156 | { |
179 | .name = "dccp", | 157 | .name = "dccp", |
180 | .match = &match, | 158 | .match = match, |
181 | .checkentry = &checkentry6, | 159 | .matchsize = sizeof(struct xt_dccp_info), |
160 | .proto = IPPROTO_DCCP, | ||
161 | .checkentry = checkentry, | ||
162 | .family = AF_INET6, | ||
182 | .me = THIS_MODULE, | 163 | .me = THIS_MODULE, |
183 | }; | 164 | }; |
184 | 165 | ||
@@ -193,17 +174,17 @@ static int __init init(void) | |||
193 | dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL); | 174 | dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL); |
194 | if (!dccp_optbuf) | 175 | if (!dccp_optbuf) |
195 | return -ENOMEM; | 176 | return -ENOMEM; |
196 | ret = xt_register_match(AF_INET, &dccp_match); | 177 | ret = xt_register_match(&dccp_match); |
197 | if (ret) | 178 | if (ret) |
198 | goto out_kfree; | 179 | goto out_kfree; |
199 | ret = xt_register_match(AF_INET6, &dccp6_match); | 180 | ret = xt_register_match(&dccp6_match); |
200 | if (ret) | 181 | if (ret) |
201 | goto out_unreg; | 182 | goto out_unreg; |
202 | 183 | ||
203 | return ret; | 184 | return ret; |
204 | 185 | ||
205 | out_unreg: | 186 | out_unreg: |
206 | xt_unregister_match(AF_INET, &dccp_match); | 187 | xt_unregister_match(&dccp_match); |
207 | out_kfree: | 188 | out_kfree: |
208 | kfree(dccp_optbuf); | 189 | kfree(dccp_optbuf); |
209 | 190 | ||
@@ -212,8 +193,8 @@ out_kfree: | |||
212 | 193 | ||
213 | static void __exit fini(void) | 194 | static void __exit fini(void) |
214 | { | 195 | { |
215 | xt_unregister_match(AF_INET6, &dccp6_match); | 196 | xt_unregister_match(&dccp6_match); |
216 | xt_unregister_match(AF_INET, &dccp_match); | 197 | xt_unregister_match(&dccp_match); |
217 | kfree(dccp_optbuf); | 198 | kfree(dccp_optbuf); |
218 | } | 199 | } |
219 | 200 | ||
diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c index 38b6715e1db4..101f0005e987 100644 --- a/net/netfilter/xt_helper.c +++ b/net/netfilter/xt_helper.c | |||
@@ -42,6 +42,7 @@ static int | |||
42 | match(const struct sk_buff *skb, | 42 | match(const struct sk_buff *skb, |
43 | const struct net_device *in, | 43 | const struct net_device *in, |
44 | const struct net_device *out, | 44 | const struct net_device *out, |
45 | const struct xt_match *match, | ||
45 | const void *matchinfo, | 46 | const void *matchinfo, |
46 | int offset, | 47 | int offset, |
47 | unsigned int protoff, | 48 | unsigned int protoff, |
@@ -89,6 +90,7 @@ static int | |||
89 | match(const struct sk_buff *skb, | 90 | match(const struct sk_buff *skb, |
90 | const struct net_device *in, | 91 | const struct net_device *in, |
91 | const struct net_device *out, | 92 | const struct net_device *out, |
93 | const struct xt_match *match, | ||
92 | const void *matchinfo, | 94 | const void *matchinfo, |
93 | int offset, | 95 | int offset, |
94 | unsigned int protoff, | 96 | unsigned int protoff, |
@@ -96,6 +98,7 @@ match(const struct sk_buff *skb, | |||
96 | { | 98 | { |
97 | const struct xt_helper_info *info = matchinfo; | 99 | const struct xt_helper_info *info = matchinfo; |
98 | struct nf_conn *ct; | 100 | struct nf_conn *ct; |
101 | struct nf_conn_help *master_help; | ||
99 | enum ip_conntrack_info ctinfo; | 102 | enum ip_conntrack_info ctinfo; |
100 | int ret = info->invert; | 103 | int ret = info->invert; |
101 | 104 | ||
@@ -111,7 +114,8 @@ match(const struct sk_buff *skb, | |||
111 | } | 114 | } |
112 | 115 | ||
113 | read_lock_bh(&nf_conntrack_lock); | 116 | read_lock_bh(&nf_conntrack_lock); |
114 | if (!ct->master->helper) { | 117 | master_help = nfct_help(ct->master); |
118 | if (!master_help || !master_help->helper) { | ||
115 | DEBUGP("xt_helper: master ct %p has no helper\n", | 119 | DEBUGP("xt_helper: master ct %p has no helper\n", |
116 | exp->expectant); | 120 | exp->expectant); |
117 | goto out_unlock; | 121 | goto out_unlock; |
@@ -123,8 +127,8 @@ match(const struct sk_buff *skb, | |||
123 | if (info->name[0] == '\0') | 127 | if (info->name[0] == '\0') |
124 | ret ^= 1; | 128 | ret ^= 1; |
125 | else | 129 | else |
126 | ret ^= !strncmp(ct->master->helper->name, info->name, | 130 | ret ^= !strncmp(master_help->helper->name, info->name, |
127 | strlen(ct->master->helper->name)); | 131 | strlen(master_help->helper->name)); |
128 | out_unlock: | 132 | out_unlock: |
129 | read_unlock_bh(&nf_conntrack_lock); | 133 | read_unlock_bh(&nf_conntrack_lock); |
130 | return ret; | 134 | return ret; |
@@ -133,31 +137,48 @@ out_unlock: | |||
133 | 137 | ||
134 | static int check(const char *tablename, | 138 | static int check(const char *tablename, |
135 | const void *inf, | 139 | const void *inf, |
140 | const struct xt_match *match, | ||
136 | void *matchinfo, | 141 | void *matchinfo, |
137 | unsigned int matchsize, | 142 | unsigned int matchsize, |
138 | unsigned int hook_mask) | 143 | unsigned int hook_mask) |
139 | { | 144 | { |
140 | struct xt_helper_info *info = matchinfo; | 145 | struct xt_helper_info *info = matchinfo; |
141 | 146 | ||
142 | info->name[29] = '\0'; | 147 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
143 | 148 | if (nf_ct_l3proto_try_module_get(match->family) < 0) { | |
144 | /* verify size */ | 149 | printk(KERN_WARNING "can't load nf_conntrack support for " |
145 | if (matchsize != XT_ALIGN(sizeof(struct xt_helper_info))) | 150 | "proto=%d\n", match->family); |
146 | return 0; | 151 | return 0; |
147 | 152 | } | |
153 | #endif | ||
154 | info->name[29] = '\0'; | ||
148 | return 1; | 155 | return 1; |
149 | } | 156 | } |
150 | 157 | ||
158 | static void | ||
159 | destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize) | ||
160 | { | ||
161 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
162 | nf_ct_l3proto_module_put(match->family); | ||
163 | #endif | ||
164 | } | ||
165 | |||
151 | static struct xt_match helper_match = { | 166 | static struct xt_match helper_match = { |
152 | .name = "helper", | 167 | .name = "helper", |
153 | .match = &match, | 168 | .match = match, |
154 | .checkentry = &check, | 169 | .matchsize = sizeof(struct xt_helper_info), |
170 | .checkentry = check, | ||
171 | .destroy = destroy, | ||
172 | .family = AF_INET, | ||
155 | .me = THIS_MODULE, | 173 | .me = THIS_MODULE, |
156 | }; | 174 | }; |
157 | static struct xt_match helper6_match = { | 175 | static struct xt_match helper6_match = { |
158 | .name = "helper", | 176 | .name = "helper", |
159 | .match = &match, | 177 | .match = match, |
160 | .checkentry = &check, | 178 | .matchsize = sizeof(struct xt_helper_info), |
179 | .checkentry = check, | ||
180 | .destroy = destroy, | ||
181 | .family = AF_INET6, | ||
161 | .me = THIS_MODULE, | 182 | .me = THIS_MODULE, |
162 | }; | 183 | }; |
163 | 184 | ||
@@ -166,21 +187,21 @@ static int __init init(void) | |||
166 | int ret; | 187 | int ret; |
167 | need_conntrack(); | 188 | need_conntrack(); |
168 | 189 | ||
169 | ret = xt_register_match(AF_INET, &helper_match); | 190 | ret = xt_register_match(&helper_match); |
170 | if (ret < 0) | 191 | if (ret < 0) |
171 | return ret; | 192 | return ret; |
172 | 193 | ||
173 | ret = xt_register_match(AF_INET6, &helper6_match); | 194 | ret = xt_register_match(&helper6_match); |
174 | if (ret < 0) | 195 | if (ret < 0) |
175 | xt_unregister_match(AF_INET, &helper_match); | 196 | xt_unregister_match(&helper_match); |
176 | 197 | ||
177 | return ret; | 198 | return ret; |
178 | } | 199 | } |
179 | 200 | ||
180 | static void __exit fini(void) | 201 | static void __exit fini(void) |
181 | { | 202 | { |
182 | xt_unregister_match(AF_INET, &helper_match); | 203 | xt_unregister_match(&helper_match); |
183 | xt_unregister_match(AF_INET6, &helper6_match); | 204 | xt_unregister_match(&helper6_match); |
184 | } | 205 | } |
185 | 206 | ||
186 | module_init(init); | 207 | module_init(init); |
diff --git a/net/netfilter/xt_length.c b/net/netfilter/xt_length.c index 39c8faea63de..38560caef757 100644 --- a/net/netfilter/xt_length.c +++ b/net/netfilter/xt_length.c | |||
@@ -24,6 +24,7 @@ static int | |||
24 | match(const struct sk_buff *skb, | 24 | match(const struct sk_buff *skb, |
25 | const struct net_device *in, | 25 | const struct net_device *in, |
26 | const struct net_device *out, | 26 | const struct net_device *out, |
27 | const struct xt_match *match, | ||
27 | const void *matchinfo, | 28 | const void *matchinfo, |
28 | int offset, | 29 | int offset, |
29 | unsigned int protoff, | 30 | unsigned int protoff, |
@@ -39,6 +40,7 @@ static int | |||
39 | match6(const struct sk_buff *skb, | 40 | match6(const struct sk_buff *skb, |
40 | const struct net_device *in, | 41 | const struct net_device *in, |
41 | const struct net_device *out, | 42 | const struct net_device *out, |
43 | const struct xt_match *match, | ||
42 | const void *matchinfo, | 44 | const void *matchinfo, |
43 | int offset, | 45 | int offset, |
44 | unsigned int protoff, | 46 | unsigned int protoff, |
@@ -50,49 +52,39 @@ match6(const struct sk_buff *skb, | |||
50 | return (pktlen >= info->min && pktlen <= info->max) ^ info->invert; | 52 | return (pktlen >= info->min && pktlen <= info->max) ^ info->invert; |
51 | } | 53 | } |
52 | 54 | ||
53 | static int | ||
54 | checkentry(const char *tablename, | ||
55 | const void *ip, | ||
56 | void *matchinfo, | ||
57 | unsigned int matchsize, | ||
58 | unsigned int hook_mask) | ||
59 | { | ||
60 | if (matchsize != XT_ALIGN(sizeof(struct xt_length_info))) | ||
61 | return 0; | ||
62 | |||
63 | return 1; | ||
64 | } | ||
65 | |||
66 | static struct xt_match length_match = { | 55 | static struct xt_match length_match = { |
67 | .name = "length", | 56 | .name = "length", |
68 | .match = &match, | 57 | .match = match, |
69 | .checkentry = &checkentry, | 58 | .matchsize = sizeof(struct xt_length_info), |
59 | .family = AF_INET, | ||
70 | .me = THIS_MODULE, | 60 | .me = THIS_MODULE, |
71 | }; | 61 | }; |
62 | |||
72 | static struct xt_match length6_match = { | 63 | static struct xt_match length6_match = { |
73 | .name = "length", | 64 | .name = "length", |
74 | .match = &match6, | 65 | .match = match6, |
75 | .checkentry = &checkentry, | 66 | .matchsize = sizeof(struct xt_length_info), |
67 | .family = AF_INET6, | ||
76 | .me = THIS_MODULE, | 68 | .me = THIS_MODULE, |
77 | }; | 69 | }; |
78 | 70 | ||
79 | static int __init init(void) | 71 | static int __init init(void) |
80 | { | 72 | { |
81 | int ret; | 73 | int ret; |
82 | ret = xt_register_match(AF_INET, &length_match); | 74 | ret = xt_register_match(&length_match); |
83 | if (ret) | 75 | if (ret) |
84 | return ret; | 76 | return ret; |
85 | ret = xt_register_match(AF_INET6, &length6_match); | 77 | ret = xt_register_match(&length6_match); |
86 | if (ret) | 78 | if (ret) |
87 | xt_unregister_match(AF_INET, &length_match); | 79 | xt_unregister_match(&length_match); |
88 | 80 | ||
89 | return ret; | 81 | return ret; |
90 | } | 82 | } |
91 | 83 | ||
92 | static void __exit fini(void) | 84 | static void __exit fini(void) |
93 | { | 85 | { |
94 | xt_unregister_match(AF_INET, &length_match); | 86 | xt_unregister_match(&length_match); |
95 | xt_unregister_match(AF_INET6, &length6_match); | 87 | xt_unregister_match(&length6_match); |
96 | } | 88 | } |
97 | 89 | ||
98 | module_init(init); | 90 | module_init(init); |
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c index 15e40506bc3a..e91c1a444e77 100644 --- a/net/netfilter/xt_limit.c +++ b/net/netfilter/xt_limit.c | |||
@@ -68,6 +68,7 @@ static int | |||
68 | ipt_limit_match(const struct sk_buff *skb, | 68 | ipt_limit_match(const struct sk_buff *skb, |
69 | const struct net_device *in, | 69 | const struct net_device *in, |
70 | const struct net_device *out, | 70 | const struct net_device *out, |
71 | const struct xt_match *match, | ||
71 | const void *matchinfo, | 72 | const void *matchinfo, |
72 | int offset, | 73 | int offset, |
73 | unsigned int protoff, | 74 | unsigned int protoff, |
@@ -107,15 +108,13 @@ user2credits(u_int32_t user) | |||
107 | static int | 108 | static int |
108 | ipt_limit_checkentry(const char *tablename, | 109 | ipt_limit_checkentry(const char *tablename, |
109 | const void *inf, | 110 | const void *inf, |
111 | const struct xt_match *match, | ||
110 | void *matchinfo, | 112 | void *matchinfo, |
111 | unsigned int matchsize, | 113 | unsigned int matchsize, |
112 | unsigned int hook_mask) | 114 | unsigned int hook_mask) |
113 | { | 115 | { |
114 | struct xt_rateinfo *r = matchinfo; | 116 | struct xt_rateinfo *r = matchinfo; |
115 | 117 | ||
116 | if (matchsize != XT_ALIGN(sizeof(struct xt_rateinfo))) | ||
117 | return 0; | ||
118 | |||
119 | /* Check for overflow. */ | 118 | /* Check for overflow. */ |
120 | if (r->burst == 0 | 119 | if (r->burst == 0 |
121 | || user2credits(r->avg * r->burst) < user2credits(r->avg)) { | 120 | || user2credits(r->avg * r->burst) < user2credits(r->avg)) { |
@@ -140,13 +139,17 @@ ipt_limit_checkentry(const char *tablename, | |||
140 | static struct xt_match ipt_limit_reg = { | 139 | static struct xt_match ipt_limit_reg = { |
141 | .name = "limit", | 140 | .name = "limit", |
142 | .match = ipt_limit_match, | 141 | .match = ipt_limit_match, |
142 | .matchsize = sizeof(struct xt_rateinfo), | ||
143 | .checkentry = ipt_limit_checkentry, | 143 | .checkentry = ipt_limit_checkentry, |
144 | .family = AF_INET, | ||
144 | .me = THIS_MODULE, | 145 | .me = THIS_MODULE, |
145 | }; | 146 | }; |
146 | static struct xt_match limit6_reg = { | 147 | static struct xt_match limit6_reg = { |
147 | .name = "limit", | 148 | .name = "limit", |
148 | .match = ipt_limit_match, | 149 | .match = ipt_limit_match, |
150 | .matchsize = sizeof(struct xt_rateinfo), | ||
149 | .checkentry = ipt_limit_checkentry, | 151 | .checkentry = ipt_limit_checkentry, |
152 | .family = AF_INET6, | ||
150 | .me = THIS_MODULE, | 153 | .me = THIS_MODULE, |
151 | }; | 154 | }; |
152 | 155 | ||
@@ -154,21 +157,21 @@ static int __init init(void) | |||
154 | { | 157 | { |
155 | int ret; | 158 | int ret; |
156 | 159 | ||
157 | ret = xt_register_match(AF_INET, &ipt_limit_reg); | 160 | ret = xt_register_match(&ipt_limit_reg); |
158 | if (ret) | 161 | if (ret) |
159 | return ret; | 162 | return ret; |
160 | 163 | ||
161 | ret = xt_register_match(AF_INET6, &limit6_reg); | 164 | ret = xt_register_match(&limit6_reg); |
162 | if (ret) | 165 | if (ret) |
163 | xt_unregister_match(AF_INET, &ipt_limit_reg); | 166 | xt_unregister_match(&ipt_limit_reg); |
164 | 167 | ||
165 | return ret; | 168 | return ret; |
166 | } | 169 | } |
167 | 170 | ||
168 | static void __exit fini(void) | 171 | static void __exit fini(void) |
169 | { | 172 | { |
170 | xt_unregister_match(AF_INET, &ipt_limit_reg); | 173 | xt_unregister_match(&ipt_limit_reg); |
171 | xt_unregister_match(AF_INET6, &limit6_reg); | 174 | xt_unregister_match(&limit6_reg); |
172 | } | 175 | } |
173 | 176 | ||
174 | module_init(init); | 177 | module_init(init); |
diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c index 0461dcb5fc7a..f4defa28a6ec 100644 --- a/net/netfilter/xt_mac.c +++ b/net/netfilter/xt_mac.c | |||
@@ -27,6 +27,7 @@ static int | |||
27 | match(const struct sk_buff *skb, | 27 | match(const struct sk_buff *skb, |
28 | const struct net_device *in, | 28 | const struct net_device *in, |
29 | const struct net_device *out, | 29 | const struct net_device *out, |
30 | const struct xt_match *match, | ||
30 | const void *matchinfo, | 31 | const void *matchinfo, |
31 | int offset, | 32 | int offset, |
32 | unsigned int protoff, | 33 | unsigned int protoff, |
@@ -42,58 +43,43 @@ match(const struct sk_buff *skb, | |||
42 | ^ info->invert)); | 43 | ^ info->invert)); |
43 | } | 44 | } |
44 | 45 | ||
45 | static int | ||
46 | ipt_mac_checkentry(const char *tablename, | ||
47 | const void *inf, | ||
48 | void *matchinfo, | ||
49 | unsigned int matchsize, | ||
50 | unsigned int hook_mask) | ||
51 | { | ||
52 | /* FORWARD isn't always valid, but it's nice to be able to do --RR */ | ||
53 | if (hook_mask | ||
54 | & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | ||
55 | | (1 << NF_IP_FORWARD))) { | ||
56 | printk("xt_mac: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n"); | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | if (matchsize != XT_ALIGN(sizeof(struct xt_mac_info))) | ||
61 | return 0; | ||
62 | |||
63 | return 1; | ||
64 | } | ||
65 | |||
66 | static struct xt_match mac_match = { | 46 | static struct xt_match mac_match = { |
67 | .name = "mac", | 47 | .name = "mac", |
68 | .match = &match, | 48 | .match = match, |
69 | .checkentry = &ipt_mac_checkentry, | 49 | .matchsize = sizeof(struct xt_mac_info), |
50 | .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | | ||
51 | (1 << NF_IP_FORWARD), | ||
52 | .family = AF_INET, | ||
70 | .me = THIS_MODULE, | 53 | .me = THIS_MODULE, |
71 | }; | 54 | }; |
72 | static struct xt_match mac6_match = { | 55 | static struct xt_match mac6_match = { |
73 | .name = "mac", | 56 | .name = "mac", |
74 | .match = &match, | 57 | .match = match, |
75 | .checkentry = &ipt_mac_checkentry, | 58 | .matchsize = sizeof(struct xt_mac_info), |
59 | .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | | ||
60 | (1 << NF_IP_FORWARD), | ||
61 | .family = AF_INET6, | ||
76 | .me = THIS_MODULE, | 62 | .me = THIS_MODULE, |
77 | }; | 63 | }; |
78 | 64 | ||
79 | static int __init init(void) | 65 | static int __init init(void) |
80 | { | 66 | { |
81 | int ret; | 67 | int ret; |
82 | ret = xt_register_match(AF_INET, &mac_match); | 68 | ret = xt_register_match(&mac_match); |
83 | if (ret) | 69 | if (ret) |
84 | return ret; | 70 | return ret; |
85 | 71 | ||
86 | ret = xt_register_match(AF_INET6, &mac6_match); | 72 | ret = xt_register_match(&mac6_match); |
87 | if (ret) | 73 | if (ret) |
88 | xt_unregister_match(AF_INET, &mac_match); | 74 | xt_unregister_match(&mac_match); |
89 | 75 | ||
90 | return ret; | 76 | return ret; |
91 | } | 77 | } |
92 | 78 | ||
93 | static void __exit fini(void) | 79 | static void __exit fini(void) |
94 | { | 80 | { |
95 | xt_unregister_match(AF_INET, &mac_match); | 81 | xt_unregister_match(&mac_match); |
96 | xt_unregister_match(AF_INET6, &mac6_match); | 82 | xt_unregister_match(&mac6_match); |
97 | } | 83 | } |
98 | 84 | ||
99 | module_init(init); | 85 | module_init(init); |
diff --git a/net/netfilter/xt_mark.c b/net/netfilter/xt_mark.c index 2a0ac62b72c8..ce0badfeef9a 100644 --- a/net/netfilter/xt_mark.c +++ b/net/netfilter/xt_mark.c | |||
@@ -23,6 +23,7 @@ static int | |||
23 | match(const struct sk_buff *skb, | 23 | match(const struct sk_buff *skb, |
24 | const struct net_device *in, | 24 | const struct net_device *in, |
25 | const struct net_device *out, | 25 | const struct net_device *out, |
26 | const struct xt_match *match, | ||
26 | const void *matchinfo, | 27 | const void *matchinfo, |
27 | int offset, | 28 | int offset, |
28 | unsigned int protoff, | 29 | unsigned int protoff, |
@@ -36,55 +37,56 @@ match(const struct sk_buff *skb, | |||
36 | static int | 37 | static int |
37 | checkentry(const char *tablename, | 38 | checkentry(const char *tablename, |
38 | const void *entry, | 39 | const void *entry, |
40 | const struct xt_match *match, | ||
39 | void *matchinfo, | 41 | void *matchinfo, |
40 | unsigned int matchsize, | 42 | unsigned int matchsize, |
41 | unsigned int hook_mask) | 43 | unsigned int hook_mask) |
42 | { | 44 | { |
43 | struct xt_mark_info *minfo = (struct xt_mark_info *) matchinfo; | 45 | struct xt_mark_info *minfo = (struct xt_mark_info *) matchinfo; |
44 | 46 | ||
45 | if (matchsize != XT_ALIGN(sizeof(struct xt_mark_info))) | ||
46 | return 0; | ||
47 | |||
48 | if (minfo->mark > 0xffffffff || minfo->mask > 0xffffffff) { | 47 | if (minfo->mark > 0xffffffff || minfo->mask > 0xffffffff) { |
49 | printk(KERN_WARNING "mark: only supports 32bit mark\n"); | 48 | printk(KERN_WARNING "mark: only supports 32bit mark\n"); |
50 | return 0; | 49 | return 0; |
51 | } | 50 | } |
52 | |||
53 | return 1; | 51 | return 1; |
54 | } | 52 | } |
55 | 53 | ||
56 | static struct xt_match mark_match = { | 54 | static struct xt_match mark_match = { |
57 | .name = "mark", | 55 | .name = "mark", |
58 | .match = &match, | 56 | .match = match, |
59 | .checkentry = &checkentry, | 57 | .matchsize = sizeof(struct xt_mark_info), |
58 | .checkentry = checkentry, | ||
59 | .family = AF_INET, | ||
60 | .me = THIS_MODULE, | 60 | .me = THIS_MODULE, |
61 | }; | 61 | }; |
62 | 62 | ||
63 | static struct xt_match mark6_match = { | 63 | static struct xt_match mark6_match = { |
64 | .name = "mark", | 64 | .name = "mark", |
65 | .match = &match, | 65 | .match = match, |
66 | .checkentry = &checkentry, | 66 | .matchsize = sizeof(struct xt_mark_info), |
67 | .checkentry = checkentry, | ||
68 | .family = AF_INET6, | ||
67 | .me = THIS_MODULE, | 69 | .me = THIS_MODULE, |
68 | }; | 70 | }; |
69 | 71 | ||
70 | static int __init init(void) | 72 | static int __init init(void) |
71 | { | 73 | { |
72 | int ret; | 74 | int ret; |
73 | ret = xt_register_match(AF_INET, &mark_match); | 75 | ret = xt_register_match(&mark_match); |
74 | if (ret) | 76 | if (ret) |
75 | return ret; | 77 | return ret; |
76 | 78 | ||
77 | ret = xt_register_match(AF_INET6, &mark6_match); | 79 | ret = xt_register_match(&mark6_match); |
78 | if (ret) | 80 | if (ret) |
79 | xt_unregister_match(AF_INET, &mark_match); | 81 | xt_unregister_match(&mark_match); |
80 | 82 | ||
81 | return ret; | 83 | return ret; |
82 | } | 84 | } |
83 | 85 | ||
84 | static void __exit fini(void) | 86 | static void __exit fini(void) |
85 | { | 87 | { |
86 | xt_unregister_match(AF_INET, &mark_match); | 88 | xt_unregister_match(&mark_match); |
87 | xt_unregister_match(AF_INET6, &mark6_match); | 89 | xt_unregister_match(&mark6_match); |
88 | } | 90 | } |
89 | 91 | ||
90 | module_init(init); | 92 | module_init(init); |
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c index 19bb57c14dfe..089f4f7e8636 100644 --- a/net/netfilter/xt_physdev.c +++ b/net/netfilter/xt_physdev.c | |||
@@ -26,6 +26,7 @@ static int | |||
26 | match(const struct sk_buff *skb, | 26 | match(const struct sk_buff *skb, |
27 | const struct net_device *in, | 27 | const struct net_device *in, |
28 | const struct net_device *out, | 28 | const struct net_device *out, |
29 | const struct xt_match *match, | ||
29 | const void *matchinfo, | 30 | const void *matchinfo, |
30 | int offset, | 31 | int offset, |
31 | unsigned int protoff, | 32 | unsigned int protoff, |
@@ -102,14 +103,13 @@ match_outdev: | |||
102 | static int | 103 | static int |
103 | checkentry(const char *tablename, | 104 | checkentry(const char *tablename, |
104 | const void *ip, | 105 | const void *ip, |
106 | const struct xt_match *match, | ||
105 | void *matchinfo, | 107 | void *matchinfo, |
106 | unsigned int matchsize, | 108 | unsigned int matchsize, |
107 | unsigned int hook_mask) | 109 | unsigned int hook_mask) |
108 | { | 110 | { |
109 | const struct xt_physdev_info *info = matchinfo; | 111 | const struct xt_physdev_info *info = matchinfo; |
110 | 112 | ||
111 | if (matchsize != XT_ALIGN(sizeof(struct xt_physdev_info))) | ||
112 | return 0; | ||
113 | if (!(info->bitmask & XT_PHYSDEV_OP_MASK) || | 113 | if (!(info->bitmask & XT_PHYSDEV_OP_MASK) || |
114 | info->bitmask & ~XT_PHYSDEV_OP_MASK) | 114 | info->bitmask & ~XT_PHYSDEV_OP_MASK) |
115 | return 0; | 115 | return 0; |
@@ -118,15 +118,19 @@ checkentry(const char *tablename, | |||
118 | 118 | ||
119 | static struct xt_match physdev_match = { | 119 | static struct xt_match physdev_match = { |
120 | .name = "physdev", | 120 | .name = "physdev", |
121 | .match = &match, | 121 | .match = match, |
122 | .checkentry = &checkentry, | 122 | .matchsize = sizeof(struct xt_physdev_info), |
123 | .checkentry = checkentry, | ||
124 | .family = AF_INET, | ||
123 | .me = THIS_MODULE, | 125 | .me = THIS_MODULE, |
124 | }; | 126 | }; |
125 | 127 | ||
126 | static struct xt_match physdev6_match = { | 128 | static struct xt_match physdev6_match = { |
127 | .name = "physdev", | 129 | .name = "physdev", |
128 | .match = &match, | 130 | .match = match, |
129 | .checkentry = &checkentry, | 131 | .matchsize = sizeof(struct xt_physdev_info), |
132 | .checkentry = checkentry, | ||
133 | .family = AF_INET6, | ||
130 | .me = THIS_MODULE, | 134 | .me = THIS_MODULE, |
131 | }; | 135 | }; |
132 | 136 | ||
@@ -134,21 +138,21 @@ static int __init init(void) | |||
134 | { | 138 | { |
135 | int ret; | 139 | int ret; |
136 | 140 | ||
137 | ret = xt_register_match(AF_INET, &physdev_match); | 141 | ret = xt_register_match(&physdev_match); |
138 | if (ret < 0) | 142 | if (ret < 0) |
139 | return ret; | 143 | return ret; |
140 | 144 | ||
141 | ret = xt_register_match(AF_INET6, &physdev6_match); | 145 | ret = xt_register_match(&physdev6_match); |
142 | if (ret < 0) | 146 | if (ret < 0) |
143 | xt_unregister_match(AF_INET, &physdev_match); | 147 | xt_unregister_match(&physdev_match); |
144 | 148 | ||
145 | return ret; | 149 | return ret; |
146 | } | 150 | } |
147 | 151 | ||
148 | static void __exit fini(void) | 152 | static void __exit fini(void) |
149 | { | 153 | { |
150 | xt_unregister_match(AF_INET, &physdev_match); | 154 | xt_unregister_match(&physdev_match); |
151 | xt_unregister_match(AF_INET6, &physdev6_match); | 155 | xt_unregister_match(&physdev6_match); |
152 | } | 156 | } |
153 | 157 | ||
154 | module_init(init); | 158 | module_init(init); |
diff --git a/net/netfilter/xt_pkttype.c b/net/netfilter/xt_pkttype.c index ab1b2630f97d..8b8bca988ac6 100644 --- a/net/netfilter/xt_pkttype.c +++ b/net/netfilter/xt_pkttype.c | |||
@@ -22,6 +22,7 @@ MODULE_ALIAS("ip6t_pkttype"); | |||
22 | static int match(const struct sk_buff *skb, | 22 | static int match(const struct sk_buff *skb, |
23 | const struct net_device *in, | 23 | const struct net_device *in, |
24 | const struct net_device *out, | 24 | const struct net_device *out, |
25 | const struct xt_match *match, | ||
25 | const void *matchinfo, | 26 | const void *matchinfo, |
26 | int offset, | 27 | int offset, |
27 | unsigned int protoff, | 28 | unsigned int protoff, |
@@ -32,50 +33,40 @@ static int match(const struct sk_buff *skb, | |||
32 | return (skb->pkt_type == info->pkttype) ^ info->invert; | 33 | return (skb->pkt_type == info->pkttype) ^ info->invert; |
33 | } | 34 | } |
34 | 35 | ||
35 | static int checkentry(const char *tablename, | ||
36 | const void *ip, | ||
37 | void *matchinfo, | ||
38 | unsigned int matchsize, | ||
39 | unsigned int hook_mask) | ||
40 | { | ||
41 | if (matchsize != XT_ALIGN(sizeof(struct xt_pkttype_info))) | ||
42 | return 0; | ||
43 | |||
44 | return 1; | ||
45 | } | ||
46 | |||
47 | static struct xt_match pkttype_match = { | 36 | static struct xt_match pkttype_match = { |
48 | .name = "pkttype", | 37 | .name = "pkttype", |
49 | .match = &match, | 38 | .match = match, |
50 | .checkentry = &checkentry, | 39 | .matchsize = sizeof(struct xt_pkttype_info), |
40 | .family = AF_INET, | ||
51 | .me = THIS_MODULE, | 41 | .me = THIS_MODULE, |
52 | }; | 42 | }; |
43 | |||
53 | static struct xt_match pkttype6_match = { | 44 | static struct xt_match pkttype6_match = { |
54 | .name = "pkttype", | 45 | .name = "pkttype", |
55 | .match = &match, | 46 | .match = match, |
56 | .checkentry = &checkentry, | 47 | .matchsize = sizeof(struct xt_pkttype_info), |
48 | .family = AF_INET6, | ||
57 | .me = THIS_MODULE, | 49 | .me = THIS_MODULE, |
58 | }; | 50 | }; |
59 | 51 | ||
60 | |||
61 | static int __init init(void) | 52 | static int __init init(void) |
62 | { | 53 | { |
63 | int ret; | 54 | int ret; |
64 | ret = xt_register_match(AF_INET, &pkttype_match); | 55 | ret = xt_register_match(&pkttype_match); |
65 | if (ret) | 56 | if (ret) |
66 | return ret; | 57 | return ret; |
67 | 58 | ||
68 | ret = xt_register_match(AF_INET6, &pkttype6_match); | 59 | ret = xt_register_match(&pkttype6_match); |
69 | if (ret) | 60 | if (ret) |
70 | xt_unregister_match(AF_INET, &pkttype_match); | 61 | xt_unregister_match(&pkttype_match); |
71 | 62 | ||
72 | return ret; | 63 | return ret; |
73 | } | 64 | } |
74 | 65 | ||
75 | static void __exit fini(void) | 66 | static void __exit fini(void) |
76 | { | 67 | { |
77 | xt_unregister_match(AF_INET, &pkttype_match); | 68 | xt_unregister_match(&pkttype_match); |
78 | xt_unregister_match(AF_INET6, &pkttype6_match); | 69 | xt_unregister_match(&pkttype6_match); |
79 | } | 70 | } |
80 | 71 | ||
81 | module_init(init); | 72 | module_init(init); |
diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c new file mode 100644 index 000000000000..1099cb005fcc --- /dev/null +++ b/net/netfilter/xt_policy.c | |||
@@ -0,0 +1,211 @@ | |||
1 | /* IP tables module for matching IPsec policy | ||
2 | * | ||
3 | * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/skbuff.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <net/xfrm.h> | ||
16 | |||
17 | #include <linux/netfilter/xt_policy.h> | ||
18 | #include <linux/netfilter/x_tables.h> | ||
19 | |||
20 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
21 | MODULE_DESCRIPTION("Xtables IPsec policy matching module"); | ||
22 | MODULE_LICENSE("GPL"); | ||
23 | |||
24 | static inline int | ||
25 | xt_addr_cmp(const union xt_policy_addr *a1, const union xt_policy_addr *m, | ||
26 | const union xt_policy_addr *a2, unsigned short family) | ||
27 | { | ||
28 | switch (family) { | ||
29 | case AF_INET: | ||
30 | return !((a1->a4.s_addr ^ a2->a4.s_addr) & m->a4.s_addr); | ||
31 | case AF_INET6: | ||
32 | return !ipv6_masked_addr_cmp(&a1->a6, &m->a6, &a2->a6); | ||
33 | } | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static inline int | ||
38 | match_xfrm_state(struct xfrm_state *x, const struct xt_policy_elem *e, | ||
39 | unsigned short family) | ||
40 | { | ||
41 | #define MATCH_ADDR(x,y,z) (!e->match.x || \ | ||
42 | (xt_addr_cmp(&e->x, &e->y, z, family) \ | ||
43 | ^ e->invert.x)) | ||
44 | #define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x)) | ||
45 | |||
46 | return MATCH_ADDR(saddr, smask, (union xt_policy_addr *)&x->props.saddr) && | ||
47 | MATCH_ADDR(daddr, dmask, (union xt_policy_addr *)&x->id.daddr) && | ||
48 | MATCH(proto, x->id.proto) && | ||
49 | MATCH(mode, x->props.mode) && | ||
50 | MATCH(spi, x->id.spi) && | ||
51 | MATCH(reqid, x->props.reqid); | ||
52 | } | ||
53 | |||
54 | static int | ||
55 | match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info, | ||
56 | unsigned short family) | ||
57 | { | ||
58 | const struct xt_policy_elem *e; | ||
59 | struct sec_path *sp = skb->sp; | ||
60 | int strict = info->flags & XT_POLICY_MATCH_STRICT; | ||
61 | int i, pos; | ||
62 | |||
63 | if (sp == NULL) | ||
64 | return -1; | ||
65 | if (strict && info->len != sp->len) | ||
66 | return 0; | ||
67 | |||
68 | for (i = sp->len - 1; i >= 0; i--) { | ||
69 | pos = strict ? i - sp->len + 1 : 0; | ||
70 | if (pos >= info->len) | ||
71 | return 0; | ||
72 | e = &info->pol[pos]; | ||
73 | |||
74 | if (match_xfrm_state(sp->x[i].xvec, e, family)) { | ||
75 | if (!strict) | ||
76 | return 1; | ||
77 | } else if (strict) | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | return strict ? 1 : 0; | ||
82 | } | ||
83 | |||
84 | static int | ||
85 | match_policy_out(const struct sk_buff *skb, const struct xt_policy_info *info, | ||
86 | unsigned short family) | ||
87 | { | ||
88 | const struct xt_policy_elem *e; | ||
89 | struct dst_entry *dst = skb->dst; | ||
90 | int strict = info->flags & XT_POLICY_MATCH_STRICT; | ||
91 | int i, pos; | ||
92 | |||
93 | if (dst->xfrm == NULL) | ||
94 | return -1; | ||
95 | |||
96 | for (i = 0; dst && dst->xfrm; dst = dst->child, i++) { | ||
97 | pos = strict ? i : 0; | ||
98 | if (pos >= info->len) | ||
99 | return 0; | ||
100 | e = &info->pol[pos]; | ||
101 | |||
102 | if (match_xfrm_state(dst->xfrm, e, family)) { | ||
103 | if (!strict) | ||
104 | return 1; | ||
105 | } else if (strict) | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | return strict ? i == info->len : 0; | ||
110 | } | ||
111 | |||
112 | static int match(const struct sk_buff *skb, | ||
113 | const struct net_device *in, | ||
114 | const struct net_device *out, | ||
115 | const struct xt_match *match, | ||
116 | const void *matchinfo, | ||
117 | int offset, | ||
118 | unsigned int protoff, | ||
119 | int *hotdrop) | ||
120 | { | ||
121 | const struct xt_policy_info *info = matchinfo; | ||
122 | int ret; | ||
123 | |||
124 | if (info->flags & XT_POLICY_MATCH_IN) | ||
125 | ret = match_policy_in(skb, info, match->family); | ||
126 | else | ||
127 | ret = match_policy_out(skb, info, match->family); | ||
128 | |||
129 | if (ret < 0) | ||
130 | ret = info->flags & XT_POLICY_MATCH_NONE ? 1 : 0; | ||
131 | else if (info->flags & XT_POLICY_MATCH_NONE) | ||
132 | ret = 0; | ||
133 | |||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | static int checkentry(const char *tablename, const void *ip_void, | ||
138 | const struct xt_match *match, | ||
139 | void *matchinfo, unsigned int matchsize, | ||
140 | unsigned int hook_mask) | ||
141 | { | ||
142 | struct xt_policy_info *info = matchinfo; | ||
143 | |||
144 | if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT))) { | ||
145 | printk(KERN_ERR "xt_policy: neither incoming nor " | ||
146 | "outgoing policy selected\n"); | ||
147 | return 0; | ||
148 | } | ||
149 | /* hook values are equal for IPv4 and IPv6 */ | ||
150 | if (hook_mask & (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN) | ||
151 | && info->flags & XT_POLICY_MATCH_OUT) { | ||
152 | printk(KERN_ERR "xt_policy: output policy not valid in " | ||
153 | "PRE_ROUTING and INPUT\n"); | ||
154 | return 0; | ||
155 | } | ||
156 | if (hook_mask & (1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT) | ||
157 | && info->flags & XT_POLICY_MATCH_IN) { | ||
158 | printk(KERN_ERR "xt_policy: input policy not valid in " | ||
159 | "POST_ROUTING and OUTPUT\n"); | ||
160 | return 0; | ||
161 | } | ||
162 | if (info->len > XT_POLICY_MAX_ELEM) { | ||
163 | printk(KERN_ERR "xt_policy: too many policy elements\n"); | ||
164 | return 0; | ||
165 | } | ||
166 | return 1; | ||
167 | } | ||
168 | |||
169 | static struct xt_match policy_match = { | ||
170 | .name = "policy", | ||
171 | .family = AF_INET, | ||
172 | .match = match, | ||
173 | .matchsize = sizeof(struct xt_policy_info), | ||
174 | .checkentry = checkentry, | ||
175 | .family = AF_INET, | ||
176 | .me = THIS_MODULE, | ||
177 | }; | ||
178 | |||
179 | static struct xt_match policy6_match = { | ||
180 | .name = "policy", | ||
181 | .family = AF_INET6, | ||
182 | .match = match, | ||
183 | .matchsize = sizeof(struct xt_policy_info), | ||
184 | .checkentry = checkentry, | ||
185 | .family = AF_INET6, | ||
186 | .me = THIS_MODULE, | ||
187 | }; | ||
188 | |||
189 | static int __init init(void) | ||
190 | { | ||
191 | int ret; | ||
192 | |||
193 | ret = xt_register_match(&policy_match); | ||
194 | if (ret) | ||
195 | return ret; | ||
196 | ret = xt_register_match(&policy6_match); | ||
197 | if (ret) | ||
198 | xt_unregister_match(&policy_match); | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static void __exit fini(void) | ||
203 | { | ||
204 | xt_unregister_match(&policy6_match); | ||
205 | xt_unregister_match(&policy_match); | ||
206 | } | ||
207 | |||
208 | module_init(init); | ||
209 | module_exit(fini); | ||
210 | MODULE_ALIAS("ipt_policy"); | ||
211 | MODULE_ALIAS("ip6t_policy"); | ||
diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c index 2b7e1781d34d..5e31a4a835bf 100644 --- a/net/netfilter/xt_realm.c +++ b/net/netfilter/xt_realm.c | |||
@@ -27,6 +27,7 @@ static int | |||
27 | match(const struct sk_buff *skb, | 27 | match(const struct sk_buff *skb, |
28 | const struct net_device *in, | 28 | const struct net_device *in, |
29 | const struct net_device *out, | 29 | const struct net_device *out, |
30 | const struct xt_match *match, | ||
30 | const void *matchinfo, | 31 | const void *matchinfo, |
31 | int offset, | 32 | int offset, |
32 | unsigned int protoff, | 33 | unsigned int protoff, |
@@ -38,41 +39,24 @@ match(const struct sk_buff *skb, | |||
38 | return (info->id == (dst->tclassid & info->mask)) ^ info->invert; | 39 | return (info->id == (dst->tclassid & info->mask)) ^ info->invert; |
39 | } | 40 | } |
40 | 41 | ||
41 | static int check(const char *tablename, | ||
42 | const void *ip, | ||
43 | void *matchinfo, | ||
44 | unsigned int matchsize, | ||
45 | unsigned int hook_mask) | ||
46 | { | ||
47 | if (hook_mask | ||
48 | & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) | | ||
49 | (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_LOCAL_IN))) { | ||
50 | printk("xt_realm: only valid for POST_ROUTING, LOCAL_OUT, " | ||
51 | "LOCAL_IN or FORWARD.\n"); | ||
52 | return 0; | ||
53 | } | ||
54 | if (matchsize != XT_ALIGN(sizeof(struct xt_realm_info))) { | ||
55 | printk("xt_realm: invalid matchsize.\n"); | ||
56 | return 0; | ||
57 | } | ||
58 | return 1; | ||
59 | } | ||
60 | |||
61 | static struct xt_match realm_match = { | 42 | static struct xt_match realm_match = { |
62 | .name = "realm", | 43 | .name = "realm", |
63 | .match = match, | 44 | .match = match, |
64 | .checkentry = check, | 45 | .matchsize = sizeof(struct xt_realm_info), |
46 | .hooks = (1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) | | ||
47 | (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_LOCAL_IN), | ||
48 | .family = AF_INET, | ||
65 | .me = THIS_MODULE | 49 | .me = THIS_MODULE |
66 | }; | 50 | }; |
67 | 51 | ||
68 | static int __init init(void) | 52 | static int __init init(void) |
69 | { | 53 | { |
70 | return xt_register_match(AF_INET, &realm_match); | 54 | return xt_register_match(&realm_match); |
71 | } | 55 | } |
72 | 56 | ||
73 | static void __exit fini(void) | 57 | static void __exit fini(void) |
74 | { | 58 | { |
75 | xt_unregister_match(AF_INET, &realm_match); | 59 | xt_unregister_match(&realm_match); |
76 | } | 60 | } |
77 | 61 | ||
78 | module_init(init); | 62 | module_init(init); |
diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c index 10fbfc5ba758..c6eb24a2fe13 100644 --- a/net/netfilter/xt_sctp.c +++ b/net/netfilter/xt_sctp.c | |||
@@ -123,6 +123,7 @@ static int | |||
123 | match(const struct sk_buff *skb, | 123 | match(const struct sk_buff *skb, |
124 | const struct net_device *in, | 124 | const struct net_device *in, |
125 | const struct net_device *out, | 125 | const struct net_device *out, |
126 | const struct xt_match *match, | ||
126 | const void *matchinfo, | 127 | const void *matchinfo, |
127 | int offset, | 128 | int offset, |
128 | unsigned int protoff, | 129 | unsigned int protoff, |
@@ -162,19 +163,14 @@ match(const struct sk_buff *skb, | |||
162 | static int | 163 | static int |
163 | checkentry(const char *tablename, | 164 | checkentry(const char *tablename, |
164 | const void *inf, | 165 | const void *inf, |
166 | const struct xt_match *match, | ||
165 | void *matchinfo, | 167 | void *matchinfo, |
166 | unsigned int matchsize, | 168 | unsigned int matchsize, |
167 | unsigned int hook_mask) | 169 | unsigned int hook_mask) |
168 | { | 170 | { |
169 | const struct xt_sctp_info *info; | 171 | const struct xt_sctp_info *info = matchinfo; |
170 | const struct ipt_ip *ip = inf; | ||
171 | |||
172 | info = (const struct xt_sctp_info *)matchinfo; | ||
173 | 172 | ||
174 | return ip->proto == IPPROTO_SCTP | 173 | return !(info->flags & ~XT_SCTP_VALID_FLAGS) |
175 | && !(ip->invflags & XT_INV_PROTO) | ||
176 | && matchsize == XT_ALIGN(sizeof(struct xt_sctp_info)) | ||
177 | && !(info->flags & ~XT_SCTP_VALID_FLAGS) | ||
178 | && !(info->invflags & ~XT_SCTP_VALID_FLAGS) | 174 | && !(info->invflags & ~XT_SCTP_VALID_FLAGS) |
179 | && !(info->invflags & ~info->flags) | 175 | && !(info->invflags & ~info->flags) |
180 | && ((!(info->flags & XT_SCTP_CHUNK_TYPES)) || | 176 | && ((!(info->flags & XT_SCTP_CHUNK_TYPES)) || |
@@ -184,66 +180,44 @@ checkentry(const char *tablename, | |||
184 | | SCTP_CHUNK_MATCH_ONLY))); | 180 | | SCTP_CHUNK_MATCH_ONLY))); |
185 | } | 181 | } |
186 | 182 | ||
187 | static int | 183 | static struct xt_match sctp_match = { |
188 | checkentry6(const char *tablename, | 184 | .name = "sctp", |
189 | const void *inf, | 185 | .match = match, |
190 | void *matchinfo, | 186 | .matchsize = sizeof(struct xt_sctp_info), |
191 | unsigned int matchsize, | 187 | .proto = IPPROTO_SCTP, |
192 | unsigned int hook_mask) | 188 | .checkentry = checkentry, |
193 | { | 189 | .family = AF_INET, |
194 | const struct xt_sctp_info *info; | 190 | .me = THIS_MODULE |
195 | const struct ip6t_ip6 *ip = inf; | ||
196 | |||
197 | info = (const struct xt_sctp_info *)matchinfo; | ||
198 | |||
199 | return ip->proto == IPPROTO_SCTP | ||
200 | && !(ip->invflags & XT_INV_PROTO) | ||
201 | && matchsize == XT_ALIGN(sizeof(struct xt_sctp_info)) | ||
202 | && !(info->flags & ~XT_SCTP_VALID_FLAGS) | ||
203 | && !(info->invflags & ~XT_SCTP_VALID_FLAGS) | ||
204 | && !(info->invflags & ~info->flags) | ||
205 | && ((!(info->flags & XT_SCTP_CHUNK_TYPES)) || | ||
206 | (info->chunk_match_type & | ||
207 | (SCTP_CHUNK_MATCH_ALL | ||
208 | | SCTP_CHUNK_MATCH_ANY | ||
209 | | SCTP_CHUNK_MATCH_ONLY))); | ||
210 | } | ||
211 | |||
212 | |||
213 | static struct xt_match sctp_match = | ||
214 | { | ||
215 | .name = "sctp", | ||
216 | .match = &match, | ||
217 | .checkentry = &checkentry, | ||
218 | .me = THIS_MODULE | ||
219 | }; | ||
220 | static struct xt_match sctp6_match = | ||
221 | { | ||
222 | .name = "sctp", | ||
223 | .match = &match, | ||
224 | .checkentry = &checkentry6, | ||
225 | .me = THIS_MODULE | ||
226 | }; | 191 | }; |
227 | 192 | ||
193 | static struct xt_match sctp6_match = { | ||
194 | .name = "sctp", | ||
195 | .match = match, | ||
196 | .matchsize = sizeof(struct xt_sctp_info), | ||
197 | .proto = IPPROTO_SCTP, | ||
198 | .checkentry = checkentry, | ||
199 | .family = AF_INET6, | ||
200 | .me = THIS_MODULE | ||
201 | }; | ||
228 | 202 | ||
229 | static int __init init(void) | 203 | static int __init init(void) |
230 | { | 204 | { |
231 | int ret; | 205 | int ret; |
232 | ret = xt_register_match(AF_INET, &sctp_match); | 206 | ret = xt_register_match(&sctp_match); |
233 | if (ret) | 207 | if (ret) |
234 | return ret; | 208 | return ret; |
235 | 209 | ||
236 | ret = xt_register_match(AF_INET6, &sctp6_match); | 210 | ret = xt_register_match(&sctp6_match); |
237 | if (ret) | 211 | if (ret) |
238 | xt_unregister_match(AF_INET, &sctp_match); | 212 | xt_unregister_match(&sctp_match); |
239 | 213 | ||
240 | return ret; | 214 | return ret; |
241 | } | 215 | } |
242 | 216 | ||
243 | static void __exit fini(void) | 217 | static void __exit fini(void) |
244 | { | 218 | { |
245 | xt_unregister_match(AF_INET6, &sctp6_match); | 219 | xt_unregister_match(&sctp6_match); |
246 | xt_unregister_match(AF_INET, &sctp_match); | 220 | xt_unregister_match(&sctp_match); |
247 | } | 221 | } |
248 | 222 | ||
249 | module_init(init); | 223 | module_init(init); |
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c index 39ce808d40ef..e6c0be9d94d2 100644 --- a/net/netfilter/xt_state.c +++ b/net/netfilter/xt_state.c | |||
@@ -24,6 +24,7 @@ static int | |||
24 | match(const struct sk_buff *skb, | 24 | match(const struct sk_buff *skb, |
25 | const struct net_device *in, | 25 | const struct net_device *in, |
26 | const struct net_device *out, | 26 | const struct net_device *out, |
27 | const struct xt_match *match, | ||
27 | const void *matchinfo, | 28 | const void *matchinfo, |
28 | int offset, | 29 | int offset, |
29 | unsigned int protoff, | 30 | unsigned int protoff, |
@@ -44,28 +45,47 @@ match(const struct sk_buff *skb, | |||
44 | } | 45 | } |
45 | 46 | ||
46 | static int check(const char *tablename, | 47 | static int check(const char *tablename, |
47 | const void *ip, | 48 | const void *inf, |
49 | const struct xt_match *match, | ||
48 | void *matchinfo, | 50 | void *matchinfo, |
49 | unsigned int matchsize, | 51 | unsigned int matchsize, |
50 | unsigned int hook_mask) | 52 | unsigned int hook_mask) |
51 | { | 53 | { |
52 | if (matchsize != XT_ALIGN(sizeof(struct xt_state_info))) | 54 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
55 | if (nf_ct_l3proto_try_module_get(match->family) < 0) { | ||
56 | printk(KERN_WARNING "can't load nf_conntrack support for " | ||
57 | "proto=%d\n", match->family); | ||
53 | return 0; | 58 | return 0; |
54 | 59 | } | |
60 | #endif | ||
55 | return 1; | 61 | return 1; |
56 | } | 62 | } |
57 | 63 | ||
64 | static void | ||
65 | destroy(const struct xt_match *match, void *matchinfo, unsigned int matchsize) | ||
66 | { | ||
67 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
68 | nf_ct_l3proto_module_put(match->family); | ||
69 | #endif | ||
70 | } | ||
71 | |||
58 | static struct xt_match state_match = { | 72 | static struct xt_match state_match = { |
59 | .name = "state", | 73 | .name = "state", |
60 | .match = &match, | 74 | .match = match, |
61 | .checkentry = &check, | 75 | .checkentry = check, |
76 | .destroy = destroy, | ||
77 | .matchsize = sizeof(struct xt_state_info), | ||
78 | .family = AF_INET, | ||
62 | .me = THIS_MODULE, | 79 | .me = THIS_MODULE, |
63 | }; | 80 | }; |
64 | 81 | ||
65 | static struct xt_match state6_match = { | 82 | static struct xt_match state6_match = { |
66 | .name = "state", | 83 | .name = "state", |
67 | .match = &match, | 84 | .match = match, |
68 | .checkentry = &check, | 85 | .checkentry = check, |
86 | .destroy = destroy, | ||
87 | .matchsize = sizeof(struct xt_state_info), | ||
88 | .family = AF_INET6, | ||
69 | .me = THIS_MODULE, | 89 | .me = THIS_MODULE, |
70 | }; | 90 | }; |
71 | 91 | ||
@@ -75,21 +95,21 @@ static int __init init(void) | |||
75 | 95 | ||
76 | need_conntrack(); | 96 | need_conntrack(); |
77 | 97 | ||
78 | ret = xt_register_match(AF_INET, &state_match); | 98 | ret = xt_register_match(&state_match); |
79 | if (ret < 0) | 99 | if (ret < 0) |
80 | return ret; | 100 | return ret; |
81 | 101 | ||
82 | ret = xt_register_match(AF_INET6, &state6_match); | 102 | ret = xt_register_match(&state6_match); |
83 | if (ret < 0) | 103 | if (ret < 0) |
84 | xt_unregister_match(AF_INET,&state_match); | 104 | xt_unregister_match(&state_match); |
85 | 105 | ||
86 | return ret; | 106 | return ret; |
87 | } | 107 | } |
88 | 108 | ||
89 | static void __exit fini(void) | 109 | static void __exit fini(void) |
90 | { | 110 | { |
91 | xt_unregister_match(AF_INET, &state_match); | 111 | xt_unregister_match(&state_match); |
92 | xt_unregister_match(AF_INET6, &state6_match); | 112 | xt_unregister_match(&state6_match); |
93 | } | 113 | } |
94 | 114 | ||
95 | module_init(init); | 115 | module_init(init); |
diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c index 7c7d5c8807d6..703d80fccacf 100644 --- a/net/netfilter/xt_string.c +++ b/net/netfilter/xt_string.c | |||
@@ -24,6 +24,7 @@ MODULE_ALIAS("ip6t_string"); | |||
24 | static int match(const struct sk_buff *skb, | 24 | static int match(const struct sk_buff *skb, |
25 | const struct net_device *in, | 25 | const struct net_device *in, |
26 | const struct net_device *out, | 26 | const struct net_device *out, |
27 | const struct xt_match *match, | ||
27 | const void *matchinfo, | 28 | const void *matchinfo, |
28 | int offset, | 29 | int offset, |
29 | unsigned int protoff, | 30 | unsigned int protoff, |
@@ -43,6 +44,7 @@ static int match(const struct sk_buff *skb, | |||
43 | 44 | ||
44 | static int checkentry(const char *tablename, | 45 | static int checkentry(const char *tablename, |
45 | const void *ip, | 46 | const void *ip, |
47 | const struct xt_match *match, | ||
46 | void *matchinfo, | 48 | void *matchinfo, |
47 | unsigned int matchsize, | 49 | unsigned int matchsize, |
48 | unsigned int hook_mask) | 50 | unsigned int hook_mask) |
@@ -50,9 +52,6 @@ static int checkentry(const char *tablename, | |||
50 | struct xt_string_info *conf = matchinfo; | 52 | struct xt_string_info *conf = matchinfo; |
51 | struct ts_config *ts_conf; | 53 | struct ts_config *ts_conf; |
52 | 54 | ||
53 | if (matchsize != XT_ALIGN(sizeof(struct xt_string_info))) | ||
54 | return 0; | ||
55 | |||
56 | /* Damn, can't handle this case properly with iptables... */ | 55 | /* Damn, can't handle this case properly with iptables... */ |
57 | if (conf->from_offset > conf->to_offset) | 56 | if (conf->from_offset > conf->to_offset) |
58 | return 0; | 57 | return 0; |
@@ -67,7 +66,8 @@ static int checkentry(const char *tablename, | |||
67 | return 1; | 66 | return 1; |
68 | } | 67 | } |
69 | 68 | ||
70 | static void destroy(void *matchinfo, unsigned int matchsize) | 69 | static void destroy(const struct xt_match *match, void *matchinfo, |
70 | unsigned int matchsize) | ||
71 | { | 71 | { |
72 | textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config); | 72 | textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config); |
73 | } | 73 | } |
@@ -75,15 +75,19 @@ static void destroy(void *matchinfo, unsigned int matchsize) | |||
75 | static struct xt_match string_match = { | 75 | static struct xt_match string_match = { |
76 | .name = "string", | 76 | .name = "string", |
77 | .match = match, | 77 | .match = match, |
78 | .matchsize = sizeof(struct xt_string_info), | ||
78 | .checkentry = checkentry, | 79 | .checkentry = checkentry, |
79 | .destroy = destroy, | 80 | .destroy = destroy, |
81 | .family = AF_INET, | ||
80 | .me = THIS_MODULE | 82 | .me = THIS_MODULE |
81 | }; | 83 | }; |
82 | static struct xt_match string6_match = { | 84 | static struct xt_match string6_match = { |
83 | .name = "string", | 85 | .name = "string", |
84 | .match = match, | 86 | .match = match, |
87 | .matchsize = sizeof(struct xt_string_info), | ||
85 | .checkentry = checkentry, | 88 | .checkentry = checkentry, |
86 | .destroy = destroy, | 89 | .destroy = destroy, |
90 | .family = AF_INET6, | ||
87 | .me = THIS_MODULE | 91 | .me = THIS_MODULE |
88 | }; | 92 | }; |
89 | 93 | ||
@@ -91,20 +95,20 @@ static int __init init(void) | |||
91 | { | 95 | { |
92 | int ret; | 96 | int ret; |
93 | 97 | ||
94 | ret = xt_register_match(AF_INET, &string_match); | 98 | ret = xt_register_match(&string_match); |
95 | if (ret) | 99 | if (ret) |
96 | return ret; | 100 | return ret; |
97 | ret = xt_register_match(AF_INET6, &string6_match); | 101 | ret = xt_register_match(&string6_match); |
98 | if (ret) | 102 | if (ret) |
99 | xt_unregister_match(AF_INET, &string_match); | 103 | xt_unregister_match(&string_match); |
100 | 104 | ||
101 | return ret; | 105 | return ret; |
102 | } | 106 | } |
103 | 107 | ||
104 | static void __exit fini(void) | 108 | static void __exit fini(void) |
105 | { | 109 | { |
106 | xt_unregister_match(AF_INET, &string_match); | 110 | xt_unregister_match(&string_match); |
107 | xt_unregister_match(AF_INET6, &string6_match); | 111 | xt_unregister_match(&string6_match); |
108 | } | 112 | } |
109 | 113 | ||
110 | module_init(init); | 114 | module_init(init); |
diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c index acf7f533e9f1..70a8858ae3f1 100644 --- a/net/netfilter/xt_tcpmss.c +++ b/net/netfilter/xt_tcpmss.c | |||
@@ -81,6 +81,7 @@ static int | |||
81 | match(const struct sk_buff *skb, | 81 | match(const struct sk_buff *skb, |
82 | const struct net_device *in, | 82 | const struct net_device *in, |
83 | const struct net_device *out, | 83 | const struct net_device *out, |
84 | const struct xt_match *match, | ||
84 | const void *matchinfo, | 85 | const void *matchinfo, |
85 | int offset, | 86 | int offset, |
86 | unsigned int protoff, | 87 | unsigned int protoff, |
@@ -92,58 +93,21 @@ match(const struct sk_buff *skb, | |||
92 | info->invert, hotdrop); | 93 | info->invert, hotdrop); |
93 | } | 94 | } |
94 | 95 | ||
95 | static int | ||
96 | checkentry(const char *tablename, | ||
97 | const void *ipinfo, | ||
98 | void *matchinfo, | ||
99 | unsigned int matchsize, | ||
100 | unsigned int hook_mask) | ||
101 | { | ||
102 | const struct ipt_ip *ip = ipinfo; | ||
103 | if (matchsize != XT_ALIGN(sizeof(struct xt_tcpmss_match_info))) | ||
104 | return 0; | ||
105 | |||
106 | /* Must specify -p tcp */ | ||
107 | if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) { | ||
108 | printk("tcpmss: Only works on TCP packets\n"); | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | return 1; | ||
113 | } | ||
114 | |||
115 | static int | ||
116 | checkentry6(const char *tablename, | ||
117 | const void *ipinfo, | ||
118 | void *matchinfo, | ||
119 | unsigned int matchsize, | ||
120 | unsigned int hook_mask) | ||
121 | { | ||
122 | const struct ip6t_ip6 *ip = ipinfo; | ||
123 | |||
124 | if (matchsize != XT_ALIGN(sizeof(struct xt_tcpmss_match_info))) | ||
125 | return 0; | ||
126 | |||
127 | /* Must specify -p tcp */ | ||
128 | if (ip->proto != IPPROTO_TCP || (ip->invflags & XT_INV_PROTO)) { | ||
129 | printk("tcpmss: Only works on TCP packets\n"); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | return 1; | ||
134 | } | ||
135 | |||
136 | static struct xt_match tcpmss_match = { | 96 | static struct xt_match tcpmss_match = { |
137 | .name = "tcpmss", | 97 | .name = "tcpmss", |
138 | .match = &match, | 98 | .match = match, |
139 | .checkentry = &checkentry, | 99 | .matchsize = sizeof(struct xt_tcpmss_match_info), |
100 | .proto = IPPROTO_TCP, | ||
101 | .family = AF_INET, | ||
140 | .me = THIS_MODULE, | 102 | .me = THIS_MODULE, |
141 | }; | 103 | }; |
142 | 104 | ||
143 | static struct xt_match tcpmss6_match = { | 105 | static struct xt_match tcpmss6_match = { |
144 | .name = "tcpmss", | 106 | .name = "tcpmss", |
145 | .match = &match, | 107 | .match = match, |
146 | .checkentry = &checkentry6, | 108 | .matchsize = sizeof(struct xt_tcpmss_match_info), |
109 | .proto = IPPROTO_TCP, | ||
110 | .family = AF_INET6, | ||
147 | .me = THIS_MODULE, | 111 | .me = THIS_MODULE, |
148 | }; | 112 | }; |
149 | 113 | ||
@@ -151,21 +115,21 @@ static struct xt_match tcpmss6_match = { | |||
151 | static int __init init(void) | 115 | static int __init init(void) |
152 | { | 116 | { |
153 | int ret; | 117 | int ret; |
154 | ret = xt_register_match(AF_INET, &tcpmss_match); | 118 | ret = xt_register_match(&tcpmss_match); |
155 | if (ret) | 119 | if (ret) |
156 | return ret; | 120 | return ret; |
157 | 121 | ||
158 | ret = xt_register_match(AF_INET6, &tcpmss6_match); | 122 | ret = xt_register_match(&tcpmss6_match); |
159 | if (ret) | 123 | if (ret) |
160 | xt_unregister_match(AF_INET, &tcpmss_match); | 124 | xt_unregister_match(&tcpmss_match); |
161 | 125 | ||
162 | return ret; | 126 | return ret; |
163 | } | 127 | } |
164 | 128 | ||
165 | static void __exit fini(void) | 129 | static void __exit fini(void) |
166 | { | 130 | { |
167 | xt_unregister_match(AF_INET6, &tcpmss6_match); | 131 | xt_unregister_match(&tcpmss6_match); |
168 | xt_unregister_match(AF_INET, &tcpmss_match); | 132 | xt_unregister_match(&tcpmss_match); |
169 | } | 133 | } |
170 | 134 | ||
171 | module_init(init); | 135 | module_init(init); |
diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c index 669c8113cc60..14a990eb666a 100644 --- a/net/netfilter/xt_tcpudp.c +++ b/net/netfilter/xt_tcpudp.c | |||
@@ -74,6 +74,7 @@ static int | |||
74 | tcp_match(const struct sk_buff *skb, | 74 | tcp_match(const struct sk_buff *skb, |
75 | const struct net_device *in, | 75 | const struct net_device *in, |
76 | const struct net_device *out, | 76 | const struct net_device *out, |
77 | const struct xt_match *match, | ||
77 | const void *matchinfo, | 78 | const void *matchinfo, |
78 | int offset, | 79 | int offset, |
79 | unsigned int protoff, | 80 | unsigned int protoff, |
@@ -138,43 +139,22 @@ tcp_match(const struct sk_buff *skb, | |||
138 | static int | 139 | static int |
139 | tcp_checkentry(const char *tablename, | 140 | tcp_checkentry(const char *tablename, |
140 | const void *info, | 141 | const void *info, |
142 | const struct xt_match *match, | ||
141 | void *matchinfo, | 143 | void *matchinfo, |
142 | unsigned int matchsize, | 144 | unsigned int matchsize, |
143 | unsigned int hook_mask) | 145 | unsigned int hook_mask) |
144 | { | 146 | { |
145 | const struct ipt_ip *ip = info; | ||
146 | const struct xt_tcp *tcpinfo = matchinfo; | 147 | const struct xt_tcp *tcpinfo = matchinfo; |
147 | 148 | ||
148 | /* Must specify proto == TCP, and no unknown invflags */ | 149 | /* Must specify no unknown invflags */ |
149 | return ip->proto == IPPROTO_TCP | 150 | return !(tcpinfo->invflags & ~XT_TCP_INV_MASK); |
150 | && !(ip->invflags & XT_INV_PROTO) | ||
151 | && matchsize == XT_ALIGN(sizeof(struct xt_tcp)) | ||
152 | && !(tcpinfo->invflags & ~XT_TCP_INV_MASK); | ||
153 | } | 151 | } |
154 | 152 | ||
155 | /* Called when user tries to insert an entry of this type. */ | ||
156 | static int | ||
157 | tcp6_checkentry(const char *tablename, | ||
158 | const void *entry, | ||
159 | void *matchinfo, | ||
160 | unsigned int matchsize, | ||
161 | unsigned int hook_mask) | ||
162 | { | ||
163 | const struct ip6t_ip6 *ipv6 = entry; | ||
164 | const struct xt_tcp *tcpinfo = matchinfo; | ||
165 | |||
166 | /* Must specify proto == TCP, and no unknown invflags */ | ||
167 | return ipv6->proto == IPPROTO_TCP | ||
168 | && !(ipv6->invflags & XT_INV_PROTO) | ||
169 | && matchsize == XT_ALIGN(sizeof(struct xt_tcp)) | ||
170 | && !(tcpinfo->invflags & ~XT_TCP_INV_MASK); | ||
171 | } | ||
172 | |||
173 | |||
174 | static int | 153 | static int |
175 | udp_match(const struct sk_buff *skb, | 154 | udp_match(const struct sk_buff *skb, |
176 | const struct net_device *in, | 155 | const struct net_device *in, |
177 | const struct net_device *out, | 156 | const struct net_device *out, |
157 | const struct xt_match *match, | ||
178 | const void *matchinfo, | 158 | const void *matchinfo, |
179 | int offset, | 159 | int offset, |
180 | unsigned int protoff, | 160 | unsigned int protoff, |
@@ -208,126 +188,92 @@ udp_match(const struct sk_buff *skb, | |||
208 | static int | 188 | static int |
209 | udp_checkentry(const char *tablename, | 189 | udp_checkentry(const char *tablename, |
210 | const void *info, | 190 | const void *info, |
191 | const struct xt_match *match, | ||
211 | void *matchinfo, | 192 | void *matchinfo, |
212 | unsigned int matchinfosize, | 193 | unsigned int matchsize, |
213 | unsigned int hook_mask) | ||
214 | { | ||
215 | const struct ipt_ip *ip = info; | ||
216 | const struct xt_udp *udpinfo = matchinfo; | ||
217 | |||
218 | /* Must specify proto == UDP, and no unknown invflags */ | ||
219 | if (ip->proto != IPPROTO_UDP || (ip->invflags & XT_INV_PROTO)) { | ||
220 | duprintf("ipt_udp: Protocol %u != %u\n", ip->proto, | ||
221 | IPPROTO_UDP); | ||
222 | return 0; | ||
223 | } | ||
224 | if (matchinfosize != XT_ALIGN(sizeof(struct xt_udp))) { | ||
225 | duprintf("ipt_udp: matchsize %u != %u\n", | ||
226 | matchinfosize, XT_ALIGN(sizeof(struct xt_udp))); | ||
227 | return 0; | ||
228 | } | ||
229 | if (udpinfo->invflags & ~XT_UDP_INV_MASK) { | ||
230 | duprintf("ipt_udp: unknown flags %X\n", | ||
231 | udpinfo->invflags); | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | return 1; | ||
236 | } | ||
237 | |||
238 | /* Called when user tries to insert an entry of this type. */ | ||
239 | static int | ||
240 | udp6_checkentry(const char *tablename, | ||
241 | const void *entry, | ||
242 | void *matchinfo, | ||
243 | unsigned int matchinfosize, | ||
244 | unsigned int hook_mask) | 194 | unsigned int hook_mask) |
245 | { | 195 | { |
246 | const struct ip6t_ip6 *ipv6 = entry; | 196 | const struct xt_tcp *udpinfo = matchinfo; |
247 | const struct xt_udp *udpinfo = matchinfo; | ||
248 | 197 | ||
249 | /* Must specify proto == UDP, and no unknown invflags */ | 198 | /* Must specify no unknown invflags */ |
250 | if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & XT_INV_PROTO)) { | 199 | return !(udpinfo->invflags & ~XT_UDP_INV_MASK); |
251 | duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto, | ||
252 | IPPROTO_UDP); | ||
253 | return 0; | ||
254 | } | ||
255 | if (matchinfosize != XT_ALIGN(sizeof(struct xt_udp))) { | ||
256 | duprintf("ip6t_udp: matchsize %u != %u\n", | ||
257 | matchinfosize, XT_ALIGN(sizeof(struct xt_udp))); | ||
258 | return 0; | ||
259 | } | ||
260 | if (udpinfo->invflags & ~XT_UDP_INV_MASK) { | ||
261 | duprintf("ip6t_udp: unknown flags %X\n", | ||
262 | udpinfo->invflags); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | return 1; | ||
267 | } | 200 | } |
268 | 201 | ||
269 | static struct xt_match tcp_matchstruct = { | 202 | static struct xt_match tcp_matchstruct = { |
270 | .name = "tcp", | 203 | .name = "tcp", |
271 | .match = &tcp_match, | 204 | .match = tcp_match, |
272 | .checkentry = &tcp_checkentry, | 205 | .matchsize = sizeof(struct xt_tcp), |
206 | .proto = IPPROTO_TCP, | ||
207 | .family = AF_INET, | ||
208 | .checkentry = tcp_checkentry, | ||
273 | .me = THIS_MODULE, | 209 | .me = THIS_MODULE, |
274 | }; | 210 | }; |
211 | |||
275 | static struct xt_match tcp6_matchstruct = { | 212 | static struct xt_match tcp6_matchstruct = { |
276 | .name = "tcp", | 213 | .name = "tcp", |
277 | .match = &tcp_match, | 214 | .match = tcp_match, |
278 | .checkentry = &tcp6_checkentry, | 215 | .matchsize = sizeof(struct xt_tcp), |
216 | .proto = IPPROTO_TCP, | ||
217 | .family = AF_INET6, | ||
218 | .checkentry = tcp_checkentry, | ||
279 | .me = THIS_MODULE, | 219 | .me = THIS_MODULE, |
280 | }; | 220 | }; |
281 | 221 | ||
282 | static struct xt_match udp_matchstruct = { | 222 | static struct xt_match udp_matchstruct = { |
283 | .name = "udp", | 223 | .name = "udp", |
284 | .match = &udp_match, | 224 | .match = udp_match, |
285 | .checkentry = &udp_checkentry, | 225 | .matchsize = sizeof(struct xt_udp), |
226 | .proto = IPPROTO_UDP, | ||
227 | .family = AF_INET, | ||
228 | .checkentry = udp_checkentry, | ||
286 | .me = THIS_MODULE, | 229 | .me = THIS_MODULE, |
287 | }; | 230 | }; |
288 | static struct xt_match udp6_matchstruct = { | 231 | static struct xt_match udp6_matchstruct = { |
289 | .name = "udp", | 232 | .name = "udp", |
290 | .match = &udp_match, | 233 | .match = udp_match, |
291 | .checkentry = &udp6_checkentry, | 234 | .matchsize = sizeof(struct xt_udp), |
235 | .proto = IPPROTO_UDP, | ||
236 | .family = AF_INET6, | ||
237 | .checkentry = udp_checkentry, | ||
292 | .me = THIS_MODULE, | 238 | .me = THIS_MODULE, |
293 | }; | 239 | }; |
294 | 240 | ||
295 | static int __init init(void) | 241 | static int __init init(void) |
296 | { | 242 | { |
297 | int ret; | 243 | int ret; |
298 | ret = xt_register_match(AF_INET, &tcp_matchstruct); | 244 | ret = xt_register_match(&tcp_matchstruct); |
299 | if (ret) | 245 | if (ret) |
300 | return ret; | 246 | return ret; |
301 | 247 | ||
302 | ret = xt_register_match(AF_INET6, &tcp6_matchstruct); | 248 | ret = xt_register_match(&tcp6_matchstruct); |
303 | if (ret) | 249 | if (ret) |
304 | goto out_unreg_tcp; | 250 | goto out_unreg_tcp; |
305 | 251 | ||
306 | ret = xt_register_match(AF_INET, &udp_matchstruct); | 252 | ret = xt_register_match(&udp_matchstruct); |
307 | if (ret) | 253 | if (ret) |
308 | goto out_unreg_tcp6; | 254 | goto out_unreg_tcp6; |
309 | 255 | ||
310 | ret = xt_register_match(AF_INET6, &udp6_matchstruct); | 256 | ret = xt_register_match(&udp6_matchstruct); |
311 | if (ret) | 257 | if (ret) |
312 | goto out_unreg_udp; | 258 | goto out_unreg_udp; |
313 | 259 | ||
314 | return ret; | 260 | return ret; |
315 | 261 | ||
316 | out_unreg_udp: | 262 | out_unreg_udp: |
317 | xt_unregister_match(AF_INET, &tcp_matchstruct); | 263 | xt_unregister_match(&tcp_matchstruct); |
318 | out_unreg_tcp6: | 264 | out_unreg_tcp6: |
319 | xt_unregister_match(AF_INET6, &tcp6_matchstruct); | 265 | xt_unregister_match(&tcp6_matchstruct); |
320 | out_unreg_tcp: | 266 | out_unreg_tcp: |
321 | xt_unregister_match(AF_INET, &tcp_matchstruct); | 267 | xt_unregister_match(&tcp_matchstruct); |
322 | return ret; | 268 | return ret; |
323 | } | 269 | } |
324 | 270 | ||
325 | static void __exit fini(void) | 271 | static void __exit fini(void) |
326 | { | 272 | { |
327 | xt_unregister_match(AF_INET6, &udp6_matchstruct); | 273 | xt_unregister_match(&udp6_matchstruct); |
328 | xt_unregister_match(AF_INET, &udp_matchstruct); | 274 | xt_unregister_match(&udp_matchstruct); |
329 | xt_unregister_match(AF_INET6, &tcp6_matchstruct); | 275 | xt_unregister_match(&tcp6_matchstruct); |
330 | xt_unregister_match(AF_INET, &tcp_matchstruct); | 276 | xt_unregister_match(&tcp_matchstruct); |
331 | } | 277 | } |
332 | 278 | ||
333 | module_init(init); | 279 | module_init(init); |
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 59dc7d140600..d00a9034cb5f 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -106,6 +106,7 @@ struct nl_pid_hash { | |||
106 | struct netlink_table { | 106 | struct netlink_table { |
107 | struct nl_pid_hash hash; | 107 | struct nl_pid_hash hash; |
108 | struct hlist_head mc_list; | 108 | struct hlist_head mc_list; |
109 | unsigned long *listeners; | ||
109 | unsigned int nl_nonroot; | 110 | unsigned int nl_nonroot; |
110 | unsigned int groups; | 111 | unsigned int groups; |
111 | struct module *module; | 112 | struct module *module; |
@@ -296,6 +297,24 @@ static inline int nl_pid_hash_dilute(struct nl_pid_hash *hash, int len) | |||
296 | 297 | ||
297 | static const struct proto_ops netlink_ops; | 298 | static const struct proto_ops netlink_ops; |
298 | 299 | ||
300 | static void | ||
301 | netlink_update_listeners(struct sock *sk) | ||
302 | { | ||
303 | struct netlink_table *tbl = &nl_table[sk->sk_protocol]; | ||
304 | struct hlist_node *node; | ||
305 | unsigned long mask; | ||
306 | unsigned int i; | ||
307 | |||
308 | for (i = 0; i < NLGRPSZ(tbl->groups)/sizeof(unsigned long); i++) { | ||
309 | mask = 0; | ||
310 | sk_for_each_bound(sk, node, &tbl->mc_list) | ||
311 | mask |= nlk_sk(sk)->groups[i]; | ||
312 | tbl->listeners[i] = mask; | ||
313 | } | ||
314 | /* this function is only called with the netlink table "grabbed", which | ||
315 | * makes sure updates are visible before bind or setsockopt return. */ | ||
316 | } | ||
317 | |||
299 | static int netlink_insert(struct sock *sk, u32 pid) | 318 | static int netlink_insert(struct sock *sk, u32 pid) |
300 | { | 319 | { |
301 | struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; | 320 | struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; |
@@ -456,12 +475,14 @@ static int netlink_release(struct socket *sock) | |||
456 | if (nlk->module) | 475 | if (nlk->module) |
457 | module_put(nlk->module); | 476 | module_put(nlk->module); |
458 | 477 | ||
478 | netlink_table_grab(); | ||
459 | if (nlk->flags & NETLINK_KERNEL_SOCKET) { | 479 | if (nlk->flags & NETLINK_KERNEL_SOCKET) { |
460 | netlink_table_grab(); | 480 | kfree(nl_table[sk->sk_protocol].listeners); |
461 | nl_table[sk->sk_protocol].module = NULL; | 481 | nl_table[sk->sk_protocol].module = NULL; |
462 | nl_table[sk->sk_protocol].registered = 0; | 482 | nl_table[sk->sk_protocol].registered = 0; |
463 | netlink_table_ungrab(); | 483 | } else if (nlk->subscriptions) |
464 | } | 484 | netlink_update_listeners(sk); |
485 | netlink_table_ungrab(); | ||
465 | 486 | ||
466 | kfree(nlk->groups); | 487 | kfree(nlk->groups); |
467 | nlk->groups = NULL; | 488 | nlk->groups = NULL; |
@@ -589,6 +610,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len | |||
589 | hweight32(nladdr->nl_groups) - | 610 | hweight32(nladdr->nl_groups) - |
590 | hweight32(nlk->groups[0])); | 611 | hweight32(nlk->groups[0])); |
591 | nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups; | 612 | nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups; |
613 | netlink_update_listeners(sk); | ||
592 | netlink_table_ungrab(); | 614 | netlink_table_ungrab(); |
593 | 615 | ||
594 | return 0; | 616 | return 0; |
@@ -807,6 +829,17 @@ retry: | |||
807 | return netlink_sendskb(sk, skb, ssk->sk_protocol); | 829 | return netlink_sendskb(sk, skb, ssk->sk_protocol); |
808 | } | 830 | } |
809 | 831 | ||
832 | int netlink_has_listeners(struct sock *sk, unsigned int group) | ||
833 | { | ||
834 | int res = 0; | ||
835 | |||
836 | BUG_ON(!(nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET)); | ||
837 | if (group - 1 < nl_table[sk->sk_protocol].groups) | ||
838 | res = test_bit(group - 1, nl_table[sk->sk_protocol].listeners); | ||
839 | return res; | ||
840 | } | ||
841 | EXPORT_SYMBOL_GPL(netlink_has_listeners); | ||
842 | |||
810 | static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb) | 843 | static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb) |
811 | { | 844 | { |
812 | struct netlink_sock *nlk = nlk_sk(sk); | 845 | struct netlink_sock *nlk = nlk_sk(sk); |
@@ -1011,6 +1044,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, | |||
1011 | else | 1044 | else |
1012 | __clear_bit(val - 1, nlk->groups); | 1045 | __clear_bit(val - 1, nlk->groups); |
1013 | netlink_update_subscriptions(sk, subscriptions); | 1046 | netlink_update_subscriptions(sk, subscriptions); |
1047 | netlink_update_listeners(sk); | ||
1014 | netlink_table_ungrab(); | 1048 | netlink_table_ungrab(); |
1015 | err = 0; | 1049 | err = 0; |
1016 | break; | 1050 | break; |
@@ -1237,6 +1271,7 @@ netlink_kernel_create(int unit, unsigned int groups, | |||
1237 | struct socket *sock; | 1271 | struct socket *sock; |
1238 | struct sock *sk; | 1272 | struct sock *sk; |
1239 | struct netlink_sock *nlk; | 1273 | struct netlink_sock *nlk; |
1274 | unsigned long *listeners = NULL; | ||
1240 | 1275 | ||
1241 | if (!nl_table) | 1276 | if (!nl_table) |
1242 | return NULL; | 1277 | return NULL; |
@@ -1250,6 +1285,13 @@ netlink_kernel_create(int unit, unsigned int groups, | |||
1250 | if (__netlink_create(sock, unit) < 0) | 1285 | if (__netlink_create(sock, unit) < 0) |
1251 | goto out_sock_release; | 1286 | goto out_sock_release; |
1252 | 1287 | ||
1288 | if (groups < 32) | ||
1289 | groups = 32; | ||
1290 | |||
1291 | listeners = kzalloc(NLGRPSZ(groups), GFP_KERNEL); | ||
1292 | if (!listeners) | ||
1293 | goto out_sock_release; | ||
1294 | |||
1253 | sk = sock->sk; | 1295 | sk = sock->sk; |
1254 | sk->sk_data_ready = netlink_data_ready; | 1296 | sk->sk_data_ready = netlink_data_ready; |
1255 | if (input) | 1297 | if (input) |
@@ -1262,7 +1304,8 @@ netlink_kernel_create(int unit, unsigned int groups, | |||
1262 | nlk->flags |= NETLINK_KERNEL_SOCKET; | 1304 | nlk->flags |= NETLINK_KERNEL_SOCKET; |
1263 | 1305 | ||
1264 | netlink_table_grab(); | 1306 | netlink_table_grab(); |
1265 | nl_table[unit].groups = groups < 32 ? 32 : groups; | 1307 | nl_table[unit].groups = groups; |
1308 | nl_table[unit].listeners = listeners; | ||
1266 | nl_table[unit].module = module; | 1309 | nl_table[unit].module = module; |
1267 | nl_table[unit].registered = 1; | 1310 | nl_table[unit].registered = 1; |
1268 | netlink_table_ungrab(); | 1311 | netlink_table_ungrab(); |
@@ -1270,6 +1313,7 @@ netlink_kernel_create(int unit, unsigned int groups, | |||
1270 | return sk; | 1313 | return sk; |
1271 | 1314 | ||
1272 | out_sock_release: | 1315 | out_sock_release: |
1316 | kfree(listeners); | ||
1273 | sock_release(sock); | 1317 | sock_release(sock); |
1274 | return NULL; | 1318 | return NULL; |
1275 | } | 1319 | } |
diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 778b1e5a4b50..13eeee582886 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig | |||
@@ -434,7 +434,6 @@ config NET_EMATCH_TEXT | |||
434 | 434 | ||
435 | config NET_CLS_ACT | 435 | config NET_CLS_ACT |
436 | bool "Actions" | 436 | bool "Actions" |
437 | depends on EXPERIMENTAL | ||
438 | select NET_ESTIMATOR | 437 | select NET_ESTIMATOR |
439 | ---help--- | 438 | ---help--- |
440 | Say Y here if you want to use traffic control actions. Actions | 439 | Say Y here if you want to use traffic control actions. Actions |
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index 39a22a3ffe78..6056d20ef429 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c | |||
@@ -70,7 +70,8 @@ ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook) | |||
70 | t->u.kernel.target = target; | 70 | t->u.kernel.target = target; |
71 | 71 | ||
72 | if (t->u.kernel.target->checkentry | 72 | if (t->u.kernel.target->checkentry |
73 | && !t->u.kernel.target->checkentry(table, NULL, t->data, | 73 | && !t->u.kernel.target->checkentry(table, NULL, |
74 | t->u.kernel.target, t->data, | ||
74 | t->u.target_size - sizeof(*t), | 75 | t->u.target_size - sizeof(*t), |
75 | hook)) { | 76 | hook)) { |
76 | DPRINTK("ipt_init_target: check failed for `%s'.\n", | 77 | DPRINTK("ipt_init_target: check failed for `%s'.\n", |
@@ -86,7 +87,7 @@ static void | |||
86 | ipt_destroy_target(struct ipt_entry_target *t) | 87 | ipt_destroy_target(struct ipt_entry_target *t) |
87 | { | 88 | { |
88 | if (t->u.kernel.target->destroy) | 89 | if (t->u.kernel.target->destroy) |
89 | t->u.kernel.target->destroy(t->data, | 90 | t->u.kernel.target->destroy(t->u.kernel.target, t->data, |
90 | t->u.target_size - sizeof(*t)); | 91 | t->u.target_size - sizeof(*t)); |
91 | module_put(t->u.kernel.target->me); | 92 | module_put(t->u.kernel.target->me); |
92 | } | 93 | } |
@@ -224,8 +225,9 @@ tcf_ipt(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) | |||
224 | /* iptables targets take a double skb pointer in case the skb | 225 | /* iptables targets take a double skb pointer in case the skb |
225 | * needs to be replaced. We don't own the skb, so this must not | 226 | * needs to be replaced. We don't own the skb, so this must not |
226 | * happen. The pskb_expand_head above should make sure of this */ | 227 | * happen. The pskb_expand_head above should make sure of this */ |
227 | ret = p->t->u.kernel.target->target(&skb, skb->dev, NULL, | 228 | ret = p->t->u.kernel.target->target(&skb, skb->dev, NULL, p->hook, |
228 | p->hook, p->t->data, NULL); | 229 | p->t->u.kernel.target, p->t->data, |
230 | NULL); | ||
229 | switch (ret) { | 231 | switch (ret) { |
230 | case NF_ACCEPT: | 232 | case NF_ACCEPT: |
231 | result = TC_ACT_OK; | 233 | result = TC_ACT_OK; |
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 2b670479dde1..78e052591fa9 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c | |||
@@ -347,8 +347,7 @@ static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n) | |||
347 | if (n->ht_down) | 347 | if (n->ht_down) |
348 | n->ht_down->refcnt--; | 348 | n->ht_down->refcnt--; |
349 | #ifdef CONFIG_CLS_U32_PERF | 349 | #ifdef CONFIG_CLS_U32_PERF |
350 | if (n) | 350 | kfree(n->pf); |
351 | kfree(n->pf); | ||
352 | #endif | 351 | #endif |
353 | kfree(n); | 352 | kfree(n); |
354 | return 0; | 353 | return 0; |
@@ -680,8 +679,7 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, | |||
680 | return 0; | 679 | return 0; |
681 | } | 680 | } |
682 | #ifdef CONFIG_CLS_U32_PERF | 681 | #ifdef CONFIG_CLS_U32_PERF |
683 | if (n) | 682 | kfree(n->pf); |
684 | kfree(n->pf); | ||
685 | #endif | 683 | #endif |
686 | kfree(n); | 684 | kfree(n); |
687 | return err; | 685 | return err; |
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index 93ebce40acac..ac7cb60d1e25 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c | |||
@@ -638,6 +638,7 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl, | |||
638 | sch,p,flow,skb,tcm); | 638 | sch,p,flow,skb,tcm); |
639 | if (!find_flow(p,flow)) return -EINVAL; | 639 | if (!find_flow(p,flow)) return -EINVAL; |
640 | tcm->tcm_handle = flow->classid; | 640 | tcm->tcm_handle = flow->classid; |
641 | tcm->tcm_info = flow->q->handle; | ||
641 | rta = (struct rtattr *) b; | 642 | rta = (struct rtattr *) b; |
642 | RTA_PUT(skb,TCA_OPTIONS,0,NULL); | 643 | RTA_PUT(skb,TCA_OPTIONS,0,NULL); |
643 | RTA_PUT(skb,TCA_ATM_HDR,flow->hdr_len,flow->hdr); | 644 | RTA_PUT(skb,TCA_ATM_HDR,flow->hdr_len,flow->hdr); |
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index 13e0e7b3856b..f6320ca70493 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c | |||
@@ -438,6 +438,7 @@ static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl, | |||
438 | return -EINVAL; | 438 | return -EINVAL; |
439 | 439 | ||
440 | tcm->tcm_handle = TC_H_MAKE(TC_H_MAJ(sch->handle), cl-1); | 440 | tcm->tcm_handle = TC_H_MAKE(TC_H_MAJ(sch->handle), cl-1); |
441 | tcm->tcm_info = p->q->handle; | ||
441 | 442 | ||
442 | opts = RTA_NEST(skb, TCA_OPTIONS); | 443 | opts = RTA_NEST(skb, TCA_OPTIONS); |
443 | RTA_PUT_U8(skb,TCA_DSMARK_MASK, p->mask[cl-1]); | 444 | RTA_PUT_U8(skb,TCA_DSMARK_MASK, p->mask[cl-1]); |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 99ceb91f0150..31eb83717c26 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -234,7 +234,7 @@ static void dev_watchdog_down(struct net_device *dev) | |||
234 | { | 234 | { |
235 | spin_lock_bh(&dev->xmit_lock); | 235 | spin_lock_bh(&dev->xmit_lock); |
236 | if (del_timer(&dev->watchdog_timer)) | 236 | if (del_timer(&dev->watchdog_timer)) |
237 | __dev_put(dev); | 237 | dev_put(dev); |
238 | spin_unlock_bh(&dev->xmit_lock); | 238 | spin_unlock_bh(&dev->xmit_lock); |
239 | } | 239 | } |
240 | 240 | ||
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index ba5283204837..7228d30512c7 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c | |||
@@ -252,9 +252,9 @@ static int netem_requeue(struct sk_buff *skb, struct Qdisc *sch) | |||
252 | static unsigned int netem_drop(struct Qdisc* sch) | 252 | static unsigned int netem_drop(struct Qdisc* sch) |
253 | { | 253 | { |
254 | struct netem_sched_data *q = qdisc_priv(sch); | 254 | struct netem_sched_data *q = qdisc_priv(sch); |
255 | unsigned int len; | 255 | unsigned int len = 0; |
256 | 256 | ||
257 | if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) { | 257 | if (q->qdisc->ops->drop && (len = q->qdisc->ops->drop(q->qdisc)) != 0) { |
258 | sch->q.qlen--; | 258 | sch->q.qlen--; |
259 | sch->qstats.drops++; | 259 | sch->qstats.drops++; |
260 | } | 260 | } |
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 1641db33a994..3395ca7bcadf 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c | |||
@@ -165,7 +165,7 @@ static unsigned int prio_drop(struct Qdisc* sch) | |||
165 | 165 | ||
166 | for (prio = q->bands-1; prio >= 0; prio--) { | 166 | for (prio = q->bands-1; prio >= 0; prio--) { |
167 | qdisc = q->queues[prio]; | 167 | qdisc = q->queues[prio]; |
168 | if ((len = qdisc->ops->drop(qdisc)) != 0) { | 168 | if (qdisc->ops->drop && (len = qdisc->ops->drop(qdisc)) != 0) { |
169 | sch->q.qlen--; | 169 | sch->q.qlen--; |
170 | return len; | 170 | return len; |
171 | } | 171 | } |
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index dccfa44c2d71..2be563cba72b 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c | |||
@@ -44,6 +44,7 @@ struct red_sched_data | |||
44 | unsigned char flags; | 44 | unsigned char flags; |
45 | struct red_parms parms; | 45 | struct red_parms parms; |
46 | struct red_stats stats; | 46 | struct red_stats stats; |
47 | struct Qdisc *qdisc; | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | static inline int red_use_ecn(struct red_sched_data *q) | 50 | static inline int red_use_ecn(struct red_sched_data *q) |
@@ -59,8 +60,10 @@ static inline int red_use_harddrop(struct red_sched_data *q) | |||
59 | static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch) | 60 | static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch) |
60 | { | 61 | { |
61 | struct red_sched_data *q = qdisc_priv(sch); | 62 | struct red_sched_data *q = qdisc_priv(sch); |
63 | struct Qdisc *child = q->qdisc; | ||
64 | int ret; | ||
62 | 65 | ||
63 | q->parms.qavg = red_calc_qavg(&q->parms, sch->qstats.backlog); | 66 | q->parms.qavg = red_calc_qavg(&q->parms, child->qstats.backlog); |
64 | 67 | ||
65 | if (red_is_idling(&q->parms)) | 68 | if (red_is_idling(&q->parms)) |
66 | red_end_of_idle_period(&q->parms); | 69 | red_end_of_idle_period(&q->parms); |
@@ -91,11 +94,16 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc* sch) | |||
91 | break; | 94 | break; |
92 | } | 95 | } |
93 | 96 | ||
94 | if (sch->qstats.backlog + skb->len <= q->limit) | 97 | ret = child->enqueue(skb, child); |
95 | return qdisc_enqueue_tail(skb, sch); | 98 | if (likely(ret == NET_XMIT_SUCCESS)) { |
96 | 99 | sch->bstats.bytes += skb->len; | |
97 | q->stats.pdrop++; | 100 | sch->bstats.packets++; |
98 | return qdisc_drop(skb, sch); | 101 | sch->q.qlen++; |
102 | } else { | ||
103 | q->stats.pdrop++; | ||
104 | sch->qstats.drops++; | ||
105 | } | ||
106 | return ret; | ||
99 | 107 | ||
100 | congestion_drop: | 108 | congestion_drop: |
101 | qdisc_drop(skb, sch); | 109 | qdisc_drop(skb, sch); |
@@ -105,21 +113,30 @@ congestion_drop: | |||
105 | static int red_requeue(struct sk_buff *skb, struct Qdisc* sch) | 113 | static int red_requeue(struct sk_buff *skb, struct Qdisc* sch) |
106 | { | 114 | { |
107 | struct red_sched_data *q = qdisc_priv(sch); | 115 | struct red_sched_data *q = qdisc_priv(sch); |
116 | struct Qdisc *child = q->qdisc; | ||
117 | int ret; | ||
108 | 118 | ||
109 | if (red_is_idling(&q->parms)) | 119 | if (red_is_idling(&q->parms)) |
110 | red_end_of_idle_period(&q->parms); | 120 | red_end_of_idle_period(&q->parms); |
111 | 121 | ||
112 | return qdisc_requeue(skb, sch); | 122 | ret = child->ops->requeue(skb, child); |
123 | if (likely(ret == NET_XMIT_SUCCESS)) { | ||
124 | sch->qstats.requeues++; | ||
125 | sch->q.qlen++; | ||
126 | } | ||
127 | return ret; | ||
113 | } | 128 | } |
114 | 129 | ||
115 | static struct sk_buff * red_dequeue(struct Qdisc* sch) | 130 | static struct sk_buff * red_dequeue(struct Qdisc* sch) |
116 | { | 131 | { |
117 | struct sk_buff *skb; | 132 | struct sk_buff *skb; |
118 | struct red_sched_data *q = qdisc_priv(sch); | 133 | struct red_sched_data *q = qdisc_priv(sch); |
134 | struct Qdisc *child = q->qdisc; | ||
119 | 135 | ||
120 | skb = qdisc_dequeue_head(sch); | 136 | skb = child->dequeue(child); |
121 | 137 | if (skb) | |
122 | if (skb == NULL && !red_is_idling(&q->parms)) | 138 | sch->q.qlen--; |
139 | else if (!red_is_idling(&q->parms)) | ||
123 | red_start_of_idle_period(&q->parms); | 140 | red_start_of_idle_period(&q->parms); |
124 | 141 | ||
125 | return skb; | 142 | return skb; |
@@ -127,14 +144,14 @@ static struct sk_buff * red_dequeue(struct Qdisc* sch) | |||
127 | 144 | ||
128 | static unsigned int red_drop(struct Qdisc* sch) | 145 | static unsigned int red_drop(struct Qdisc* sch) |
129 | { | 146 | { |
130 | struct sk_buff *skb; | ||
131 | struct red_sched_data *q = qdisc_priv(sch); | 147 | struct red_sched_data *q = qdisc_priv(sch); |
148 | struct Qdisc *child = q->qdisc; | ||
149 | unsigned int len; | ||
132 | 150 | ||
133 | skb = qdisc_dequeue_tail(sch); | 151 | if (child->ops->drop && (len = child->ops->drop(child)) > 0) { |
134 | if (skb) { | ||
135 | unsigned int len = skb->len; | ||
136 | q->stats.other++; | 152 | q->stats.other++; |
137 | qdisc_drop(skb, sch); | 153 | sch->qstats.drops++; |
154 | sch->q.qlen--; | ||
138 | return len; | 155 | return len; |
139 | } | 156 | } |
140 | 157 | ||
@@ -148,15 +165,48 @@ static void red_reset(struct Qdisc* sch) | |||
148 | { | 165 | { |
149 | struct red_sched_data *q = qdisc_priv(sch); | 166 | struct red_sched_data *q = qdisc_priv(sch); |
150 | 167 | ||
151 | qdisc_reset_queue(sch); | 168 | qdisc_reset(q->qdisc); |
169 | sch->q.qlen = 0; | ||
152 | red_restart(&q->parms); | 170 | red_restart(&q->parms); |
153 | } | 171 | } |
154 | 172 | ||
173 | static void red_destroy(struct Qdisc *sch) | ||
174 | { | ||
175 | struct red_sched_data *q = qdisc_priv(sch); | ||
176 | qdisc_destroy(q->qdisc); | ||
177 | } | ||
178 | |||
179 | static struct Qdisc *red_create_dflt(struct net_device *dev, u32 limit) | ||
180 | { | ||
181 | struct Qdisc *q = qdisc_create_dflt(dev, &bfifo_qdisc_ops); | ||
182 | struct rtattr *rta; | ||
183 | int ret; | ||
184 | |||
185 | if (q) { | ||
186 | rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), | ||
187 | GFP_KERNEL); | ||
188 | if (rta) { | ||
189 | rta->rta_type = RTM_NEWQDISC; | ||
190 | rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt)); | ||
191 | ((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit; | ||
192 | |||
193 | ret = q->ops->change(q, rta); | ||
194 | kfree(rta); | ||
195 | |||
196 | if (ret == 0) | ||
197 | return q; | ||
198 | } | ||
199 | qdisc_destroy(q); | ||
200 | } | ||
201 | return NULL; | ||
202 | } | ||
203 | |||
155 | static int red_change(struct Qdisc *sch, struct rtattr *opt) | 204 | static int red_change(struct Qdisc *sch, struct rtattr *opt) |
156 | { | 205 | { |
157 | struct red_sched_data *q = qdisc_priv(sch); | 206 | struct red_sched_data *q = qdisc_priv(sch); |
158 | struct rtattr *tb[TCA_RED_MAX]; | 207 | struct rtattr *tb[TCA_RED_MAX]; |
159 | struct tc_red_qopt *ctl; | 208 | struct tc_red_qopt *ctl; |
209 | struct Qdisc *child = NULL; | ||
160 | 210 | ||
161 | if (opt == NULL || rtattr_parse_nested(tb, TCA_RED_MAX, opt)) | 211 | if (opt == NULL || rtattr_parse_nested(tb, TCA_RED_MAX, opt)) |
162 | return -EINVAL; | 212 | return -EINVAL; |
@@ -169,9 +219,17 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt) | |||
169 | 219 | ||
170 | ctl = RTA_DATA(tb[TCA_RED_PARMS-1]); | 220 | ctl = RTA_DATA(tb[TCA_RED_PARMS-1]); |
171 | 221 | ||
222 | if (ctl->limit > 0) { | ||
223 | child = red_create_dflt(sch->dev, ctl->limit); | ||
224 | if (child == NULL) | ||
225 | return -ENOMEM; | ||
226 | } | ||
227 | |||
172 | sch_tree_lock(sch); | 228 | sch_tree_lock(sch); |
173 | q->flags = ctl->flags; | 229 | q->flags = ctl->flags; |
174 | q->limit = ctl->limit; | 230 | q->limit = ctl->limit; |
231 | if (child) | ||
232 | qdisc_destroy(xchg(&q->qdisc, child)); | ||
175 | 233 | ||
176 | red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, | 234 | red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, |
177 | ctl->Plog, ctl->Scell_log, | 235 | ctl->Plog, ctl->Scell_log, |
@@ -186,6 +244,9 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt) | |||
186 | 244 | ||
187 | static int red_init(struct Qdisc* sch, struct rtattr *opt) | 245 | static int red_init(struct Qdisc* sch, struct rtattr *opt) |
188 | { | 246 | { |
247 | struct red_sched_data *q = qdisc_priv(sch); | ||
248 | |||
249 | q->qdisc = &noop_qdisc; | ||
189 | return red_change(sch, opt); | 250 | return red_change(sch, opt); |
190 | } | 251 | } |
191 | 252 | ||
@@ -224,15 +285,101 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) | |||
224 | return gnet_stats_copy_app(d, &st, sizeof(st)); | 285 | return gnet_stats_copy_app(d, &st, sizeof(st)); |
225 | } | 286 | } |
226 | 287 | ||
288 | static int red_dump_class(struct Qdisc *sch, unsigned long cl, | ||
289 | struct sk_buff *skb, struct tcmsg *tcm) | ||
290 | { | ||
291 | struct red_sched_data *q = qdisc_priv(sch); | ||
292 | |||
293 | if (cl != 1) | ||
294 | return -ENOENT; | ||
295 | tcm->tcm_handle |= TC_H_MIN(1); | ||
296 | tcm->tcm_info = q->qdisc->handle; | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int red_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, | ||
301 | struct Qdisc **old) | ||
302 | { | ||
303 | struct red_sched_data *q = qdisc_priv(sch); | ||
304 | |||
305 | if (new == NULL) | ||
306 | new = &noop_qdisc; | ||
307 | |||
308 | sch_tree_lock(sch); | ||
309 | *old = xchg(&q->qdisc, new); | ||
310 | qdisc_reset(*old); | ||
311 | sch->q.qlen = 0; | ||
312 | sch_tree_unlock(sch); | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static struct Qdisc *red_leaf(struct Qdisc *sch, unsigned long arg) | ||
317 | { | ||
318 | struct red_sched_data *q = qdisc_priv(sch); | ||
319 | return q->qdisc; | ||
320 | } | ||
321 | |||
322 | static unsigned long red_get(struct Qdisc *sch, u32 classid) | ||
323 | { | ||
324 | return 1; | ||
325 | } | ||
326 | |||
327 | static void red_put(struct Qdisc *sch, unsigned long arg) | ||
328 | { | ||
329 | return; | ||
330 | } | ||
331 | |||
332 | static int red_change_class(struct Qdisc *sch, u32 classid, u32 parentid, | ||
333 | struct rtattr **tca, unsigned long *arg) | ||
334 | { | ||
335 | return -ENOSYS; | ||
336 | } | ||
337 | |||
338 | static int red_delete(struct Qdisc *sch, unsigned long cl) | ||
339 | { | ||
340 | return -ENOSYS; | ||
341 | } | ||
342 | |||
343 | static void red_walk(struct Qdisc *sch, struct qdisc_walker *walker) | ||
344 | { | ||
345 | if (!walker->stop) { | ||
346 | if (walker->count >= walker->skip) | ||
347 | if (walker->fn(sch, 1, walker) < 0) { | ||
348 | walker->stop = 1; | ||
349 | return; | ||
350 | } | ||
351 | walker->count++; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | static struct tcf_proto **red_find_tcf(struct Qdisc *sch, unsigned long cl) | ||
356 | { | ||
357 | return NULL; | ||
358 | } | ||
359 | |||
360 | static struct Qdisc_class_ops red_class_ops = { | ||
361 | .graft = red_graft, | ||
362 | .leaf = red_leaf, | ||
363 | .get = red_get, | ||
364 | .put = red_put, | ||
365 | .change = red_change_class, | ||
366 | .delete = red_delete, | ||
367 | .walk = red_walk, | ||
368 | .tcf_chain = red_find_tcf, | ||
369 | .dump = red_dump_class, | ||
370 | }; | ||
371 | |||
227 | static struct Qdisc_ops red_qdisc_ops = { | 372 | static struct Qdisc_ops red_qdisc_ops = { |
228 | .id = "red", | 373 | .id = "red", |
229 | .priv_size = sizeof(struct red_sched_data), | 374 | .priv_size = sizeof(struct red_sched_data), |
375 | .cl_ops = &red_class_ops, | ||
230 | .enqueue = red_enqueue, | 376 | .enqueue = red_enqueue, |
231 | .dequeue = red_dequeue, | 377 | .dequeue = red_dequeue, |
232 | .requeue = red_requeue, | 378 | .requeue = red_requeue, |
233 | .drop = red_drop, | 379 | .drop = red_drop, |
234 | .init = red_init, | 380 | .init = red_init, |
235 | .reset = red_reset, | 381 | .reset = red_reset, |
382 | .destroy = red_destroy, | ||
236 | .change = red_change, | 383 | .change = red_change, |
237 | .dump = red_dump, | 384 | .dump = red_dump, |
238 | .dump_stats = red_dump_stats, | 385 | .dump_stats = red_dump_stats, |
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 86d8da0cbd02..e057768f68b4 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c | |||
@@ -232,6 +232,7 @@ static unsigned int sfq_drop(struct Qdisc *sch) | |||
232 | sfq_dec(q, x); | 232 | sfq_dec(q, x); |
233 | sch->q.qlen--; | 233 | sch->q.qlen--; |
234 | sch->qstats.drops++; | 234 | sch->qstats.drops++; |
235 | sch->qstats.backlog -= len; | ||
235 | return len; | 236 | return len; |
236 | } | 237 | } |
237 | 238 | ||
@@ -248,6 +249,7 @@ static unsigned int sfq_drop(struct Qdisc *sch) | |||
248 | sch->q.qlen--; | 249 | sch->q.qlen--; |
249 | q->ht[q->hash[d]] = SFQ_DEPTH; | 250 | q->ht[q->hash[d]] = SFQ_DEPTH; |
250 | sch->qstats.drops++; | 251 | sch->qstats.drops++; |
252 | sch->qstats.backlog -= len; | ||
251 | return len; | 253 | return len; |
252 | } | 254 | } |
253 | 255 | ||
@@ -266,6 +268,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch) | |||
266 | q->ht[hash] = x = q->dep[SFQ_DEPTH].next; | 268 | q->ht[hash] = x = q->dep[SFQ_DEPTH].next; |
267 | q->hash[x] = hash; | 269 | q->hash[x] = hash; |
268 | } | 270 | } |
271 | sch->qstats.backlog += skb->len; | ||
269 | __skb_queue_tail(&q->qs[x], skb); | 272 | __skb_queue_tail(&q->qs[x], skb); |
270 | sfq_inc(q, x); | 273 | sfq_inc(q, x); |
271 | if (q->qs[x].qlen == 1) { /* The flow is new */ | 274 | if (q->qs[x].qlen == 1) { /* The flow is new */ |
@@ -301,6 +304,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch) | |||
301 | q->ht[hash] = x = q->dep[SFQ_DEPTH].next; | 304 | q->ht[hash] = x = q->dep[SFQ_DEPTH].next; |
302 | q->hash[x] = hash; | 305 | q->hash[x] = hash; |
303 | } | 306 | } |
307 | sch->qstats.backlog += skb->len; | ||
304 | __skb_queue_head(&q->qs[x], skb); | 308 | __skb_queue_head(&q->qs[x], skb); |
305 | sfq_inc(q, x); | 309 | sfq_inc(q, x); |
306 | if (q->qs[x].qlen == 1) { /* The flow is new */ | 310 | if (q->qs[x].qlen == 1) { /* The flow is new */ |
@@ -344,6 +348,7 @@ sfq_dequeue(struct Qdisc* sch) | |||
344 | skb = __skb_dequeue(&q->qs[a]); | 348 | skb = __skb_dequeue(&q->qs[a]); |
345 | sfq_dec(q, a); | 349 | sfq_dec(q, a); |
346 | sch->q.qlen--; | 350 | sch->q.qlen--; |
351 | sch->qstats.backlog -= skb->len; | ||
347 | 352 | ||
348 | /* Is the slot empty? */ | 353 | /* Is the slot empty? */ |
349 | if (q->qs[a].qlen == 0) { | 354 | if (q->qs[a].qlen == 0) { |
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index cb9711ea8c6c..d8e03c74ca76 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c | |||
@@ -177,9 +177,9 @@ static int tbf_requeue(struct sk_buff *skb, struct Qdisc* sch) | |||
177 | static unsigned int tbf_drop(struct Qdisc* sch) | 177 | static unsigned int tbf_drop(struct Qdisc* sch) |
178 | { | 178 | { |
179 | struct tbf_sched_data *q = qdisc_priv(sch); | 179 | struct tbf_sched_data *q = qdisc_priv(sch); |
180 | unsigned int len; | 180 | unsigned int len = 0; |
181 | 181 | ||
182 | if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) { | 182 | if (q->qdisc->ops->drop && (len = q->qdisc->ops->drop(q->qdisc)) != 0) { |
183 | sch->q.qlen--; | 183 | sch->q.qlen--; |
184 | sch->qstats.drops++; | 184 | sch->qstats.drops++; |
185 | } | 185 | } |
@@ -341,13 +341,14 @@ static int tbf_change(struct Qdisc* sch, struct rtattr *opt) | |||
341 | if (max_size < 0) | 341 | if (max_size < 0) |
342 | goto done; | 342 | goto done; |
343 | 343 | ||
344 | if (q->qdisc == &noop_qdisc) { | 344 | if (qopt->limit > 0) { |
345 | if ((child = tbf_create_dflt_qdisc(sch->dev, qopt->limit)) == NULL) | 345 | if ((child = tbf_create_dflt_qdisc(sch->dev, qopt->limit)) == NULL) |
346 | goto done; | 346 | goto done; |
347 | } | 347 | } |
348 | 348 | ||
349 | sch_tree_lock(sch); | 349 | sch_tree_lock(sch); |
350 | if (child) q->qdisc = child; | 350 | if (child) |
351 | qdisc_destroy(xchg(&q->qdisc, child)); | ||
351 | q->limit = qopt->limit; | 352 | q->limit = qopt->limit; |
352 | q->mtu = qopt->mtu; | 353 | q->mtu = qopt->mtu; |
353 | q->max_size = max_size; | 354 | q->max_size = max_size; |
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 2e266129a764..c20d282fac06 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -861,23 +861,27 @@ static int sctp_inet6_supported_addrs(const struct sctp_sock *opt, | |||
861 | } | 861 | } |
862 | 862 | ||
863 | static const struct proto_ops inet6_seqpacket_ops = { | 863 | static const struct proto_ops inet6_seqpacket_ops = { |
864 | .family = PF_INET6, | 864 | .family = PF_INET6, |
865 | .owner = THIS_MODULE, | 865 | .owner = THIS_MODULE, |
866 | .release = inet6_release, | 866 | .release = inet6_release, |
867 | .bind = inet6_bind, | 867 | .bind = inet6_bind, |
868 | .connect = inet_dgram_connect, | 868 | .connect = inet_dgram_connect, |
869 | .socketpair = sock_no_socketpair, | 869 | .socketpair = sock_no_socketpair, |
870 | .accept = inet_accept, | 870 | .accept = inet_accept, |
871 | .getname = inet6_getname, | 871 | .getname = inet6_getname, |
872 | .poll = sctp_poll, | 872 | .poll = sctp_poll, |
873 | .ioctl = inet6_ioctl, | 873 | .ioctl = inet6_ioctl, |
874 | .listen = sctp_inet_listen, | 874 | .listen = sctp_inet_listen, |
875 | .shutdown = inet_shutdown, | 875 | .shutdown = inet_shutdown, |
876 | .setsockopt = sock_common_setsockopt, | 876 | .setsockopt = sock_common_setsockopt, |
877 | .getsockopt = sock_common_getsockopt, | 877 | .getsockopt = sock_common_getsockopt, |
878 | .sendmsg = inet_sendmsg, | 878 | .sendmsg = inet_sendmsg, |
879 | .recvmsg = sock_common_recvmsg, | 879 | .recvmsg = sock_common_recvmsg, |
880 | .mmap = sock_no_mmap, | 880 | .mmap = sock_no_mmap, |
881 | #ifdef CONFIG_COMPAT | ||
882 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
883 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
884 | #endif | ||
881 | }; | 885 | }; |
882 | 886 | ||
883 | static struct inet_protosw sctpv6_seqpacket_protosw = { | 887 | static struct inet_protosw sctpv6_seqpacket_protosw = { |
@@ -911,31 +915,35 @@ static struct inet6_protocol sctpv6_protocol = { | |||
911 | }; | 915 | }; |
912 | 916 | ||
913 | static struct sctp_af sctp_ipv6_specific = { | 917 | static struct sctp_af sctp_ipv6_specific = { |
914 | .sctp_xmit = sctp_v6_xmit, | 918 | .sa_family = AF_INET6, |
915 | .setsockopt = ipv6_setsockopt, | 919 | .sctp_xmit = sctp_v6_xmit, |
916 | .getsockopt = ipv6_getsockopt, | 920 | .setsockopt = ipv6_setsockopt, |
917 | .get_dst = sctp_v6_get_dst, | 921 | .getsockopt = ipv6_getsockopt, |
918 | .get_saddr = sctp_v6_get_saddr, | 922 | .get_dst = sctp_v6_get_dst, |
919 | .copy_addrlist = sctp_v6_copy_addrlist, | 923 | .get_saddr = sctp_v6_get_saddr, |
920 | .from_skb = sctp_v6_from_skb, | 924 | .copy_addrlist = sctp_v6_copy_addrlist, |
921 | .from_sk = sctp_v6_from_sk, | 925 | .from_skb = sctp_v6_from_skb, |
922 | .to_sk_saddr = sctp_v6_to_sk_saddr, | 926 | .from_sk = sctp_v6_from_sk, |
923 | .to_sk_daddr = sctp_v6_to_sk_daddr, | 927 | .to_sk_saddr = sctp_v6_to_sk_saddr, |
924 | .from_addr_param = sctp_v6_from_addr_param, | 928 | .to_sk_daddr = sctp_v6_to_sk_daddr, |
925 | .to_addr_param = sctp_v6_to_addr_param, | 929 | .from_addr_param = sctp_v6_from_addr_param, |
926 | .dst_saddr = sctp_v6_dst_saddr, | 930 | .to_addr_param = sctp_v6_to_addr_param, |
927 | .cmp_addr = sctp_v6_cmp_addr, | 931 | .dst_saddr = sctp_v6_dst_saddr, |
928 | .scope = sctp_v6_scope, | 932 | .cmp_addr = sctp_v6_cmp_addr, |
929 | .addr_valid = sctp_v6_addr_valid, | 933 | .scope = sctp_v6_scope, |
930 | .inaddr_any = sctp_v6_inaddr_any, | 934 | .addr_valid = sctp_v6_addr_valid, |
931 | .is_any = sctp_v6_is_any, | 935 | .inaddr_any = sctp_v6_inaddr_any, |
932 | .available = sctp_v6_available, | 936 | .is_any = sctp_v6_is_any, |
933 | .skb_iif = sctp_v6_skb_iif, | 937 | .available = sctp_v6_available, |
934 | .is_ce = sctp_v6_is_ce, | 938 | .skb_iif = sctp_v6_skb_iif, |
935 | .seq_dump_addr = sctp_v6_seq_dump_addr, | 939 | .is_ce = sctp_v6_is_ce, |
936 | .net_header_len = sizeof(struct ipv6hdr), | 940 | .seq_dump_addr = sctp_v6_seq_dump_addr, |
937 | .sockaddr_len = sizeof(struct sockaddr_in6), | 941 | .net_header_len = sizeof(struct ipv6hdr), |
938 | .sa_family = AF_INET6, | 942 | .sockaddr_len = sizeof(struct sockaddr_in6), |
943 | #ifdef CONFIG_COMPAT | ||
944 | .compat_setsockopt = compat_ipv6_setsockopt, | ||
945 | .compat_getsockopt = compat_ipv6_getsockopt, | ||
946 | #endif | ||
939 | }; | 947 | }; |
940 | 948 | ||
941 | static struct sctp_pf sctp_pf_inet6_specific = { | 949 | static struct sctp_pf sctp_pf_inet6_specific = { |
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index de693b43c8ea..2088aa992b7a 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
@@ -831,24 +831,28 @@ static struct notifier_block sctp_inetaddr_notifier = { | |||
831 | 831 | ||
832 | /* Socket operations. */ | 832 | /* Socket operations. */ |
833 | static const struct proto_ops inet_seqpacket_ops = { | 833 | static const struct proto_ops inet_seqpacket_ops = { |
834 | .family = PF_INET, | 834 | .family = PF_INET, |
835 | .owner = THIS_MODULE, | 835 | .owner = THIS_MODULE, |
836 | .release = inet_release, /* Needs to be wrapped... */ | 836 | .release = inet_release, /* Needs to be wrapped... */ |
837 | .bind = inet_bind, | 837 | .bind = inet_bind, |
838 | .connect = inet_dgram_connect, | 838 | .connect = inet_dgram_connect, |
839 | .socketpair = sock_no_socketpair, | 839 | .socketpair = sock_no_socketpair, |
840 | .accept = inet_accept, | 840 | .accept = inet_accept, |
841 | .getname = inet_getname, /* Semantics are different. */ | 841 | .getname = inet_getname, /* Semantics are different. */ |
842 | .poll = sctp_poll, | 842 | .poll = sctp_poll, |
843 | .ioctl = inet_ioctl, | 843 | .ioctl = inet_ioctl, |
844 | .listen = sctp_inet_listen, | 844 | .listen = sctp_inet_listen, |
845 | .shutdown = inet_shutdown, /* Looks harmless. */ | 845 | .shutdown = inet_shutdown, /* Looks harmless. */ |
846 | .setsockopt = sock_common_setsockopt, /* IP_SOL IP_OPTION is a problem. */ | 846 | .setsockopt = sock_common_setsockopt, /* IP_SOL IP_OPTION is a problem */ |
847 | .getsockopt = sock_common_getsockopt, | 847 | .getsockopt = sock_common_getsockopt, |
848 | .sendmsg = inet_sendmsg, | 848 | .sendmsg = inet_sendmsg, |
849 | .recvmsg = sock_common_recvmsg, | 849 | .recvmsg = sock_common_recvmsg, |
850 | .mmap = sock_no_mmap, | 850 | .mmap = sock_no_mmap, |
851 | .sendpage = sock_no_sendpage, | 851 | .sendpage = sock_no_sendpage, |
852 | #ifdef CONFIG_COMPAT | ||
853 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
854 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
855 | #endif | ||
852 | }; | 856 | }; |
853 | 857 | ||
854 | /* Registration with AF_INET family. */ | 858 | /* Registration with AF_INET family. */ |
@@ -880,31 +884,35 @@ static struct net_protocol sctp_protocol = { | |||
880 | 884 | ||
881 | /* IPv4 address related functions. */ | 885 | /* IPv4 address related functions. */ |
882 | static struct sctp_af sctp_ipv4_specific = { | 886 | static struct sctp_af sctp_ipv4_specific = { |
883 | .sctp_xmit = sctp_v4_xmit, | 887 | .sa_family = AF_INET, |
884 | .setsockopt = ip_setsockopt, | 888 | .sctp_xmit = sctp_v4_xmit, |
885 | .getsockopt = ip_getsockopt, | 889 | .setsockopt = ip_setsockopt, |
886 | .get_dst = sctp_v4_get_dst, | 890 | .getsockopt = ip_getsockopt, |
887 | .get_saddr = sctp_v4_get_saddr, | 891 | .get_dst = sctp_v4_get_dst, |
888 | .copy_addrlist = sctp_v4_copy_addrlist, | 892 | .get_saddr = sctp_v4_get_saddr, |
889 | .from_skb = sctp_v4_from_skb, | 893 | .copy_addrlist = sctp_v4_copy_addrlist, |
890 | .from_sk = sctp_v4_from_sk, | 894 | .from_skb = sctp_v4_from_skb, |
891 | .to_sk_saddr = sctp_v4_to_sk_saddr, | 895 | .from_sk = sctp_v4_from_sk, |
892 | .to_sk_daddr = sctp_v4_to_sk_daddr, | 896 | .to_sk_saddr = sctp_v4_to_sk_saddr, |
893 | .from_addr_param= sctp_v4_from_addr_param, | 897 | .to_sk_daddr = sctp_v4_to_sk_daddr, |
894 | .to_addr_param = sctp_v4_to_addr_param, | 898 | .from_addr_param = sctp_v4_from_addr_param, |
895 | .dst_saddr = sctp_v4_dst_saddr, | 899 | .to_addr_param = sctp_v4_to_addr_param, |
896 | .cmp_addr = sctp_v4_cmp_addr, | 900 | .dst_saddr = sctp_v4_dst_saddr, |
897 | .addr_valid = sctp_v4_addr_valid, | 901 | .cmp_addr = sctp_v4_cmp_addr, |
898 | .inaddr_any = sctp_v4_inaddr_any, | 902 | .addr_valid = sctp_v4_addr_valid, |
899 | .is_any = sctp_v4_is_any, | 903 | .inaddr_any = sctp_v4_inaddr_any, |
900 | .available = sctp_v4_available, | 904 | .is_any = sctp_v4_is_any, |
901 | .scope = sctp_v4_scope, | 905 | .available = sctp_v4_available, |
902 | .skb_iif = sctp_v4_skb_iif, | 906 | .scope = sctp_v4_scope, |
903 | .is_ce = sctp_v4_is_ce, | 907 | .skb_iif = sctp_v4_skb_iif, |
904 | .seq_dump_addr = sctp_v4_seq_dump_addr, | 908 | .is_ce = sctp_v4_is_ce, |
905 | .net_header_len = sizeof(struct iphdr), | 909 | .seq_dump_addr = sctp_v4_seq_dump_addr, |
906 | .sockaddr_len = sizeof(struct sockaddr_in), | 910 | .net_header_len = sizeof(struct iphdr), |
907 | .sa_family = AF_INET, | 911 | .sockaddr_len = sizeof(struct sockaddr_in), |
912 | #ifdef CONFIG_COMPAT | ||
913 | .compat_setsockopt = compat_ip_setsockopt, | ||
914 | .compat_getsockopt = compat_ip_getsockopt, | ||
915 | #endif | ||
908 | }; | 916 | }; |
909 | 917 | ||
910 | struct sctp_pf *sctp_get_pf_specific(sa_family_t family) { | 918 | struct sctp_pf *sctp_get_pf_specific(sa_family_t family) { |
diff --git a/net/socket.c b/net/socket.c index 7e1bdef8b09e..e2d5bae994de 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -68,6 +68,7 @@ | |||
68 | #include <linux/netdevice.h> | 68 | #include <linux/netdevice.h> |
69 | #include <linux/proc_fs.h> | 69 | #include <linux/proc_fs.h> |
70 | #include <linux/seq_file.h> | 70 | #include <linux/seq_file.h> |
71 | #include <linux/mutex.h> | ||
71 | #include <linux/wanrouter.h> | 72 | #include <linux/wanrouter.h> |
72 | #include <linux/if_bridge.h> | 73 | #include <linux/if_bridge.h> |
73 | #include <linux/if_frad.h> | 74 | #include <linux/if_frad.h> |
@@ -106,6 +107,10 @@ static unsigned int sock_poll(struct file *file, | |||
106 | struct poll_table_struct *wait); | 107 | struct poll_table_struct *wait); |
107 | static long sock_ioctl(struct file *file, | 108 | static long sock_ioctl(struct file *file, |
108 | unsigned int cmd, unsigned long arg); | 109 | unsigned int cmd, unsigned long arg); |
110 | #ifdef CONFIG_COMPAT | ||
111 | static long compat_sock_ioctl(struct file *file, | ||
112 | unsigned int cmd, unsigned long arg); | ||
113 | #endif | ||
109 | static int sock_fasync(int fd, struct file *filp, int on); | 114 | static int sock_fasync(int fd, struct file *filp, int on); |
110 | static ssize_t sock_readv(struct file *file, const struct iovec *vector, | 115 | static ssize_t sock_readv(struct file *file, const struct iovec *vector, |
111 | unsigned long count, loff_t *ppos); | 116 | unsigned long count, loff_t *ppos); |
@@ -127,6 +132,9 @@ static struct file_operations socket_file_ops = { | |||
127 | .aio_write = sock_aio_write, | 132 | .aio_write = sock_aio_write, |
128 | .poll = sock_poll, | 133 | .poll = sock_poll, |
129 | .unlocked_ioctl = sock_ioctl, | 134 | .unlocked_ioctl = sock_ioctl, |
135 | #ifdef CONFIG_COMPAT | ||
136 | .compat_ioctl = compat_sock_ioctl, | ||
137 | #endif | ||
130 | .mmap = sock_mmap, | 138 | .mmap = sock_mmap, |
131 | .open = sock_no_open, /* special open code to disallow open via /proc */ | 139 | .open = sock_no_open, /* special open code to disallow open via /proc */ |
132 | .release = sock_close, | 140 | .release = sock_close, |
@@ -348,8 +356,8 @@ static struct dentry_operations sockfs_dentry_operations = { | |||
348 | /* | 356 | /* |
349 | * Obtains the first available file descriptor and sets it up for use. | 357 | * Obtains the first available file descriptor and sets it up for use. |
350 | * | 358 | * |
351 | * This function creates file structure and maps it to fd space | 359 | * These functions create file structures and maps them to fd space |
352 | * of current process. On success it returns file descriptor | 360 | * of the current process. On success it returns file descriptor |
353 | * and file struct implicitly stored in sock->file. | 361 | * and file struct implicitly stored in sock->file. |
354 | * Note that another thread may close file descriptor before we return | 362 | * Note that another thread may close file descriptor before we return |
355 | * from this function. We use the fact that now we do not refer | 363 | * from this function. We use the fact that now we do not refer |
@@ -362,53 +370,90 @@ static struct dentry_operations sockfs_dentry_operations = { | |||
362 | * but we take care of internal coherence yet. | 370 | * but we take care of internal coherence yet. |
363 | */ | 371 | */ |
364 | 372 | ||
365 | int sock_map_fd(struct socket *sock) | 373 | static int sock_alloc_fd(struct file **filep) |
366 | { | 374 | { |
367 | int fd; | 375 | int fd; |
368 | struct qstr this; | ||
369 | char name[32]; | ||
370 | |||
371 | /* | ||
372 | * Find a file descriptor suitable for return to the user. | ||
373 | */ | ||
374 | 376 | ||
375 | fd = get_unused_fd(); | 377 | fd = get_unused_fd(); |
376 | if (fd >= 0) { | 378 | if (likely(fd >= 0)) { |
377 | struct file *file = get_empty_filp(); | 379 | struct file *file = get_empty_filp(); |
378 | 380 | ||
379 | if (!file) { | 381 | *filep = file; |
382 | if (unlikely(!file)) { | ||
380 | put_unused_fd(fd); | 383 | put_unused_fd(fd); |
381 | fd = -ENFILE; | 384 | return -ENFILE; |
382 | goto out; | ||
383 | } | 385 | } |
386 | } else | ||
387 | *filep = NULL; | ||
388 | return fd; | ||
389 | } | ||
390 | |||
391 | static int sock_attach_fd(struct socket *sock, struct file *file) | ||
392 | { | ||
393 | struct qstr this; | ||
394 | char name[32]; | ||
384 | 395 | ||
385 | this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino); | 396 | this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino); |
386 | this.name = name; | 397 | this.name = name; |
387 | this.hash = SOCK_INODE(sock)->i_ino; | 398 | this.hash = SOCK_INODE(sock)->i_ino; |
388 | 399 | ||
389 | file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this); | 400 | file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this); |
390 | if (!file->f_dentry) { | 401 | if (unlikely(!file->f_dentry)) |
391 | put_filp(file); | 402 | return -ENOMEM; |
403 | |||
404 | file->f_dentry->d_op = &sockfs_dentry_operations; | ||
405 | d_add(file->f_dentry, SOCK_INODE(sock)); | ||
406 | file->f_vfsmnt = mntget(sock_mnt); | ||
407 | file->f_mapping = file->f_dentry->d_inode->i_mapping; | ||
408 | |||
409 | sock->file = file; | ||
410 | file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops; | ||
411 | file->f_mode = FMODE_READ | FMODE_WRITE; | ||
412 | file->f_flags = O_RDWR; | ||
413 | file->f_pos = 0; | ||
414 | file->private_data = sock; | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | int sock_map_fd(struct socket *sock) | ||
420 | { | ||
421 | struct file *newfile; | ||
422 | int fd = sock_alloc_fd(&newfile); | ||
423 | |||
424 | if (likely(fd >= 0)) { | ||
425 | int err = sock_attach_fd(sock, newfile); | ||
426 | |||
427 | if (unlikely(err < 0)) { | ||
428 | put_filp(newfile); | ||
392 | put_unused_fd(fd); | 429 | put_unused_fd(fd); |
393 | fd = -ENOMEM; | 430 | return err; |
394 | goto out; | ||
395 | } | 431 | } |
396 | file->f_dentry->d_op = &sockfs_dentry_operations; | 432 | fd_install(fd, newfile); |
397 | d_add(file->f_dentry, SOCK_INODE(sock)); | 433 | } |
398 | file->f_vfsmnt = mntget(sock_mnt); | 434 | return fd; |
399 | file->f_mapping = file->f_dentry->d_inode->i_mapping; | 435 | } |
400 | 436 | ||
401 | sock->file = file; | 437 | static struct socket *sock_from_file(struct file *file, int *err) |
402 | file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops; | 438 | { |
403 | file->f_mode = FMODE_READ | FMODE_WRITE; | 439 | struct inode *inode; |
404 | file->f_flags = O_RDWR; | 440 | struct socket *sock; |
405 | file->f_pos = 0; | 441 | |
406 | file->private_data = sock; | 442 | if (file->f_op == &socket_file_ops) |
407 | fd_install(fd, file); | 443 | return file->private_data; /* set in sock_map_fd */ |
444 | |||
445 | inode = file->f_dentry->d_inode; | ||
446 | if (!S_ISSOCK(inode->i_mode)) { | ||
447 | *err = -ENOTSOCK; | ||
448 | return NULL; | ||
408 | } | 449 | } |
409 | 450 | ||
410 | out: | 451 | sock = SOCKET_I(inode); |
411 | return fd; | 452 | if (sock->file != file) { |
453 | printk(KERN_ERR "socki_lookup: socket file changed!\n"); | ||
454 | sock->file = file; | ||
455 | } | ||
456 | return sock; | ||
412 | } | 457 | } |
413 | 458 | ||
414 | /** | 459 | /** |
@@ -427,31 +472,31 @@ out: | |||
427 | struct socket *sockfd_lookup(int fd, int *err) | 472 | struct socket *sockfd_lookup(int fd, int *err) |
428 | { | 473 | { |
429 | struct file *file; | 474 | struct file *file; |
430 | struct inode *inode; | ||
431 | struct socket *sock; | 475 | struct socket *sock; |
432 | 476 | ||
433 | if (!(file = fget(fd))) | 477 | if (!(file = fget(fd))) { |
434 | { | ||
435 | *err = -EBADF; | 478 | *err = -EBADF; |
436 | return NULL; | 479 | return NULL; |
437 | } | 480 | } |
438 | 481 | sock = sock_from_file(file, err); | |
439 | if (file->f_op == &socket_file_ops) | 482 | if (!sock) |
440 | return file->private_data; /* set in sock_map_fd */ | ||
441 | |||
442 | inode = file->f_dentry->d_inode; | ||
443 | if (!S_ISSOCK(inode->i_mode)) { | ||
444 | *err = -ENOTSOCK; | ||
445 | fput(file); | 483 | fput(file); |
446 | return NULL; | 484 | return sock; |
447 | } | 485 | } |
448 | 486 | ||
449 | sock = SOCKET_I(inode); | 487 | static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed) |
450 | if (sock->file != file) { | 488 | { |
451 | printk(KERN_ERR "socki_lookup: socket file changed!\n"); | 489 | struct file *file; |
452 | sock->file = file; | 490 | struct socket *sock; |
491 | |||
492 | file = fget_light(fd, fput_needed); | ||
493 | if (file) { | ||
494 | sock = sock_from_file(file, err); | ||
495 | if (sock) | ||
496 | return sock; | ||
497 | fput_light(file, *fput_needed); | ||
453 | } | 498 | } |
454 | return sock; | 499 | return NULL; |
455 | } | 500 | } |
456 | 501 | ||
457 | /** | 502 | /** |
@@ -789,36 +834,36 @@ static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, | |||
789 | * with module unload. | 834 | * with module unload. |
790 | */ | 835 | */ |
791 | 836 | ||
792 | static DECLARE_MUTEX(br_ioctl_mutex); | 837 | static DEFINE_MUTEX(br_ioctl_mutex); |
793 | static int (*br_ioctl_hook)(unsigned int cmd, void __user *arg) = NULL; | 838 | static int (*br_ioctl_hook)(unsigned int cmd, void __user *arg) = NULL; |
794 | 839 | ||
795 | void brioctl_set(int (*hook)(unsigned int, void __user *)) | 840 | void brioctl_set(int (*hook)(unsigned int, void __user *)) |
796 | { | 841 | { |
797 | down(&br_ioctl_mutex); | 842 | mutex_lock(&br_ioctl_mutex); |
798 | br_ioctl_hook = hook; | 843 | br_ioctl_hook = hook; |
799 | up(&br_ioctl_mutex); | 844 | mutex_unlock(&br_ioctl_mutex); |
800 | } | 845 | } |
801 | EXPORT_SYMBOL(brioctl_set); | 846 | EXPORT_SYMBOL(brioctl_set); |
802 | 847 | ||
803 | static DECLARE_MUTEX(vlan_ioctl_mutex); | 848 | static DEFINE_MUTEX(vlan_ioctl_mutex); |
804 | static int (*vlan_ioctl_hook)(void __user *arg); | 849 | static int (*vlan_ioctl_hook)(void __user *arg); |
805 | 850 | ||
806 | void vlan_ioctl_set(int (*hook)(void __user *)) | 851 | void vlan_ioctl_set(int (*hook)(void __user *)) |
807 | { | 852 | { |
808 | down(&vlan_ioctl_mutex); | 853 | mutex_lock(&vlan_ioctl_mutex); |
809 | vlan_ioctl_hook = hook; | 854 | vlan_ioctl_hook = hook; |
810 | up(&vlan_ioctl_mutex); | 855 | mutex_unlock(&vlan_ioctl_mutex); |
811 | } | 856 | } |
812 | EXPORT_SYMBOL(vlan_ioctl_set); | 857 | EXPORT_SYMBOL(vlan_ioctl_set); |
813 | 858 | ||
814 | static DECLARE_MUTEX(dlci_ioctl_mutex); | 859 | static DEFINE_MUTEX(dlci_ioctl_mutex); |
815 | static int (*dlci_ioctl_hook)(unsigned int, void __user *); | 860 | static int (*dlci_ioctl_hook)(unsigned int, void __user *); |
816 | 861 | ||
817 | void dlci_ioctl_set(int (*hook)(unsigned int, void __user *)) | 862 | void dlci_ioctl_set(int (*hook)(unsigned int, void __user *)) |
818 | { | 863 | { |
819 | down(&dlci_ioctl_mutex); | 864 | mutex_lock(&dlci_ioctl_mutex); |
820 | dlci_ioctl_hook = hook; | 865 | dlci_ioctl_hook = hook; |
821 | up(&dlci_ioctl_mutex); | 866 | mutex_unlock(&dlci_ioctl_mutex); |
822 | } | 867 | } |
823 | EXPORT_SYMBOL(dlci_ioctl_set); | 868 | EXPORT_SYMBOL(dlci_ioctl_set); |
824 | 869 | ||
@@ -862,10 +907,10 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
862 | if (!br_ioctl_hook) | 907 | if (!br_ioctl_hook) |
863 | request_module("bridge"); | 908 | request_module("bridge"); |
864 | 909 | ||
865 | down(&br_ioctl_mutex); | 910 | mutex_lock(&br_ioctl_mutex); |
866 | if (br_ioctl_hook) | 911 | if (br_ioctl_hook) |
867 | err = br_ioctl_hook(cmd, argp); | 912 | err = br_ioctl_hook(cmd, argp); |
868 | up(&br_ioctl_mutex); | 913 | mutex_unlock(&br_ioctl_mutex); |
869 | break; | 914 | break; |
870 | case SIOCGIFVLAN: | 915 | case SIOCGIFVLAN: |
871 | case SIOCSIFVLAN: | 916 | case SIOCSIFVLAN: |
@@ -873,10 +918,10 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
873 | if (!vlan_ioctl_hook) | 918 | if (!vlan_ioctl_hook) |
874 | request_module("8021q"); | 919 | request_module("8021q"); |
875 | 920 | ||
876 | down(&vlan_ioctl_mutex); | 921 | mutex_lock(&vlan_ioctl_mutex); |
877 | if (vlan_ioctl_hook) | 922 | if (vlan_ioctl_hook) |
878 | err = vlan_ioctl_hook(argp); | 923 | err = vlan_ioctl_hook(argp); |
879 | up(&vlan_ioctl_mutex); | 924 | mutex_unlock(&vlan_ioctl_mutex); |
880 | break; | 925 | break; |
881 | case SIOCGIFDIVERT: | 926 | case SIOCGIFDIVERT: |
882 | case SIOCSIFDIVERT: | 927 | case SIOCSIFDIVERT: |
@@ -890,9 +935,9 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
890 | request_module("dlci"); | 935 | request_module("dlci"); |
891 | 936 | ||
892 | if (dlci_ioctl_hook) { | 937 | if (dlci_ioctl_hook) { |
893 | down(&dlci_ioctl_mutex); | 938 | mutex_lock(&dlci_ioctl_mutex); |
894 | err = dlci_ioctl_hook(cmd, argp); | 939 | err = dlci_ioctl_hook(cmd, argp); |
895 | up(&dlci_ioctl_mutex); | 940 | mutex_unlock(&dlci_ioctl_mutex); |
896 | } | 941 | } |
897 | break; | 942 | break; |
898 | default: | 943 | default: |
@@ -1286,19 +1331,17 @@ asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) | |||
1286 | { | 1331 | { |
1287 | struct socket *sock; | 1332 | struct socket *sock; |
1288 | char address[MAX_SOCK_ADDR]; | 1333 | char address[MAX_SOCK_ADDR]; |
1289 | int err; | 1334 | int err, fput_needed; |
1290 | 1335 | ||
1291 | if((sock = sockfd_lookup(fd,&err))!=NULL) | 1336 | if((sock = sockfd_lookup_light(fd, &err, &fput_needed))!=NULL) |
1292 | { | 1337 | { |
1293 | if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) { | 1338 | if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) { |
1294 | err = security_socket_bind(sock, (struct sockaddr *)address, addrlen); | 1339 | err = security_socket_bind(sock, (struct sockaddr *)address, addrlen); |
1295 | if (err) { | 1340 | if (!err) |
1296 | sockfd_put(sock); | 1341 | err = sock->ops->bind(sock, |
1297 | return err; | 1342 | (struct sockaddr *)address, addrlen); |
1298 | } | ||
1299 | err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen); | ||
1300 | } | 1343 | } |
1301 | sockfd_put(sock); | 1344 | fput_light(sock->file, fput_needed); |
1302 | } | 1345 | } |
1303 | return err; | 1346 | return err; |
1304 | } | 1347 | } |
@@ -1315,20 +1358,17 @@ int sysctl_somaxconn = SOMAXCONN; | |||
1315 | asmlinkage long sys_listen(int fd, int backlog) | 1358 | asmlinkage long sys_listen(int fd, int backlog) |
1316 | { | 1359 | { |
1317 | struct socket *sock; | 1360 | struct socket *sock; |
1318 | int err; | 1361 | int err, fput_needed; |
1319 | 1362 | ||
1320 | if ((sock = sockfd_lookup(fd, &err)) != NULL) { | 1363 | if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) { |
1321 | if ((unsigned) backlog > sysctl_somaxconn) | 1364 | if ((unsigned) backlog > sysctl_somaxconn) |
1322 | backlog = sysctl_somaxconn; | 1365 | backlog = sysctl_somaxconn; |
1323 | 1366 | ||
1324 | err = security_socket_listen(sock, backlog); | 1367 | err = security_socket_listen(sock, backlog); |
1325 | if (err) { | 1368 | if (!err) |
1326 | sockfd_put(sock); | 1369 | err = sock->ops->listen(sock, backlog); |
1327 | return err; | ||
1328 | } | ||
1329 | 1370 | ||
1330 | err=sock->ops->listen(sock, backlog); | 1371 | fput_light(sock->file, fput_needed); |
1331 | sockfd_put(sock); | ||
1332 | } | 1372 | } |
1333 | return err; | 1373 | return err; |
1334 | } | 1374 | } |
@@ -1349,10 +1389,11 @@ asmlinkage long sys_listen(int fd, int backlog) | |||
1349 | asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen) | 1389 | asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen) |
1350 | { | 1390 | { |
1351 | struct socket *sock, *newsock; | 1391 | struct socket *sock, *newsock; |
1352 | int err, len; | 1392 | struct file *newfile; |
1393 | int err, len, newfd, fput_needed; | ||
1353 | char address[MAX_SOCK_ADDR]; | 1394 | char address[MAX_SOCK_ADDR]; |
1354 | 1395 | ||
1355 | sock = sockfd_lookup(fd, &err); | 1396 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1356 | if (!sock) | 1397 | if (!sock) |
1357 | goto out; | 1398 | goto out; |
1358 | 1399 | ||
@@ -1369,35 +1410,48 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _ | |||
1369 | */ | 1410 | */ |
1370 | __module_get(newsock->ops->owner); | 1411 | __module_get(newsock->ops->owner); |
1371 | 1412 | ||
1413 | newfd = sock_alloc_fd(&newfile); | ||
1414 | if (unlikely(newfd < 0)) { | ||
1415 | err = newfd; | ||
1416 | goto out_release; | ||
1417 | } | ||
1418 | |||
1419 | err = sock_attach_fd(newsock, newfile); | ||
1420 | if (err < 0) | ||
1421 | goto out_fd; | ||
1422 | |||
1372 | err = security_socket_accept(sock, newsock); | 1423 | err = security_socket_accept(sock, newsock); |
1373 | if (err) | 1424 | if (err) |
1374 | goto out_release; | 1425 | goto out_fd; |
1375 | 1426 | ||
1376 | err = sock->ops->accept(sock, newsock, sock->file->f_flags); | 1427 | err = sock->ops->accept(sock, newsock, sock->file->f_flags); |
1377 | if (err < 0) | 1428 | if (err < 0) |
1378 | goto out_release; | 1429 | goto out_fd; |
1379 | 1430 | ||
1380 | if (upeer_sockaddr) { | 1431 | if (upeer_sockaddr) { |
1381 | if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 2)<0) { | 1432 | if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 2)<0) { |
1382 | err = -ECONNABORTED; | 1433 | err = -ECONNABORTED; |
1383 | goto out_release; | 1434 | goto out_fd; |
1384 | } | 1435 | } |
1385 | err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen); | 1436 | err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen); |
1386 | if (err < 0) | 1437 | if (err < 0) |
1387 | goto out_release; | 1438 | goto out_fd; |
1388 | } | 1439 | } |
1389 | 1440 | ||
1390 | /* File flags are not inherited via accept() unlike another OSes. */ | 1441 | /* File flags are not inherited via accept() unlike another OSes. */ |
1391 | 1442 | ||
1392 | if ((err = sock_map_fd(newsock)) < 0) | 1443 | fd_install(newfd, newfile); |
1393 | goto out_release; | 1444 | err = newfd; |
1394 | 1445 | ||
1395 | security_socket_post_accept(sock, newsock); | 1446 | security_socket_post_accept(sock, newsock); |
1396 | 1447 | ||
1397 | out_put: | 1448 | out_put: |
1398 | sockfd_put(sock); | 1449 | fput_light(sock->file, fput_needed); |
1399 | out: | 1450 | out: |
1400 | return err; | 1451 | return err; |
1452 | out_fd: | ||
1453 | put_filp(newfile); | ||
1454 | put_unused_fd(newfd); | ||
1401 | out_release: | 1455 | out_release: |
1402 | sock_release(newsock); | 1456 | sock_release(newsock); |
1403 | goto out_put; | 1457 | goto out_put; |
@@ -1420,9 +1474,9 @@ asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrl | |||
1420 | { | 1474 | { |
1421 | struct socket *sock; | 1475 | struct socket *sock; |
1422 | char address[MAX_SOCK_ADDR]; | 1476 | char address[MAX_SOCK_ADDR]; |
1423 | int err; | 1477 | int err, fput_needed; |
1424 | 1478 | ||
1425 | sock = sockfd_lookup(fd, &err); | 1479 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1426 | if (!sock) | 1480 | if (!sock) |
1427 | goto out; | 1481 | goto out; |
1428 | err = move_addr_to_kernel(uservaddr, addrlen, address); | 1482 | err = move_addr_to_kernel(uservaddr, addrlen, address); |
@@ -1436,7 +1490,7 @@ asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrl | |||
1436 | err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen, | 1490 | err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen, |
1437 | sock->file->f_flags); | 1491 | sock->file->f_flags); |
1438 | out_put: | 1492 | out_put: |
1439 | sockfd_put(sock); | 1493 | fput_light(sock->file, fput_needed); |
1440 | out: | 1494 | out: |
1441 | return err; | 1495 | return err; |
1442 | } | 1496 | } |
@@ -1450,9 +1504,9 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int _ | |||
1450 | { | 1504 | { |
1451 | struct socket *sock; | 1505 | struct socket *sock; |
1452 | char address[MAX_SOCK_ADDR]; | 1506 | char address[MAX_SOCK_ADDR]; |
1453 | int len, err; | 1507 | int len, err, fput_needed; |
1454 | 1508 | ||
1455 | sock = sockfd_lookup(fd, &err); | 1509 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1456 | if (!sock) | 1510 | if (!sock) |
1457 | goto out; | 1511 | goto out; |
1458 | 1512 | ||
@@ -1466,7 +1520,7 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int _ | |||
1466 | err = move_addr_to_user(address, len, usockaddr, usockaddr_len); | 1520 | err = move_addr_to_user(address, len, usockaddr, usockaddr_len); |
1467 | 1521 | ||
1468 | out_put: | 1522 | out_put: |
1469 | sockfd_put(sock); | 1523 | fput_light(sock->file, fput_needed); |
1470 | out: | 1524 | out: |
1471 | return err; | 1525 | return err; |
1472 | } | 1526 | } |
@@ -1480,20 +1534,19 @@ asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, int _ | |||
1480 | { | 1534 | { |
1481 | struct socket *sock; | 1535 | struct socket *sock; |
1482 | char address[MAX_SOCK_ADDR]; | 1536 | char address[MAX_SOCK_ADDR]; |
1483 | int len, err; | 1537 | int len, err, fput_needed; |
1484 | 1538 | ||
1485 | if ((sock = sockfd_lookup(fd, &err))!=NULL) | 1539 | if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) { |
1486 | { | ||
1487 | err = security_socket_getpeername(sock); | 1540 | err = security_socket_getpeername(sock); |
1488 | if (err) { | 1541 | if (err) { |
1489 | sockfd_put(sock); | 1542 | fput_light(sock->file, fput_needed); |
1490 | return err; | 1543 | return err; |
1491 | } | 1544 | } |
1492 | 1545 | ||
1493 | err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1); | 1546 | err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1); |
1494 | if (!err) | 1547 | if (!err) |
1495 | err=move_addr_to_user(address,len, usockaddr, usockaddr_len); | 1548 | err=move_addr_to_user(address,len, usockaddr, usockaddr_len); |
1496 | sockfd_put(sock); | 1549 | fput_light(sock->file, fput_needed); |
1497 | } | 1550 | } |
1498 | return err; | 1551 | return err; |
1499 | } | 1552 | } |
@@ -1512,10 +1565,16 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag | |||
1512 | int err; | 1565 | int err; |
1513 | struct msghdr msg; | 1566 | struct msghdr msg; |
1514 | struct iovec iov; | 1567 | struct iovec iov; |
1515 | 1568 | int fput_needed; | |
1516 | sock = sockfd_lookup(fd, &err); | 1569 | struct file *sock_file; |
1570 | |||
1571 | sock_file = fget_light(fd, &fput_needed); | ||
1572 | if (!sock_file) | ||
1573 | return -EBADF; | ||
1574 | |||
1575 | sock = sock_from_file(sock_file, &err); | ||
1517 | if (!sock) | 1576 | if (!sock) |
1518 | goto out; | 1577 | goto out_put; |
1519 | iov.iov_base=buff; | 1578 | iov.iov_base=buff; |
1520 | iov.iov_len=len; | 1579 | iov.iov_len=len; |
1521 | msg.msg_name=NULL; | 1580 | msg.msg_name=NULL; |
@@ -1524,8 +1583,7 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag | |||
1524 | msg.msg_control=NULL; | 1583 | msg.msg_control=NULL; |
1525 | msg.msg_controllen=0; | 1584 | msg.msg_controllen=0; |
1526 | msg.msg_namelen=0; | 1585 | msg.msg_namelen=0; |
1527 | if(addr) | 1586 | if (addr) { |
1528 | { | ||
1529 | err = move_addr_to_kernel(addr, addr_len, address); | 1587 | err = move_addr_to_kernel(addr, addr_len, address); |
1530 | if (err < 0) | 1588 | if (err < 0) |
1531 | goto out_put; | 1589 | goto out_put; |
@@ -1538,8 +1596,7 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag | |||
1538 | err = sock_sendmsg(sock, &msg, len); | 1596 | err = sock_sendmsg(sock, &msg, len); |
1539 | 1597 | ||
1540 | out_put: | 1598 | out_put: |
1541 | sockfd_put(sock); | 1599 | fput_light(sock_file, fput_needed); |
1542 | out: | ||
1543 | return err; | 1600 | return err; |
1544 | } | 1601 | } |
1545 | 1602 | ||
@@ -1566,8 +1623,14 @@ asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned f | |||
1566 | struct msghdr msg; | 1623 | struct msghdr msg; |
1567 | char address[MAX_SOCK_ADDR]; | 1624 | char address[MAX_SOCK_ADDR]; |
1568 | int err,err2; | 1625 | int err,err2; |
1626 | struct file *sock_file; | ||
1627 | int fput_needed; | ||
1628 | |||
1629 | sock_file = fget_light(fd, &fput_needed); | ||
1630 | if (!sock_file) | ||
1631 | return -EBADF; | ||
1569 | 1632 | ||
1570 | sock = sockfd_lookup(fd, &err); | 1633 | sock = sock_from_file(sock_file, &err); |
1571 | if (!sock) | 1634 | if (!sock) |
1572 | goto out; | 1635 | goto out; |
1573 | 1636 | ||
@@ -1589,8 +1652,8 @@ asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned f | |||
1589 | if(err2<0) | 1652 | if(err2<0) |
1590 | err=err2; | 1653 | err=err2; |
1591 | } | 1654 | } |
1592 | sockfd_put(sock); | ||
1593 | out: | 1655 | out: |
1656 | fput_light(sock_file, fput_needed); | ||
1594 | return err; | 1657 | return err; |
1595 | } | 1658 | } |
1596 | 1659 | ||
@@ -1610,25 +1673,24 @@ asmlinkage long sys_recv(int fd, void __user * ubuf, size_t size, unsigned flags | |||
1610 | 1673 | ||
1611 | asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen) | 1674 | asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen) |
1612 | { | 1675 | { |
1613 | int err; | 1676 | int err, fput_needed; |
1614 | struct socket *sock; | 1677 | struct socket *sock; |
1615 | 1678 | ||
1616 | if (optlen < 0) | 1679 | if (optlen < 0) |
1617 | return -EINVAL; | 1680 | return -EINVAL; |
1618 | 1681 | ||
1619 | if ((sock = sockfd_lookup(fd, &err))!=NULL) | 1682 | if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) |
1620 | { | 1683 | { |
1621 | err = security_socket_setsockopt(sock,level,optname); | 1684 | err = security_socket_setsockopt(sock,level,optname); |
1622 | if (err) { | 1685 | if (err) |
1623 | sockfd_put(sock); | 1686 | goto out_put; |
1624 | return err; | ||
1625 | } | ||
1626 | 1687 | ||
1627 | if (level == SOL_SOCKET) | 1688 | if (level == SOL_SOCKET) |
1628 | err=sock_setsockopt(sock,level,optname,optval,optlen); | 1689 | err=sock_setsockopt(sock,level,optname,optval,optlen); |
1629 | else | 1690 | else |
1630 | err=sock->ops->setsockopt(sock, level, optname, optval, optlen); | 1691 | err=sock->ops->setsockopt(sock, level, optname, optval, optlen); |
1631 | sockfd_put(sock); | 1692 | out_put: |
1693 | fput_light(sock->file, fput_needed); | ||
1632 | } | 1694 | } |
1633 | return err; | 1695 | return err; |
1634 | } | 1696 | } |
@@ -1640,23 +1702,20 @@ asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optv | |||
1640 | 1702 | ||
1641 | asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen) | 1703 | asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen) |
1642 | { | 1704 | { |
1643 | int err; | 1705 | int err, fput_needed; |
1644 | struct socket *sock; | 1706 | struct socket *sock; |
1645 | 1707 | ||
1646 | if ((sock = sockfd_lookup(fd, &err))!=NULL) | 1708 | if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) { |
1647 | { | 1709 | err = security_socket_getsockopt(sock, level, optname); |
1648 | err = security_socket_getsockopt(sock, level, | 1710 | if (err) |
1649 | optname); | 1711 | goto out_put; |
1650 | if (err) { | ||
1651 | sockfd_put(sock); | ||
1652 | return err; | ||
1653 | } | ||
1654 | 1712 | ||
1655 | if (level == SOL_SOCKET) | 1713 | if (level == SOL_SOCKET) |
1656 | err=sock_getsockopt(sock,level,optname,optval,optlen); | 1714 | err=sock_getsockopt(sock,level,optname,optval,optlen); |
1657 | else | 1715 | else |
1658 | err=sock->ops->getsockopt(sock, level, optname, optval, optlen); | 1716 | err=sock->ops->getsockopt(sock, level, optname, optval, optlen); |
1659 | sockfd_put(sock); | 1717 | out_put: |
1718 | fput_light(sock->file, fput_needed); | ||
1660 | } | 1719 | } |
1661 | return err; | 1720 | return err; |
1662 | } | 1721 | } |
@@ -1668,19 +1727,15 @@ asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optv | |||
1668 | 1727 | ||
1669 | asmlinkage long sys_shutdown(int fd, int how) | 1728 | asmlinkage long sys_shutdown(int fd, int how) |
1670 | { | 1729 | { |
1671 | int err; | 1730 | int err, fput_needed; |
1672 | struct socket *sock; | 1731 | struct socket *sock; |
1673 | 1732 | ||
1674 | if ((sock = sockfd_lookup(fd, &err))!=NULL) | 1733 | if ((sock = sockfd_lookup_light(fd, &err, &fput_needed))!=NULL) |
1675 | { | 1734 | { |
1676 | err = security_socket_shutdown(sock, how); | 1735 | err = security_socket_shutdown(sock, how); |
1677 | if (err) { | 1736 | if (!err) |
1678 | sockfd_put(sock); | 1737 | err = sock->ops->shutdown(sock, how); |
1679 | return err; | 1738 | fput_light(sock->file, fput_needed); |
1680 | } | ||
1681 | |||
1682 | err=sock->ops->shutdown(sock, how); | ||
1683 | sockfd_put(sock); | ||
1684 | } | 1739 | } |
1685 | return err; | 1740 | return err; |
1686 | } | 1741 | } |
@@ -1709,6 +1764,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) | |||
1709 | unsigned char *ctl_buf = ctl; | 1764 | unsigned char *ctl_buf = ctl; |
1710 | struct msghdr msg_sys; | 1765 | struct msghdr msg_sys; |
1711 | int err, ctl_len, iov_size, total_len; | 1766 | int err, ctl_len, iov_size, total_len; |
1767 | int fput_needed; | ||
1712 | 1768 | ||
1713 | err = -EFAULT; | 1769 | err = -EFAULT; |
1714 | if (MSG_CMSG_COMPAT & flags) { | 1770 | if (MSG_CMSG_COMPAT & flags) { |
@@ -1717,7 +1773,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) | |||
1717 | } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr))) | 1773 | } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr))) |
1718 | return -EFAULT; | 1774 | return -EFAULT; |
1719 | 1775 | ||
1720 | sock = sockfd_lookup(fd, &err); | 1776 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1721 | if (!sock) | 1777 | if (!sock) |
1722 | goto out; | 1778 | goto out; |
1723 | 1779 | ||
@@ -1785,7 +1841,7 @@ out_freeiov: | |||
1785 | if (iov != iovstack) | 1841 | if (iov != iovstack) |
1786 | sock_kfree_s(sock->sk, iov, iov_size); | 1842 | sock_kfree_s(sock->sk, iov, iov_size); |
1787 | out_put: | 1843 | out_put: |
1788 | sockfd_put(sock); | 1844 | fput_light(sock->file, fput_needed); |
1789 | out: | 1845 | out: |
1790 | return err; | 1846 | return err; |
1791 | } | 1847 | } |
@@ -1803,6 +1859,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag | |||
1803 | struct msghdr msg_sys; | 1859 | struct msghdr msg_sys; |
1804 | unsigned long cmsg_ptr; | 1860 | unsigned long cmsg_ptr; |
1805 | int err, iov_size, total_len, len; | 1861 | int err, iov_size, total_len, len; |
1862 | int fput_needed; | ||
1806 | 1863 | ||
1807 | /* kernel mode address */ | 1864 | /* kernel mode address */ |
1808 | char addr[MAX_SOCK_ADDR]; | 1865 | char addr[MAX_SOCK_ADDR]; |
@@ -1818,7 +1875,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag | |||
1818 | if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) | 1875 | if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) |
1819 | return -EFAULT; | 1876 | return -EFAULT; |
1820 | 1877 | ||
1821 | sock = sockfd_lookup(fd, &err); | 1878 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1822 | if (!sock) | 1879 | if (!sock) |
1823 | goto out; | 1880 | goto out; |
1824 | 1881 | ||
@@ -1885,7 +1942,7 @@ out_freeiov: | |||
1885 | if (iov != iovstack) | 1942 | if (iov != iovstack) |
1886 | sock_kfree_s(sock->sk, iov, iov_size); | 1943 | sock_kfree_s(sock->sk, iov, iov_size); |
1887 | out_put: | 1944 | out_put: |
1888 | sockfd_put(sock); | 1945 | fput_light(sock->file, fput_needed); |
1889 | out: | 1946 | out: |
1890 | return err; | 1947 | return err; |
1891 | } | 1948 | } |
@@ -2086,6 +2143,20 @@ void socket_seq_show(struct seq_file *seq) | |||
2086 | } | 2143 | } |
2087 | #endif /* CONFIG_PROC_FS */ | 2144 | #endif /* CONFIG_PROC_FS */ |
2088 | 2145 | ||
2146 | #ifdef CONFIG_COMPAT | ||
2147 | static long compat_sock_ioctl(struct file *file, unsigned cmd, | ||
2148 | unsigned long arg) | ||
2149 | { | ||
2150 | struct socket *sock = file->private_data; | ||
2151 | int ret = -ENOIOCTLCMD; | ||
2152 | |||
2153 | if (sock->ops->compat_ioctl) | ||
2154 | ret = sock->ops->compat_ioctl(sock, cmd, arg); | ||
2155 | |||
2156 | return ret; | ||
2157 | } | ||
2158 | #endif | ||
2159 | |||
2089 | /* ABI emulation layers need these two */ | 2160 | /* ABI emulation layers need these two */ |
2090 | EXPORT_SYMBOL(move_addr_to_kernel); | 2161 | EXPORT_SYMBOL(move_addr_to_kernel); |
2091 | EXPORT_SYMBOL(move_addr_to_user); | 2162 | EXPORT_SYMBOL(move_addr_to_user); |
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index dcaa0c4453ff..0acccfeeb284 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/proc_fs.h> | 26 | #include <linux/proc_fs.h> |
27 | #include <linux/net.h> | 27 | #include <linux/net.h> |
28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
29 | #include <linux/mutex.h> | ||
29 | #include <asm/ioctls.h> | 30 | #include <asm/ioctls.h> |
30 | #include <linux/sunrpc/types.h> | 31 | #include <linux/sunrpc/types.h> |
31 | #include <linux/sunrpc/cache.h> | 32 | #include <linux/sunrpc/cache.h> |
@@ -532,7 +533,7 @@ void cache_clean_deferred(void *owner) | |||
532 | */ | 533 | */ |
533 | 534 | ||
534 | static DEFINE_SPINLOCK(queue_lock); | 535 | static DEFINE_SPINLOCK(queue_lock); |
535 | static DECLARE_MUTEX(queue_io_sem); | 536 | static DEFINE_MUTEX(queue_io_mutex); |
536 | 537 | ||
537 | struct cache_queue { | 538 | struct cache_queue { |
538 | struct list_head list; | 539 | struct list_head list; |
@@ -561,7 +562,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
561 | if (count == 0) | 562 | if (count == 0) |
562 | return 0; | 563 | return 0; |
563 | 564 | ||
564 | down(&queue_io_sem); /* protect against multiple concurrent | 565 | mutex_lock(&queue_io_mutex); /* protect against multiple concurrent |
565 | * readers on this file */ | 566 | * readers on this file */ |
566 | again: | 567 | again: |
567 | spin_lock(&queue_lock); | 568 | spin_lock(&queue_lock); |
@@ -574,7 +575,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
574 | } | 575 | } |
575 | if (rp->q.list.next == &cd->queue) { | 576 | if (rp->q.list.next == &cd->queue) { |
576 | spin_unlock(&queue_lock); | 577 | spin_unlock(&queue_lock); |
577 | up(&queue_io_sem); | 578 | mutex_unlock(&queue_io_mutex); |
578 | BUG_ON(rp->offset); | 579 | BUG_ON(rp->offset); |
579 | return 0; | 580 | return 0; |
580 | } | 581 | } |
@@ -621,11 +622,11 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
621 | } | 622 | } |
622 | if (err == -EAGAIN) | 623 | if (err == -EAGAIN) |
623 | goto again; | 624 | goto again; |
624 | up(&queue_io_sem); | 625 | mutex_unlock(&queue_io_mutex); |
625 | return err ? err : count; | 626 | return err ? err : count; |
626 | } | 627 | } |
627 | 628 | ||
628 | static char write_buf[8192]; /* protected by queue_io_sem */ | 629 | static char write_buf[8192]; /* protected by queue_io_mutex */ |
629 | 630 | ||
630 | static ssize_t | 631 | static ssize_t |
631 | cache_write(struct file *filp, const char __user *buf, size_t count, | 632 | cache_write(struct file *filp, const char __user *buf, size_t count, |
@@ -639,10 +640,10 @@ cache_write(struct file *filp, const char __user *buf, size_t count, | |||
639 | if (count >= sizeof(write_buf)) | 640 | if (count >= sizeof(write_buf)) |
640 | return -EINVAL; | 641 | return -EINVAL; |
641 | 642 | ||
642 | down(&queue_io_sem); | 643 | mutex_lock(&queue_io_mutex); |
643 | 644 | ||
644 | if (copy_from_user(write_buf, buf, count)) { | 645 | if (copy_from_user(write_buf, buf, count)) { |
645 | up(&queue_io_sem); | 646 | mutex_unlock(&queue_io_mutex); |
646 | return -EFAULT; | 647 | return -EFAULT; |
647 | } | 648 | } |
648 | write_buf[count] = '\0'; | 649 | write_buf[count] = '\0'; |
@@ -651,7 +652,7 @@ cache_write(struct file *filp, const char __user *buf, size_t count, | |||
651 | else | 652 | else |
652 | err = -EINVAL; | 653 | err = -EINVAL; |
653 | 654 | ||
654 | up(&queue_io_sem); | 655 | mutex_unlock(&queue_io_mutex); |
655 | return err ? err : count; | 656 | return err ? err : count; |
656 | } | 657 | } |
657 | 658 | ||
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 3fc13bea302d..b9969b91a9f7 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/smp.h> | 18 | #include <linux/smp.h> |
19 | #include <linux/smp_lock.h> | 19 | #include <linux/smp_lock.h> |
20 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
21 | #include <linux/mutex.h> | ||
21 | 22 | ||
22 | #include <linux/sunrpc/clnt.h> | 23 | #include <linux/sunrpc/clnt.h> |
23 | #include <linux/sunrpc/xprt.h> | 24 | #include <linux/sunrpc/xprt.h> |
@@ -62,7 +63,7 @@ static LIST_HEAD(all_tasks); | |||
62 | /* | 63 | /* |
63 | * rpciod-related stuff | 64 | * rpciod-related stuff |
64 | */ | 65 | */ |
65 | static DECLARE_MUTEX(rpciod_sema); | 66 | static DEFINE_MUTEX(rpciod_mutex); |
66 | static unsigned int rpciod_users; | 67 | static unsigned int rpciod_users; |
67 | struct workqueue_struct *rpciod_workqueue; | 68 | struct workqueue_struct *rpciod_workqueue; |
68 | 69 | ||
@@ -1055,7 +1056,7 @@ rpciod_up(void) | |||
1055 | struct workqueue_struct *wq; | 1056 | struct workqueue_struct *wq; |
1056 | int error = 0; | 1057 | int error = 0; |
1057 | 1058 | ||
1058 | down(&rpciod_sema); | 1059 | mutex_lock(&rpciod_mutex); |
1059 | dprintk("rpciod_up: users %d\n", rpciod_users); | 1060 | dprintk("rpciod_up: users %d\n", rpciod_users); |
1060 | rpciod_users++; | 1061 | rpciod_users++; |
1061 | if (rpciod_workqueue) | 1062 | if (rpciod_workqueue) |
@@ -1078,14 +1079,14 @@ rpciod_up(void) | |||
1078 | rpciod_workqueue = wq; | 1079 | rpciod_workqueue = wq; |
1079 | error = 0; | 1080 | error = 0; |
1080 | out: | 1081 | out: |
1081 | up(&rpciod_sema); | 1082 | mutex_unlock(&rpciod_mutex); |
1082 | return error; | 1083 | return error; |
1083 | } | 1084 | } |
1084 | 1085 | ||
1085 | void | 1086 | void |
1086 | rpciod_down(void) | 1087 | rpciod_down(void) |
1087 | { | 1088 | { |
1088 | down(&rpciod_sema); | 1089 | mutex_lock(&rpciod_mutex); |
1089 | dprintk("rpciod_down sema %d\n", rpciod_users); | 1090 | dprintk("rpciod_down sema %d\n", rpciod_users); |
1090 | if (rpciod_users) { | 1091 | if (rpciod_users) { |
1091 | if (--rpciod_users) | 1092 | if (--rpciod_users) |
@@ -1102,7 +1103,7 @@ rpciod_down(void) | |||
1102 | destroy_workqueue(rpciod_workqueue); | 1103 | destroy_workqueue(rpciod_workqueue); |
1103 | rpciod_workqueue = NULL; | 1104 | rpciod_workqueue = NULL; |
1104 | out: | 1105 | out: |
1105 | up(&rpciod_sema); | 1106 | mutex_unlock(&rpciod_mutex); |
1106 | } | 1107 | } |
1107 | 1108 | ||
1108 | #ifdef RPC_DEBUG | 1109 | #ifdef RPC_DEBUG |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 50580620e897..a27905a0ad27 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -1296,13 +1296,13 @@ svc_send(struct svc_rqst *rqstp) | |||
1296 | xb->page_len + | 1296 | xb->page_len + |
1297 | xb->tail[0].iov_len; | 1297 | xb->tail[0].iov_len; |
1298 | 1298 | ||
1299 | /* Grab svsk->sk_sem to serialize outgoing data. */ | 1299 | /* Grab svsk->sk_mutex to serialize outgoing data. */ |
1300 | down(&svsk->sk_sem); | 1300 | mutex_lock(&svsk->sk_mutex); |
1301 | if (test_bit(SK_DEAD, &svsk->sk_flags)) | 1301 | if (test_bit(SK_DEAD, &svsk->sk_flags)) |
1302 | len = -ENOTCONN; | 1302 | len = -ENOTCONN; |
1303 | else | 1303 | else |
1304 | len = svsk->sk_sendto(rqstp); | 1304 | len = svsk->sk_sendto(rqstp); |
1305 | up(&svsk->sk_sem); | 1305 | mutex_unlock(&svsk->sk_mutex); |
1306 | svc_sock_release(rqstp); | 1306 | svc_sock_release(rqstp); |
1307 | 1307 | ||
1308 | if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN) | 1308 | if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN) |
@@ -1351,7 +1351,7 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock, | |||
1351 | svsk->sk_lastrecv = get_seconds(); | 1351 | svsk->sk_lastrecv = get_seconds(); |
1352 | INIT_LIST_HEAD(&svsk->sk_deferred); | 1352 | INIT_LIST_HEAD(&svsk->sk_deferred); |
1353 | INIT_LIST_HEAD(&svsk->sk_ready); | 1353 | INIT_LIST_HEAD(&svsk->sk_ready); |
1354 | sema_init(&svsk->sk_sem, 1); | 1354 | mutex_init(&svsk->sk_mutex); |
1355 | 1355 | ||
1356 | /* Initialize the socket */ | 1356 | /* Initialize the socket */ |
1357 | if (sock->type == SOCK_DGRAM) | 1357 | if (sock->type == SOCK_DGRAM) |
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index a7b04f397c12..2c4ecbe50082 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c | |||
@@ -107,22 +107,22 @@ static spinlock_t bc_lock = SPIN_LOCK_UNLOCKED; | |||
107 | char tipc_bclink_name[] = "multicast-link"; | 107 | char tipc_bclink_name[] = "multicast-link"; |
108 | 108 | ||
109 | 109 | ||
110 | static inline u32 buf_seqno(struct sk_buff *buf) | 110 | static u32 buf_seqno(struct sk_buff *buf) |
111 | { | 111 | { |
112 | return msg_seqno(buf_msg(buf)); | 112 | return msg_seqno(buf_msg(buf)); |
113 | } | 113 | } |
114 | 114 | ||
115 | static inline u32 bcbuf_acks(struct sk_buff *buf) | 115 | static u32 bcbuf_acks(struct sk_buff *buf) |
116 | { | 116 | { |
117 | return (u32)(unsigned long)TIPC_SKB_CB(buf)->handle; | 117 | return (u32)(unsigned long)TIPC_SKB_CB(buf)->handle; |
118 | } | 118 | } |
119 | 119 | ||
120 | static inline void bcbuf_set_acks(struct sk_buff *buf, u32 acks) | 120 | static void bcbuf_set_acks(struct sk_buff *buf, u32 acks) |
121 | { | 121 | { |
122 | TIPC_SKB_CB(buf)->handle = (void *)(unsigned long)acks; | 122 | TIPC_SKB_CB(buf)->handle = (void *)(unsigned long)acks; |
123 | } | 123 | } |
124 | 124 | ||
125 | static inline void bcbuf_decr_acks(struct sk_buff *buf) | 125 | static void bcbuf_decr_acks(struct sk_buff *buf) |
126 | { | 126 | { |
127 | bcbuf_set_acks(buf, bcbuf_acks(buf) - 1); | 127 | bcbuf_set_acks(buf, bcbuf_acks(buf) - 1); |
128 | } | 128 | } |
@@ -134,7 +134,7 @@ static inline void bcbuf_decr_acks(struct sk_buff *buf) | |||
134 | * Called with 'node' locked, bc_lock unlocked | 134 | * Called with 'node' locked, bc_lock unlocked |
135 | */ | 135 | */ |
136 | 136 | ||
137 | static inline void bclink_set_gap(struct node *n_ptr) | 137 | static void bclink_set_gap(struct node *n_ptr) |
138 | { | 138 | { |
139 | struct sk_buff *buf = n_ptr->bclink.deferred_head; | 139 | struct sk_buff *buf = n_ptr->bclink.deferred_head; |
140 | 140 | ||
@@ -154,7 +154,7 @@ static inline void bclink_set_gap(struct node *n_ptr) | |||
154 | * distribute NACKs, but tries to use the same spacing (divide by 16). | 154 | * distribute NACKs, but tries to use the same spacing (divide by 16). |
155 | */ | 155 | */ |
156 | 156 | ||
157 | static inline int bclink_ack_allowed(u32 n) | 157 | static int bclink_ack_allowed(u32 n) |
158 | { | 158 | { |
159 | return((n % TIPC_MIN_LINK_WIN) == tipc_own_tag); | 159 | return((n % TIPC_MIN_LINK_WIN) == tipc_own_tag); |
160 | } | 160 | } |
@@ -271,7 +271,7 @@ static void bclink_send_nack(struct node *n_ptr) | |||
271 | msg_set_bcgap_to(msg, n_ptr->bclink.gap_to); | 271 | msg_set_bcgap_to(msg, n_ptr->bclink.gap_to); |
272 | msg_set_bcast_tag(msg, tipc_own_tag); | 272 | msg_set_bcast_tag(msg, tipc_own_tag); |
273 | 273 | ||
274 | if (tipc_bearer_send(&bcbearer->bearer, buf, 0)) { | 274 | if (tipc_bearer_send(&bcbearer->bearer, buf, NULL)) { |
275 | bcl->stats.sent_nacks++; | 275 | bcl->stats.sent_nacks++; |
276 | buf_discard(buf); | 276 | buf_discard(buf); |
277 | } else { | 277 | } else { |
@@ -314,7 +314,7 @@ void tipc_bclink_check_gap(struct node *n_ptr, u32 last_sent) | |||
314 | * Only tipc_net_lock set. | 314 | * Only tipc_net_lock set. |
315 | */ | 315 | */ |
316 | 316 | ||
317 | void tipc_bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 gap_to) | 317 | static void tipc_bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 gap_to) |
318 | { | 318 | { |
319 | struct node *n_ptr = tipc_node_find(dest); | 319 | struct node *n_ptr = tipc_node_find(dest); |
320 | u32 my_after, my_to; | 320 | u32 my_after, my_to; |
@@ -425,9 +425,9 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) | |||
425 | msg_bcgap_to(msg)); | 425 | msg_bcgap_to(msg)); |
426 | } else { | 426 | } else { |
427 | tipc_bclink_peek_nack(msg_destnode(msg), | 427 | tipc_bclink_peek_nack(msg_destnode(msg), |
428 | msg_bcast_tag(msg), | 428 | msg_bcast_tag(msg), |
429 | msg_bcgap_after(msg), | 429 | msg_bcgap_after(msg), |
430 | msg_bcgap_to(msg)); | 430 | msg_bcgap_to(msg)); |
431 | } | 431 | } |
432 | buf_discard(buf); | 432 | buf_discard(buf); |
433 | return; | 433 | return; |
@@ -525,16 +525,18 @@ u32 tipc_bclink_acks_missing(struct node *n_ptr) | |||
525 | * Returns 0 if packet sent successfully, non-zero if not | 525 | * Returns 0 if packet sent successfully, non-zero if not |
526 | */ | 526 | */ |
527 | 527 | ||
528 | int tipc_bcbearer_send(struct sk_buff *buf, | 528 | static int tipc_bcbearer_send(struct sk_buff *buf, |
529 | struct tipc_bearer *unused1, | 529 | struct tipc_bearer *unused1, |
530 | struct tipc_media_addr *unused2) | 530 | struct tipc_media_addr *unused2) |
531 | { | 531 | { |
532 | static int send_count = 0; | 532 | static int send_count = 0; |
533 | 533 | ||
534 | struct node_map remains; | 534 | struct node_map *remains; |
535 | struct node_map remains_new; | 535 | struct node_map *remains_new; |
536 | struct node_map *remains_tmp; | ||
536 | int bp_index; | 537 | int bp_index; |
537 | int swap_time; | 538 | int swap_time; |
539 | int err; | ||
538 | 540 | ||
539 | /* Prepare buffer for broadcasting (if first time trying to send it) */ | 541 | /* Prepare buffer for broadcasting (if first time trying to send it) */ |
540 | 542 | ||
@@ -555,7 +557,9 @@ int tipc_bcbearer_send(struct sk_buff *buf, | |||
555 | 557 | ||
556 | /* Send buffer over bearers until all targets reached */ | 558 | /* Send buffer over bearers until all targets reached */ |
557 | 559 | ||
558 | remains = tipc_cltr_bcast_nodes; | 560 | remains = kmalloc(sizeof(struct node_map), GFP_ATOMIC); |
561 | remains_new = kmalloc(sizeof(struct node_map), GFP_ATOMIC); | ||
562 | *remains = tipc_cltr_bcast_nodes; | ||
559 | 563 | ||
560 | for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) { | 564 | for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) { |
561 | struct bearer *p = bcbearer->bpairs[bp_index].primary; | 565 | struct bearer *p = bcbearer->bpairs[bp_index].primary; |
@@ -564,8 +568,8 @@ int tipc_bcbearer_send(struct sk_buff *buf, | |||
564 | if (!p) | 568 | if (!p) |
565 | break; /* no more bearers to try */ | 569 | break; /* no more bearers to try */ |
566 | 570 | ||
567 | tipc_nmap_diff(&remains, &p->nodes, &remains_new); | 571 | tipc_nmap_diff(remains, &p->nodes, remains_new); |
568 | if (remains_new.count == remains.count) | 572 | if (remains_new->count == remains->count) |
569 | continue; /* bearer pair doesn't add anything */ | 573 | continue; /* bearer pair doesn't add anything */ |
570 | 574 | ||
571 | if (!p->publ.blocked && | 575 | if (!p->publ.blocked && |
@@ -583,17 +587,27 @@ swap: | |||
583 | bcbearer->bpairs[bp_index].primary = s; | 587 | bcbearer->bpairs[bp_index].primary = s; |
584 | bcbearer->bpairs[bp_index].secondary = p; | 588 | bcbearer->bpairs[bp_index].secondary = p; |
585 | update: | 589 | update: |
586 | if (remains_new.count == 0) | 590 | if (remains_new->count == 0) { |
587 | return TIPC_OK; | 591 | err = TIPC_OK; |
592 | goto out; | ||
593 | } | ||
588 | 594 | ||
595 | /* swap map */ | ||
596 | remains_tmp = remains; | ||
589 | remains = remains_new; | 597 | remains = remains_new; |
598 | remains_new = remains_tmp; | ||
590 | } | 599 | } |
591 | 600 | ||
592 | /* Unable to reach all targets */ | 601 | /* Unable to reach all targets */ |
593 | 602 | ||
594 | bcbearer->bearer.publ.blocked = 1; | 603 | bcbearer->bearer.publ.blocked = 1; |
595 | bcl->stats.bearer_congs++; | 604 | bcl->stats.bearer_congs++; |
596 | return ~TIPC_OK; | 605 | err = ~TIPC_OK; |
606 | |||
607 | out: | ||
608 | kfree(remains_new); | ||
609 | kfree(remains); | ||
610 | return err; | ||
597 | } | 611 | } |
598 | 612 | ||
599 | /** | 613 | /** |
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 64dcb0f3a8b2..e213a8e54855 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c | |||
@@ -45,10 +45,10 @@ | |||
45 | 45 | ||
46 | #define MAX_ADDR_STR 32 | 46 | #define MAX_ADDR_STR 32 |
47 | 47 | ||
48 | static struct media *media_list = 0; | 48 | static struct media *media_list = NULL; |
49 | static u32 media_count = 0; | 49 | static u32 media_count = 0; |
50 | 50 | ||
51 | struct bearer *tipc_bearers = 0; | 51 | struct bearer *tipc_bearers = NULL; |
52 | 52 | ||
53 | /** | 53 | /** |
54 | * media_name_valid - validate media name | 54 | * media_name_valid - validate media name |
@@ -79,7 +79,7 @@ static struct media *media_find(const char *name) | |||
79 | if (!strcmp(m_ptr->name, name)) | 79 | if (!strcmp(m_ptr->name, name)) |
80 | return m_ptr; | 80 | return m_ptr; |
81 | } | 81 | } |
82 | return 0; | 82 | return NULL; |
83 | } | 83 | } |
84 | 84 | ||
85 | /** | 85 | /** |
@@ -287,7 +287,7 @@ static struct bearer *bearer_find(const char *name) | |||
287 | if (b_ptr->active && (!strcmp(b_ptr->publ.name, name))) | 287 | if (b_ptr->active && (!strcmp(b_ptr->publ.name, name))) |
288 | return b_ptr; | 288 | return b_ptr; |
289 | } | 289 | } |
290 | return 0; | 290 | return NULL; |
291 | } | 291 | } |
292 | 292 | ||
293 | /** | 293 | /** |
@@ -307,7 +307,7 @@ struct bearer *tipc_bearer_find_interface(const char *if_name) | |||
307 | if (!strcmp(b_if_name, if_name)) | 307 | if (!strcmp(b_if_name, if_name)) |
308 | return b_ptr; | 308 | return b_ptr; |
309 | } | 309 | } |
310 | return 0; | 310 | return NULL; |
311 | } | 311 | } |
312 | 312 | ||
313 | /** | 313 | /** |
@@ -569,7 +569,7 @@ failed: | |||
569 | 569 | ||
570 | int tipc_block_bearer(const char *name) | 570 | int tipc_block_bearer(const char *name) |
571 | { | 571 | { |
572 | struct bearer *b_ptr = 0; | 572 | struct bearer *b_ptr = NULL; |
573 | struct link *l_ptr; | 573 | struct link *l_ptr; |
574 | struct link *temp_l_ptr; | 574 | struct link *temp_l_ptr; |
575 | 575 | ||
@@ -666,8 +666,8 @@ int tipc_bearer_init(void) | |||
666 | } else { | 666 | } else { |
667 | kfree(tipc_bearers); | 667 | kfree(tipc_bearers); |
668 | kfree(media_list); | 668 | kfree(media_list); |
669 | tipc_bearers = 0; | 669 | tipc_bearers = NULL; |
670 | media_list = 0; | 670 | media_list = NULL; |
671 | res = -ENOMEM; | 671 | res = -ENOMEM; |
672 | } | 672 | } |
673 | write_unlock_bh(&tipc_net_lock); | 673 | write_unlock_bh(&tipc_net_lock); |
@@ -691,8 +691,8 @@ void tipc_bearer_stop(void) | |||
691 | } | 691 | } |
692 | kfree(tipc_bearers); | 692 | kfree(tipc_bearers); |
693 | kfree(media_list); | 693 | kfree(media_list); |
694 | tipc_bearers = 0; | 694 | tipc_bearers = NULL; |
695 | media_list = 0; | 695 | media_list = NULL; |
696 | media_count = 0; | 696 | media_count = 0; |
697 | } | 697 | } |
698 | 698 | ||
diff --git a/net/tipc/cluster.c b/net/tipc/cluster.c index ab974ca19371..1aed81584e96 100644 --- a/net/tipc/cluster.c +++ b/net/tipc/cluster.c | |||
@@ -44,11 +44,11 @@ | |||
44 | #include "msg.h" | 44 | #include "msg.h" |
45 | #include "bearer.h" | 45 | #include "bearer.h" |
46 | 46 | ||
47 | void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf, | 47 | static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf, |
48 | u32 lower, u32 upper); | 48 | u32 lower, u32 upper); |
49 | struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest); | 49 | static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest); |
50 | 50 | ||
51 | struct node **tipc_local_nodes = 0; | 51 | struct node **tipc_local_nodes = NULL; |
52 | struct node_map tipc_cltr_bcast_nodes = {0,{0,}}; | 52 | struct node_map tipc_cltr_bcast_nodes = {0,{0,}}; |
53 | u32 tipc_highest_allowed_slave = 0; | 53 | u32 tipc_highest_allowed_slave = 0; |
54 | 54 | ||
@@ -61,7 +61,7 @@ struct cluster *tipc_cltr_create(u32 addr) | |||
61 | 61 | ||
62 | c_ptr = (struct cluster *)kmalloc(sizeof(*c_ptr), GFP_ATOMIC); | 62 | c_ptr = (struct cluster *)kmalloc(sizeof(*c_ptr), GFP_ATOMIC); |
63 | if (c_ptr == NULL) | 63 | if (c_ptr == NULL) |
64 | return 0; | 64 | return NULL; |
65 | memset(c_ptr, 0, sizeof(*c_ptr)); | 65 | memset(c_ptr, 0, sizeof(*c_ptr)); |
66 | 66 | ||
67 | c_ptr->addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0); | 67 | c_ptr->addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0); |
@@ -73,7 +73,7 @@ struct cluster *tipc_cltr_create(u32 addr) | |||
73 | c_ptr->nodes = (struct node **)kmalloc(alloc, GFP_ATOMIC); | 73 | c_ptr->nodes = (struct node **)kmalloc(alloc, GFP_ATOMIC); |
74 | if (c_ptr->nodes == NULL) { | 74 | if (c_ptr->nodes == NULL) { |
75 | kfree(c_ptr); | 75 | kfree(c_ptr); |
76 | return 0; | 76 | return NULL; |
77 | } | 77 | } |
78 | memset(c_ptr->nodes, 0, alloc); | 78 | memset(c_ptr->nodes, 0, alloc); |
79 | if (in_own_cluster(addr)) | 79 | if (in_own_cluster(addr)) |
@@ -91,7 +91,7 @@ struct cluster *tipc_cltr_create(u32 addr) | |||
91 | } | 91 | } |
92 | else { | 92 | else { |
93 | kfree(c_ptr); | 93 | kfree(c_ptr); |
94 | c_ptr = 0; | 94 | c_ptr = NULL; |
95 | } | 95 | } |
96 | 96 | ||
97 | return c_ptr; | 97 | return c_ptr; |
@@ -204,7 +204,7 @@ struct node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector) | |||
204 | 204 | ||
205 | assert(!in_own_cluster(c_ptr->addr)); | 205 | assert(!in_own_cluster(c_ptr->addr)); |
206 | if (!c_ptr->highest_node) | 206 | if (!c_ptr->highest_node) |
207 | return 0; | 207 | return NULL; |
208 | 208 | ||
209 | /* Start entry must be random */ | 209 | /* Start entry must be random */ |
210 | while (mask > c_ptr->highest_node) { | 210 | while (mask > c_ptr->highest_node) { |
@@ -222,14 +222,14 @@ struct node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector) | |||
222 | if (tipc_node_has_active_links(c_ptr->nodes[n_num])) | 222 | if (tipc_node_has_active_links(c_ptr->nodes[n_num])) |
223 | return c_ptr->nodes[n_num]; | 223 | return c_ptr->nodes[n_num]; |
224 | } | 224 | } |
225 | return 0; | 225 | return NULL; |
226 | } | 226 | } |
227 | 227 | ||
228 | /* | 228 | /* |
229 | * Routing table management: See description in node.c | 229 | * Routing table management: See description in node.c |
230 | */ | 230 | */ |
231 | 231 | ||
232 | struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest) | 232 | static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest) |
233 | { | 233 | { |
234 | u32 size = INT_H_SIZE + data_size; | 234 | u32 size = INT_H_SIZE + data_size; |
235 | struct sk_buff *buf = buf_acquire(size); | 235 | struct sk_buff *buf = buf_acquire(size); |
@@ -495,7 +495,7 @@ void tipc_cltr_remove_as_router(struct cluster *c_ptr, u32 router) | |||
495 | * tipc_cltr_multicast - multicast message to local nodes | 495 | * tipc_cltr_multicast - multicast message to local nodes |
496 | */ | 496 | */ |
497 | 497 | ||
498 | void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf, | 498 | static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf, |
499 | u32 lower, u32 upper) | 499 | u32 lower, u32 upper) |
500 | { | 500 | { |
501 | struct sk_buff *buf_copy; | 501 | struct sk_buff *buf_copy; |
diff --git a/net/tipc/cluster.h b/net/tipc/cluster.h index 9963642e1058..1b4cd309495a 100644 --- a/net/tipc/cluster.h +++ b/net/tipc/cluster.h | |||
@@ -86,7 +86,7 @@ static inline struct cluster *tipc_cltr_find(u32 addr) | |||
86 | 86 | ||
87 | if (z_ptr) | 87 | if (z_ptr) |
88 | return z_ptr->clusters[1]; | 88 | return z_ptr->clusters[1]; |
89 | return 0; | 89 | return NULL; |
90 | } | 90 | } |
91 | 91 | ||
92 | #endif | 92 | #endif |
diff --git a/net/tipc/config.c b/net/tipc/config.c index 3c8e6740e5ae..48b5de2dbe60 100644 --- a/net/tipc/config.c +++ b/net/tipc/config.c | |||
@@ -683,11 +683,11 @@ int tipc_cfg_init(void) | |||
683 | memset(&mng, 0, sizeof(mng)); | 683 | memset(&mng, 0, sizeof(mng)); |
684 | INIT_LIST_HEAD(&mng.link_subscribers); | 684 | INIT_LIST_HEAD(&mng.link_subscribers); |
685 | 685 | ||
686 | res = tipc_attach(&mng.user_ref, 0, 0); | 686 | res = tipc_attach(&mng.user_ref, NULL, NULL); |
687 | if (res) | 687 | if (res) |
688 | goto failed; | 688 | goto failed; |
689 | 689 | ||
690 | res = tipc_createport(mng.user_ref, 0, TIPC_CRITICAL_IMPORTANCE, | 690 | res = tipc_createport(mng.user_ref, NULL, TIPC_CRITICAL_IMPORTANCE, |
691 | NULL, NULL, NULL, | 691 | NULL, NULL, NULL, |
692 | NULL, cfg_named_msg_event, NULL, | 692 | NULL, cfg_named_msg_event, NULL, |
693 | NULL, &mng.port_ref); | 693 | NULL, &mng.port_ref); |
diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c index 4f4beefa7830..26ef95d5fe38 100644 --- a/net/tipc/dbg.c +++ b/net/tipc/dbg.c | |||
@@ -81,7 +81,7 @@ void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 sz) | |||
81 | 81 | ||
82 | pb->crs = pb->buf = raw; | 82 | pb->crs = pb->buf = raw; |
83 | pb->size = sz; | 83 | pb->size = sz; |
84 | pb->next = 0; | 84 | pb->next = NULL; |
85 | pb->buf[0] = 0; | 85 | pb->buf[0] = 0; |
86 | pb->buf[sz-1] = ~0; | 86 | pb->buf[sz-1] = ~0; |
87 | } | 87 | } |
@@ -216,7 +216,7 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...) | |||
216 | } | 216 | } |
217 | } | 217 | } |
218 | pb_next = pb->next; | 218 | pb_next = pb->next; |
219 | pb->next = 0; | 219 | pb->next = NULL; |
220 | pb = pb_next; | 220 | pb = pb_next; |
221 | } | 221 | } |
222 | spin_unlock_bh(&print_lock); | 222 | spin_unlock_bh(&print_lock); |
diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 53ba4630c10d..92601385e5f5 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c | |||
@@ -110,10 +110,10 @@ void tipc_disc_link_event(u32 addr, char *name, int up) | |||
110 | * @b_ptr: ptr to bearer issuing message | 110 | * @b_ptr: ptr to bearer issuing message |
111 | */ | 111 | */ |
112 | 112 | ||
113 | struct sk_buff *tipc_disc_init_msg(u32 type, | 113 | static struct sk_buff *tipc_disc_init_msg(u32 type, |
114 | u32 req_links, | 114 | u32 req_links, |
115 | u32 dest_domain, | 115 | u32 dest_domain, |
116 | struct bearer *b_ptr) | 116 | struct bearer *b_ptr) |
117 | { | 117 | { |
118 | struct sk_buff *buf = buf_acquire(DSC_H_SIZE); | 118 | struct sk_buff *buf = buf_acquire(DSC_H_SIZE); |
119 | struct tipc_msg *msg; | 119 | struct tipc_msg *msg; |
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 1f8d83b9c8b4..7a252785f727 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c | |||
@@ -169,7 +169,7 @@ static int enable_bearer(struct tipc_bearer *tb_ptr) | |||
169 | 169 | ||
170 | static void disable_bearer(struct tipc_bearer *tb_ptr) | 170 | static void disable_bearer(struct tipc_bearer *tb_ptr) |
171 | { | 171 | { |
172 | ((struct eth_bearer *)tb_ptr->usr_handle)->bearer = 0; | 172 | ((struct eth_bearer *)tb_ptr->usr_handle)->bearer = NULL; |
173 | } | 173 | } |
174 | 174 | ||
175 | /** | 175 | /** |
@@ -285,7 +285,7 @@ void tipc_eth_media_stop(void) | |||
285 | for (i = 0; i < MAX_ETH_BEARERS ; i++) { | 285 | for (i = 0; i < MAX_ETH_BEARERS ; i++) { |
286 | if (eth_bearers[i].bearer) { | 286 | if (eth_bearers[i].bearer) { |
287 | eth_bearers[i].bearer->blocked = 1; | 287 | eth_bearers[i].bearer->blocked = 1; |
288 | eth_bearers[i].bearer = 0; | 288 | eth_bearers[i].bearer = NULL; |
289 | } | 289 | } |
290 | if (eth_bearers[i].dev) { | 290 | if (eth_bearers[i].dev) { |
291 | dev_remove_pack(ð_bearers[i].tipc_packet_type); | 291 | dev_remove_pack(ð_bearers[i].tipc_packet_type); |
diff --git a/net/tipc/link.c b/net/tipc/link.c index 511872afa459..910b37e5083d 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
@@ -157,13 +157,13 @@ static void link_print(struct link *l_ptr, struct print_buf *buf, | |||
157 | } \ | 157 | } \ |
158 | } while (0) | 158 | } while (0) |
159 | 159 | ||
160 | static inline void dbg_print_link(struct link *l_ptr, const char *str) | 160 | static void dbg_print_link(struct link *l_ptr, const char *str) |
161 | { | 161 | { |
162 | if (DBG_OUTPUT) | 162 | if (DBG_OUTPUT) |
163 | link_print(l_ptr, DBG_OUTPUT, str); | 163 | link_print(l_ptr, DBG_OUTPUT, str); |
164 | } | 164 | } |
165 | 165 | ||
166 | static inline void dbg_print_buf_chain(struct sk_buff *root_buf) | 166 | static void dbg_print_buf_chain(struct sk_buff *root_buf) |
167 | { | 167 | { |
168 | if (DBG_OUTPUT) { | 168 | if (DBG_OUTPUT) { |
169 | struct sk_buff *buf = root_buf; | 169 | struct sk_buff *buf = root_buf; |
@@ -176,50 +176,50 @@ static inline void dbg_print_buf_chain(struct sk_buff *root_buf) | |||
176 | } | 176 | } |
177 | 177 | ||
178 | /* | 178 | /* |
179 | * Simple inlined link routines | 179 | * Simple link routines |
180 | */ | 180 | */ |
181 | 181 | ||
182 | static inline unsigned int align(unsigned int i) | 182 | static unsigned int align(unsigned int i) |
183 | { | 183 | { |
184 | return (i + 3) & ~3u; | 184 | return (i + 3) & ~3u; |
185 | } | 185 | } |
186 | 186 | ||
187 | static inline int link_working_working(struct link *l_ptr) | 187 | static int link_working_working(struct link *l_ptr) |
188 | { | 188 | { |
189 | return (l_ptr->state == WORKING_WORKING); | 189 | return (l_ptr->state == WORKING_WORKING); |
190 | } | 190 | } |
191 | 191 | ||
192 | static inline int link_working_unknown(struct link *l_ptr) | 192 | static int link_working_unknown(struct link *l_ptr) |
193 | { | 193 | { |
194 | return (l_ptr->state == WORKING_UNKNOWN); | 194 | return (l_ptr->state == WORKING_UNKNOWN); |
195 | } | 195 | } |
196 | 196 | ||
197 | static inline int link_reset_unknown(struct link *l_ptr) | 197 | static int link_reset_unknown(struct link *l_ptr) |
198 | { | 198 | { |
199 | return (l_ptr->state == RESET_UNKNOWN); | 199 | return (l_ptr->state == RESET_UNKNOWN); |
200 | } | 200 | } |
201 | 201 | ||
202 | static inline int link_reset_reset(struct link *l_ptr) | 202 | static int link_reset_reset(struct link *l_ptr) |
203 | { | 203 | { |
204 | return (l_ptr->state == RESET_RESET); | 204 | return (l_ptr->state == RESET_RESET); |
205 | } | 205 | } |
206 | 206 | ||
207 | static inline int link_blocked(struct link *l_ptr) | 207 | static int link_blocked(struct link *l_ptr) |
208 | { | 208 | { |
209 | return (l_ptr->exp_msg_count || l_ptr->blocked); | 209 | return (l_ptr->exp_msg_count || l_ptr->blocked); |
210 | } | 210 | } |
211 | 211 | ||
212 | static inline int link_congested(struct link *l_ptr) | 212 | static int link_congested(struct link *l_ptr) |
213 | { | 213 | { |
214 | return (l_ptr->out_queue_size >= l_ptr->queue_limit[0]); | 214 | return (l_ptr->out_queue_size >= l_ptr->queue_limit[0]); |
215 | } | 215 | } |
216 | 216 | ||
217 | static inline u32 link_max_pkt(struct link *l_ptr) | 217 | static u32 link_max_pkt(struct link *l_ptr) |
218 | { | 218 | { |
219 | return l_ptr->max_pkt; | 219 | return l_ptr->max_pkt; |
220 | } | 220 | } |
221 | 221 | ||
222 | static inline void link_init_max_pkt(struct link *l_ptr) | 222 | static void link_init_max_pkt(struct link *l_ptr) |
223 | { | 223 | { |
224 | u32 max_pkt; | 224 | u32 max_pkt; |
225 | 225 | ||
@@ -236,20 +236,20 @@ static inline void link_init_max_pkt(struct link *l_ptr) | |||
236 | l_ptr->max_pkt_probes = 0; | 236 | l_ptr->max_pkt_probes = 0; |
237 | } | 237 | } |
238 | 238 | ||
239 | static inline u32 link_next_sent(struct link *l_ptr) | 239 | static u32 link_next_sent(struct link *l_ptr) |
240 | { | 240 | { |
241 | if (l_ptr->next_out) | 241 | if (l_ptr->next_out) |
242 | return msg_seqno(buf_msg(l_ptr->next_out)); | 242 | return msg_seqno(buf_msg(l_ptr->next_out)); |
243 | return mod(l_ptr->next_out_no); | 243 | return mod(l_ptr->next_out_no); |
244 | } | 244 | } |
245 | 245 | ||
246 | static inline u32 link_last_sent(struct link *l_ptr) | 246 | static u32 link_last_sent(struct link *l_ptr) |
247 | { | 247 | { |
248 | return mod(link_next_sent(l_ptr) - 1); | 248 | return mod(link_next_sent(l_ptr) - 1); |
249 | } | 249 | } |
250 | 250 | ||
251 | /* | 251 | /* |
252 | * Simple non-inlined link routines (i.e. referenced outside this file) | 252 | * Simple non-static link routines (i.e. referenced outside this file) |
253 | */ | 253 | */ |
254 | 254 | ||
255 | int tipc_link_is_up(struct link *l_ptr) | 255 | int tipc_link_is_up(struct link *l_ptr) |
@@ -396,7 +396,7 @@ static void link_timeout(struct link *l_ptr) | |||
396 | tipc_node_unlock(l_ptr->owner); | 396 | tipc_node_unlock(l_ptr->owner); |
397 | } | 397 | } |
398 | 398 | ||
399 | static inline void link_set_timer(struct link *l_ptr, u32 time) | 399 | static void link_set_timer(struct link *l_ptr, u32 time) |
400 | { | 400 | { |
401 | k_start_timer(&l_ptr->timer, time); | 401 | k_start_timer(&l_ptr->timer, time); |
402 | } | 402 | } |
@@ -573,7 +573,7 @@ void tipc_link_wakeup_ports(struct link *l_ptr, int all) | |||
573 | if (win <= 0) | 573 | if (win <= 0) |
574 | break; | 574 | break; |
575 | list_del_init(&p_ptr->wait_list); | 575 | list_del_init(&p_ptr->wait_list); |
576 | p_ptr->congested_link = 0; | 576 | p_ptr->congested_link = NULL; |
577 | assert(p_ptr->wakeup); | 577 | assert(p_ptr->wakeup); |
578 | spin_lock_bh(p_ptr->publ.lock); | 578 | spin_lock_bh(p_ptr->publ.lock); |
579 | p_ptr->publ.congested = 0; | 579 | p_ptr->publ.congested = 0; |
@@ -1004,9 +1004,9 @@ static int link_bundle_buf(struct link *l_ptr, | |||
1004 | return 1; | 1004 | return 1; |
1005 | } | 1005 | } |
1006 | 1006 | ||
1007 | static inline void link_add_to_outqueue(struct link *l_ptr, | 1007 | static void link_add_to_outqueue(struct link *l_ptr, |
1008 | struct sk_buff *buf, | 1008 | struct sk_buff *buf, |
1009 | struct tipc_msg *msg) | 1009 | struct tipc_msg *msg) |
1010 | { | 1010 | { |
1011 | u32 ack = mod(l_ptr->next_in_no - 1); | 1011 | u32 ack = mod(l_ptr->next_in_no - 1); |
1012 | u32 seqno = mod(l_ptr->next_out_no++); | 1012 | u32 seqno = mod(l_ptr->next_out_no++); |
@@ -1156,8 +1156,8 @@ int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector) | |||
1156 | * Link is locked. Returns user data length. | 1156 | * Link is locked. Returns user data length. |
1157 | */ | 1157 | */ |
1158 | 1158 | ||
1159 | static inline int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf, | 1159 | static int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf, |
1160 | u32 *used_max_pkt) | 1160 | u32 *used_max_pkt) |
1161 | { | 1161 | { |
1162 | struct tipc_msg *msg = buf_msg(buf); | 1162 | struct tipc_msg *msg = buf_msg(buf); |
1163 | int res = msg_data_sz(msg); | 1163 | int res = msg_data_sz(msg); |
@@ -1355,7 +1355,7 @@ again: | |||
1355 | fragm_crs = 0; | 1355 | fragm_crs = 0; |
1356 | fragm_rest = 0; | 1356 | fragm_rest = 0; |
1357 | sect_rest = 0; | 1357 | sect_rest = 0; |
1358 | sect_crs = 0; | 1358 | sect_crs = NULL; |
1359 | curr_sect = -1; | 1359 | curr_sect = -1; |
1360 | 1360 | ||
1361 | /* Prepare reusable fragment header: */ | 1361 | /* Prepare reusable fragment header: */ |
@@ -1549,7 +1549,7 @@ u32 tipc_link_push_packet(struct link *l_ptr) | |||
1549 | msg_dbg(buf_msg(buf), ">DEF-PROT>"); | 1549 | msg_dbg(buf_msg(buf), ">DEF-PROT>"); |
1550 | l_ptr->unacked_window = 0; | 1550 | l_ptr->unacked_window = 0; |
1551 | buf_discard(buf); | 1551 | buf_discard(buf); |
1552 | l_ptr->proto_msg_queue = 0; | 1552 | l_ptr->proto_msg_queue = NULL; |
1553 | return TIPC_OK; | 1553 | return TIPC_OK; |
1554 | } else { | 1554 | } else { |
1555 | msg_dbg(buf_msg(buf), "|>DEF-PROT>"); | 1555 | msg_dbg(buf_msg(buf), "|>DEF-PROT>"); |
@@ -1860,7 +1860,7 @@ u32 tipc_link_defer_pkt(struct sk_buff **head, | |||
1860 | struct sk_buff **tail, | 1860 | struct sk_buff **tail, |
1861 | struct sk_buff *buf) | 1861 | struct sk_buff *buf) |
1862 | { | 1862 | { |
1863 | struct sk_buff *prev = 0; | 1863 | struct sk_buff *prev = NULL; |
1864 | struct sk_buff *crs = *head; | 1864 | struct sk_buff *crs = *head; |
1865 | u32 seq_no = msg_seqno(buf_msg(buf)); | 1865 | u32 seq_no = msg_seqno(buf_msg(buf)); |
1866 | 1866 | ||
@@ -1953,7 +1953,7 @@ static void link_handle_out_of_seq_msg(struct link *l_ptr, | |||
1953 | void tipc_link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg, | 1953 | void tipc_link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg, |
1954 | u32 gap, u32 tolerance, u32 priority, u32 ack_mtu) | 1954 | u32 gap, u32 tolerance, u32 priority, u32 ack_mtu) |
1955 | { | 1955 | { |
1956 | struct sk_buff *buf = 0; | 1956 | struct sk_buff *buf = NULL; |
1957 | struct tipc_msg *msg = l_ptr->pmsg; | 1957 | struct tipc_msg *msg = l_ptr->pmsg; |
1958 | u32 msg_size = sizeof(l_ptr->proto_msg); | 1958 | u32 msg_size = sizeof(l_ptr->proto_msg); |
1959 | 1959 | ||
@@ -2426,7 +2426,7 @@ static int link_recv_changeover_msg(struct link **l_ptr, | |||
2426 | } | 2426 | } |
2427 | } | 2427 | } |
2428 | exit: | 2428 | exit: |
2429 | *buf = 0; | 2429 | *buf = NULL; |
2430 | buf_discard(tunnel_buf); | 2430 | buf_discard(tunnel_buf); |
2431 | return 0; | 2431 | return 0; |
2432 | } | 2432 | } |
@@ -2539,42 +2539,37 @@ exit: | |||
2539 | * pending message. This makes dynamic memory allocation unecessary. | 2539 | * pending message. This makes dynamic memory allocation unecessary. |
2540 | */ | 2540 | */ |
2541 | 2541 | ||
2542 | static inline u32 get_long_msg_seqno(struct sk_buff *buf) | 2542 | static void set_long_msg_seqno(struct sk_buff *buf, u32 seqno) |
2543 | { | ||
2544 | return msg_seqno(buf_msg(buf)); | ||
2545 | } | ||
2546 | |||
2547 | static inline void set_long_msg_seqno(struct sk_buff *buf, u32 seqno) | ||
2548 | { | 2543 | { |
2549 | msg_set_seqno(buf_msg(buf), seqno); | 2544 | msg_set_seqno(buf_msg(buf), seqno); |
2550 | } | 2545 | } |
2551 | 2546 | ||
2552 | static inline u32 get_fragm_size(struct sk_buff *buf) | 2547 | static u32 get_fragm_size(struct sk_buff *buf) |
2553 | { | 2548 | { |
2554 | return msg_ack(buf_msg(buf)); | 2549 | return msg_ack(buf_msg(buf)); |
2555 | } | 2550 | } |
2556 | 2551 | ||
2557 | static inline void set_fragm_size(struct sk_buff *buf, u32 sz) | 2552 | static void set_fragm_size(struct sk_buff *buf, u32 sz) |
2558 | { | 2553 | { |
2559 | msg_set_ack(buf_msg(buf), sz); | 2554 | msg_set_ack(buf_msg(buf), sz); |
2560 | } | 2555 | } |
2561 | 2556 | ||
2562 | static inline u32 get_expected_frags(struct sk_buff *buf) | 2557 | static u32 get_expected_frags(struct sk_buff *buf) |
2563 | { | 2558 | { |
2564 | return msg_bcast_ack(buf_msg(buf)); | 2559 | return msg_bcast_ack(buf_msg(buf)); |
2565 | } | 2560 | } |
2566 | 2561 | ||
2567 | static inline void set_expected_frags(struct sk_buff *buf, u32 exp) | 2562 | static void set_expected_frags(struct sk_buff *buf, u32 exp) |
2568 | { | 2563 | { |
2569 | msg_set_bcast_ack(buf_msg(buf), exp); | 2564 | msg_set_bcast_ack(buf_msg(buf), exp); |
2570 | } | 2565 | } |
2571 | 2566 | ||
2572 | static inline u32 get_timer_cnt(struct sk_buff *buf) | 2567 | static u32 get_timer_cnt(struct sk_buff *buf) |
2573 | { | 2568 | { |
2574 | return msg_reroute_cnt(buf_msg(buf)); | 2569 | return msg_reroute_cnt(buf_msg(buf)); |
2575 | } | 2570 | } |
2576 | 2571 | ||
2577 | static inline void incr_timer_cnt(struct sk_buff *buf) | 2572 | static void incr_timer_cnt(struct sk_buff *buf) |
2578 | { | 2573 | { |
2579 | msg_incr_reroute_cnt(buf_msg(buf)); | 2574 | msg_incr_reroute_cnt(buf_msg(buf)); |
2580 | } | 2575 | } |
@@ -2586,13 +2581,13 @@ static inline void incr_timer_cnt(struct sk_buff *buf) | |||
2586 | int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, | 2581 | int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, |
2587 | struct tipc_msg **m) | 2582 | struct tipc_msg **m) |
2588 | { | 2583 | { |
2589 | struct sk_buff *prev = 0; | 2584 | struct sk_buff *prev = NULL; |
2590 | struct sk_buff *fbuf = *fb; | 2585 | struct sk_buff *fbuf = *fb; |
2591 | struct tipc_msg *fragm = buf_msg(fbuf); | 2586 | struct tipc_msg *fragm = buf_msg(fbuf); |
2592 | struct sk_buff *pbuf = *pending; | 2587 | struct sk_buff *pbuf = *pending; |
2593 | u32 long_msg_seq_no = msg_long_msgno(fragm); | 2588 | u32 long_msg_seq_no = msg_long_msgno(fragm); |
2594 | 2589 | ||
2595 | *fb = 0; | 2590 | *fb = NULL; |
2596 | msg_dbg(fragm,"FRG<REC<"); | 2591 | msg_dbg(fragm,"FRG<REC<"); |
2597 | 2592 | ||
2598 | /* Is there an incomplete message waiting for this fragment? */ | 2593 | /* Is there an incomplete message waiting for this fragment? */ |
@@ -2670,8 +2665,8 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, | |||
2670 | 2665 | ||
2671 | static void link_check_defragm_bufs(struct link *l_ptr) | 2666 | static void link_check_defragm_bufs(struct link *l_ptr) |
2672 | { | 2667 | { |
2673 | struct sk_buff *prev = 0; | 2668 | struct sk_buff *prev = NULL; |
2674 | struct sk_buff *next = 0; | 2669 | struct sk_buff *next = NULL; |
2675 | struct sk_buff *buf = l_ptr->defragm_buf; | 2670 | struct sk_buff *buf = l_ptr->defragm_buf; |
2676 | 2671 | ||
2677 | if (!buf) | 2672 | if (!buf) |
@@ -2750,19 +2745,19 @@ static struct link *link_find_link(const char *name, struct node **node) | |||
2750 | struct link *l_ptr; | 2745 | struct link *l_ptr; |
2751 | 2746 | ||
2752 | if (!link_name_validate(name, &link_name_parts)) | 2747 | if (!link_name_validate(name, &link_name_parts)) |
2753 | return 0; | 2748 | return NULL; |
2754 | 2749 | ||
2755 | b_ptr = tipc_bearer_find_interface(link_name_parts.if_local); | 2750 | b_ptr = tipc_bearer_find_interface(link_name_parts.if_local); |
2756 | if (!b_ptr) | 2751 | if (!b_ptr) |
2757 | return 0; | 2752 | return NULL; |
2758 | 2753 | ||
2759 | *node = tipc_node_find(link_name_parts.addr_peer); | 2754 | *node = tipc_node_find(link_name_parts.addr_peer); |
2760 | if (!*node) | 2755 | if (!*node) |
2761 | return 0; | 2756 | return NULL; |
2762 | 2757 | ||
2763 | l_ptr = (*node)->links[b_ptr->identity]; | 2758 | l_ptr = (*node)->links[b_ptr->identity]; |
2764 | if (!l_ptr || strcmp(l_ptr->name, name)) | 2759 | if (!l_ptr || strcmp(l_ptr->name, name)) |
2765 | return 0; | 2760 | return NULL; |
2766 | 2761 | ||
2767 | return l_ptr; | 2762 | return l_ptr; |
2768 | } | 2763 | } |
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 830f90999041..953307a9df1d 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c | |||
@@ -168,8 +168,8 @@ void tipc_named_withdraw(struct publication *publ) | |||
168 | void tipc_named_node_up(unsigned long node) | 168 | void tipc_named_node_up(unsigned long node) |
169 | { | 169 | { |
170 | struct publication *publ; | 170 | struct publication *publ; |
171 | struct distr_item *item = 0; | 171 | struct distr_item *item = NULL; |
172 | struct sk_buff *buf = 0; | 172 | struct sk_buff *buf = NULL; |
173 | u32 left = 0; | 173 | u32 left = 0; |
174 | u32 rest; | 174 | u32 rest; |
175 | u32 max_item_buf; | 175 | u32 max_item_buf; |
@@ -200,7 +200,7 @@ void tipc_named_node_up(unsigned long node) | |||
200 | "<%u.%u.%u>\n", tipc_zone(node), | 200 | "<%u.%u.%u>\n", tipc_zone(node), |
201 | tipc_cluster(node), tipc_node(node)); | 201 | tipc_cluster(node), tipc_node(node)); |
202 | tipc_link_send(buf, node, node); | 202 | tipc_link_send(buf, node, node); |
203 | buf = 0; | 203 | buf = NULL; |
204 | } | 204 | } |
205 | } | 205 | } |
206 | exit: | 206 | exit: |
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 3f4b23bd08f7..d129422fc5c2 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c | |||
@@ -46,7 +46,7 @@ | |||
46 | #include "cluster.h" | 46 | #include "cluster.h" |
47 | #include "bcast.h" | 47 | #include "bcast.h" |
48 | 48 | ||
49 | int tipc_nametbl_size = 1024; /* must be a power of 2 */ | 49 | static int tipc_nametbl_size = 1024; /* must be a power of 2 */ |
50 | 50 | ||
51 | /** | 51 | /** |
52 | * struct sub_seq - container for all published instances of a name sequence | 52 | * struct sub_seq - container for all published instances of a name sequence |
@@ -104,7 +104,7 @@ static atomic_t rsv_publ_ok = ATOMIC_INIT(0); | |||
104 | rwlock_t tipc_nametbl_lock = RW_LOCK_UNLOCKED; | 104 | rwlock_t tipc_nametbl_lock = RW_LOCK_UNLOCKED; |
105 | 105 | ||
106 | 106 | ||
107 | static inline int hash(int x) | 107 | static int hash(int x) |
108 | { | 108 | { |
109 | return(x & (tipc_nametbl_size - 1)); | 109 | return(x & (tipc_nametbl_size - 1)); |
110 | } | 110 | } |
@@ -121,7 +121,7 @@ static struct publication *publ_create(u32 type, u32 lower, u32 upper, | |||
121 | (struct publication *)kmalloc(sizeof(*publ), GFP_ATOMIC); | 121 | (struct publication *)kmalloc(sizeof(*publ), GFP_ATOMIC); |
122 | if (publ == NULL) { | 122 | if (publ == NULL) { |
123 | warn("Memory squeeze; failed to create publication\n"); | 123 | warn("Memory squeeze; failed to create publication\n"); |
124 | return 0; | 124 | return NULL; |
125 | } | 125 | } |
126 | 126 | ||
127 | memset(publ, 0, sizeof(*publ)); | 127 | memset(publ, 0, sizeof(*publ)); |
@@ -142,7 +142,7 @@ static struct publication *publ_create(u32 type, u32 lower, u32 upper, | |||
142 | * tipc_subseq_alloc - allocate a specified number of sub-sequence structures | 142 | * tipc_subseq_alloc - allocate a specified number of sub-sequence structures |
143 | */ | 143 | */ |
144 | 144 | ||
145 | struct sub_seq *tipc_subseq_alloc(u32 cnt) | 145 | static struct sub_seq *tipc_subseq_alloc(u32 cnt) |
146 | { | 146 | { |
147 | u32 sz = cnt * sizeof(struct sub_seq); | 147 | u32 sz = cnt * sizeof(struct sub_seq); |
148 | struct sub_seq *sseq = (struct sub_seq *)kmalloc(sz, GFP_ATOMIC); | 148 | struct sub_seq *sseq = (struct sub_seq *)kmalloc(sz, GFP_ATOMIC); |
@@ -158,7 +158,7 @@ struct sub_seq *tipc_subseq_alloc(u32 cnt) | |||
158 | * Allocates a single sub-sequence structure and sets it to all 0's. | 158 | * Allocates a single sub-sequence structure and sets it to all 0's. |
159 | */ | 159 | */ |
160 | 160 | ||
161 | struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_head) | 161 | static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_head) |
162 | { | 162 | { |
163 | struct name_seq *nseq = | 163 | struct name_seq *nseq = |
164 | (struct name_seq *)kmalloc(sizeof(*nseq), GFP_ATOMIC); | 164 | (struct name_seq *)kmalloc(sizeof(*nseq), GFP_ATOMIC); |
@@ -168,7 +168,7 @@ struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_head) | |||
168 | warn("Memory squeeze; failed to create name sequence\n"); | 168 | warn("Memory squeeze; failed to create name sequence\n"); |
169 | kfree(nseq); | 169 | kfree(nseq); |
170 | kfree(sseq); | 170 | kfree(sseq); |
171 | return 0; | 171 | return NULL; |
172 | } | 172 | } |
173 | 173 | ||
174 | memset(nseq, 0, sizeof(*nseq)); | 174 | memset(nseq, 0, sizeof(*nseq)); |
@@ -190,8 +190,8 @@ struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_head) | |||
190 | * Very time-critical, so binary searches through sub-sequence array. | 190 | * Very time-critical, so binary searches through sub-sequence array. |
191 | */ | 191 | */ |
192 | 192 | ||
193 | static inline struct sub_seq *nameseq_find_subseq(struct name_seq *nseq, | 193 | static struct sub_seq *nameseq_find_subseq(struct name_seq *nseq, |
194 | u32 instance) | 194 | u32 instance) |
195 | { | 195 | { |
196 | struct sub_seq *sseqs = nseq->sseqs; | 196 | struct sub_seq *sseqs = nseq->sseqs; |
197 | int low = 0; | 197 | int low = 0; |
@@ -207,7 +207,7 @@ static inline struct sub_seq *nameseq_find_subseq(struct name_seq *nseq, | |||
207 | else | 207 | else |
208 | return &sseqs[mid]; | 208 | return &sseqs[mid]; |
209 | } | 209 | } |
210 | return 0; | 210 | return NULL; |
211 | } | 211 | } |
212 | 212 | ||
213 | /** | 213 | /** |
@@ -243,9 +243,9 @@ static u32 nameseq_locate_subseq(struct name_seq *nseq, u32 instance) | |||
243 | * tipc_nameseq_insert_publ - | 243 | * tipc_nameseq_insert_publ - |
244 | */ | 244 | */ |
245 | 245 | ||
246 | struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, | 246 | static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, |
247 | u32 type, u32 lower, u32 upper, | 247 | u32 type, u32 lower, u32 upper, |
248 | u32 scope, u32 node, u32 port, u32 key) | 248 | u32 scope, u32 node, u32 port, u32 key) |
249 | { | 249 | { |
250 | struct subscription *s; | 250 | struct subscription *s; |
251 | struct subscription *st; | 251 | struct subscription *st; |
@@ -263,7 +263,7 @@ struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, | |||
263 | 263 | ||
264 | if ((sseq->lower != lower) || (sseq->upper != upper)) { | 264 | if ((sseq->lower != lower) || (sseq->upper != upper)) { |
265 | warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper); | 265 | warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper); |
266 | return 0; | 266 | return NULL; |
267 | } | 267 | } |
268 | } else { | 268 | } else { |
269 | u32 inspos; | 269 | u32 inspos; |
@@ -278,7 +278,7 @@ struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, | |||
278 | if ((inspos < nseq->first_free) && | 278 | if ((inspos < nseq->first_free) && |
279 | (upper >= nseq->sseqs[inspos].lower)) { | 279 | (upper >= nseq->sseqs[inspos].lower)) { |
280 | warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper); | 280 | warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper); |
281 | return 0; | 281 | return NULL; |
282 | } | 282 | } |
283 | 283 | ||
284 | /* Ensure there is space for new sub-sequence */ | 284 | /* Ensure there is space for new sub-sequence */ |
@@ -294,7 +294,7 @@ struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, | |||
294 | nseq->alloc *= 2; | 294 | nseq->alloc *= 2; |
295 | } else { | 295 | } else { |
296 | warn("Memory squeeze; failed to create sub-sequence\n"); | 296 | warn("Memory squeeze; failed to create sub-sequence\n"); |
297 | return 0; | 297 | return NULL; |
298 | } | 298 | } |
299 | } | 299 | } |
300 | dbg("Have %u sseqs for type %u\n", nseq->alloc, type); | 300 | dbg("Have %u sseqs for type %u\n", nseq->alloc, type); |
@@ -319,7 +319,7 @@ struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, | |||
319 | 319 | ||
320 | publ = publ_create(type, lower, upper, scope, node, port, key); | 320 | publ = publ_create(type, lower, upper, scope, node, port, key); |
321 | if (!publ) | 321 | if (!publ) |
322 | return 0; | 322 | return NULL; |
323 | dbg("inserting publ %x, node=%x publ->node=%x, subscr->node=%x\n", | 323 | dbg("inserting publ %x, node=%x publ->node=%x, subscr->node=%x\n", |
324 | publ, node, publ->node, publ->subscr.node); | 324 | publ, node, publ->node, publ->subscr.node); |
325 | 325 | ||
@@ -369,8 +369,8 @@ struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, | |||
369 | * tipc_nameseq_remove_publ - | 369 | * tipc_nameseq_remove_publ - |
370 | */ | 370 | */ |
371 | 371 | ||
372 | struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst, | 372 | static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst, |
373 | u32 node, u32 ref, u32 key) | 373 | u32 node, u32 ref, u32 key) |
374 | { | 374 | { |
375 | struct publication *publ; | 375 | struct publication *publ; |
376 | struct publication *prev; | 376 | struct publication *prev; |
@@ -394,7 +394,7 @@ struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst, | |||
394 | i, &nseq->sseqs[i], nseq->sseqs[i].lower, | 394 | i, &nseq->sseqs[i], nseq->sseqs[i].lower, |
395 | nseq->sseqs[i].upper); | 395 | nseq->sseqs[i].upper); |
396 | } | 396 | } |
397 | return 0; | 397 | return NULL; |
398 | } | 398 | } |
399 | dbg("nameseq_remove: seq: %x, sseq %x, <%u,%u> key %u\n", | 399 | dbg("nameseq_remove: seq: %x, sseq %x, <%u,%u> key %u\n", |
400 | nseq, sseq, nseq->type, inst, key); | 400 | nseq, sseq, nseq->type, inst, key); |
@@ -413,7 +413,7 @@ struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst, | |||
413 | prev->zone_list_next = publ->zone_list_next; | 413 | prev->zone_list_next = publ->zone_list_next; |
414 | sseq->zone_list = publ->zone_list_next; | 414 | sseq->zone_list = publ->zone_list_next; |
415 | } else { | 415 | } else { |
416 | sseq->zone_list = 0; | 416 | sseq->zone_list = NULL; |
417 | } | 417 | } |
418 | 418 | ||
419 | if (in_own_cluster(node)) { | 419 | if (in_own_cluster(node)) { |
@@ -431,7 +431,7 @@ struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst, | |||
431 | prev->cluster_list_next = publ->cluster_list_next; | 431 | prev->cluster_list_next = publ->cluster_list_next; |
432 | sseq->cluster_list = publ->cluster_list_next; | 432 | sseq->cluster_list = publ->cluster_list_next; |
433 | } else { | 433 | } else { |
434 | sseq->cluster_list = 0; | 434 | sseq->cluster_list = NULL; |
435 | } | 435 | } |
436 | } | 436 | } |
437 | 437 | ||
@@ -450,7 +450,7 @@ struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst, | |||
450 | prev->node_list_next = publ->node_list_next; | 450 | prev->node_list_next = publ->node_list_next; |
451 | sseq->node_list = publ->node_list_next; | 451 | sseq->node_list = publ->node_list_next; |
452 | } else { | 452 | } else { |
453 | sseq->node_list = 0; | 453 | sseq->node_list = NULL; |
454 | } | 454 | } |
455 | } | 455 | } |
456 | assert(!publ->node || (publ->node == node)); | 456 | assert(!publ->node || (publ->node == node)); |
@@ -535,7 +535,7 @@ static struct name_seq *nametbl_find_seq(u32 type) | |||
535 | } | 535 | } |
536 | } | 536 | } |
537 | 537 | ||
538 | return 0; | 538 | return NULL; |
539 | }; | 539 | }; |
540 | 540 | ||
541 | struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper, | 541 | struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper, |
@@ -547,7 +547,7 @@ struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper, | |||
547 | if (lower > upper) { | 547 | if (lower > upper) { |
548 | warn("Failed to publish illegal <%u,%u,%u>\n", | 548 | warn("Failed to publish illegal <%u,%u,%u>\n", |
549 | type, lower, upper); | 549 | type, lower, upper); |
550 | return 0; | 550 | return NULL; |
551 | } | 551 | } |
552 | 552 | ||
553 | dbg("Publishing <%u,%u,%u> from %x\n", type, lower, upper, node); | 553 | dbg("Publishing <%u,%u,%u> from %x\n", type, lower, upper, node); |
@@ -556,7 +556,7 @@ struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper, | |||
556 | dbg("tipc_nametbl_insert_publ: created %x\n", seq); | 556 | dbg("tipc_nametbl_insert_publ: created %x\n", seq); |
557 | } | 557 | } |
558 | if (!seq) | 558 | if (!seq) |
559 | return 0; | 559 | return NULL; |
560 | 560 | ||
561 | assert(seq->type == type); | 561 | assert(seq->type == type); |
562 | return tipc_nameseq_insert_publ(seq, type, lower, upper, | 562 | return tipc_nameseq_insert_publ(seq, type, lower, upper, |
@@ -570,7 +570,7 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower, | |||
570 | struct name_seq *seq = nametbl_find_seq(type); | 570 | struct name_seq *seq = nametbl_find_seq(type); |
571 | 571 | ||
572 | if (!seq) | 572 | if (!seq) |
573 | return 0; | 573 | return NULL; |
574 | 574 | ||
575 | dbg("Withdrawing <%u,%u> from %x\n", type, lower, node); | 575 | dbg("Withdrawing <%u,%u> from %x\n", type, lower, node); |
576 | publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key); | 576 | publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key); |
@@ -594,7 +594,7 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower, | |||
594 | u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode) | 594 | u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode) |
595 | { | 595 | { |
596 | struct sub_seq *sseq; | 596 | struct sub_seq *sseq; |
597 | struct publication *publ = 0; | 597 | struct publication *publ = NULL; |
598 | struct name_seq *seq; | 598 | struct name_seq *seq; |
599 | u32 ref; | 599 | u32 ref; |
600 | 600 | ||
@@ -740,12 +740,12 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper, | |||
740 | if (table.local_publ_count >= tipc_max_publications) { | 740 | if (table.local_publ_count >= tipc_max_publications) { |
741 | warn("Failed publish: max %u local publication\n", | 741 | warn("Failed publish: max %u local publication\n", |
742 | tipc_max_publications); | 742 | tipc_max_publications); |
743 | return 0; | 743 | return NULL; |
744 | } | 744 | } |
745 | if ((type < TIPC_RESERVED_TYPES) && !atomic_read(&rsv_publ_ok)) { | 745 | if ((type < TIPC_RESERVED_TYPES) && !atomic_read(&rsv_publ_ok)) { |
746 | warn("Failed to publish reserved name <%u,%u,%u>\n", | 746 | warn("Failed to publish reserved name <%u,%u,%u>\n", |
747 | type, lower, upper); | 747 | type, lower, upper); |
748 | return 0; | 748 | return NULL; |
749 | } | 749 | } |
750 | 750 | ||
751 | write_lock_bh(&tipc_nametbl_lock); | 751 | write_lock_bh(&tipc_nametbl_lock); |
@@ -983,6 +983,7 @@ static void nametbl_list(struct print_buf *buf, u32 depth_info, | |||
983 | } | 983 | } |
984 | } | 984 | } |
985 | 985 | ||
986 | #if 0 | ||
986 | void tipc_nametbl_print(struct print_buf *buf, const char *str) | 987 | void tipc_nametbl_print(struct print_buf *buf, const char *str) |
987 | { | 988 | { |
988 | tipc_printf(buf, str); | 989 | tipc_printf(buf, str); |
@@ -990,6 +991,7 @@ void tipc_nametbl_print(struct print_buf *buf, const char *str) | |||
990 | nametbl_list(buf, 0, 0, 0, 0); | 991 | nametbl_list(buf, 0, 0, 0, 0); |
991 | read_unlock_bh(&tipc_nametbl_lock); | 992 | read_unlock_bh(&tipc_nametbl_lock); |
992 | } | 993 | } |
994 | #endif | ||
993 | 995 | ||
994 | #define MAX_NAME_TBL_QUERY 32768 | 996 | #define MAX_NAME_TBL_QUERY 32768 |
995 | 997 | ||
@@ -1023,10 +1025,12 @@ struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space) | |||
1023 | return buf; | 1025 | return buf; |
1024 | } | 1026 | } |
1025 | 1027 | ||
1028 | #if 0 | ||
1026 | void tipc_nametbl_dump(void) | 1029 | void tipc_nametbl_dump(void) |
1027 | { | 1030 | { |
1028 | nametbl_list(TIPC_CONS, 0, 0, 0, 0); | 1031 | nametbl_list(TIPC_CONS, 0, 0, 0, 0); |
1029 | } | 1032 | } |
1033 | #endif | ||
1030 | 1034 | ||
1031 | int tipc_nametbl_init(void) | 1035 | int tipc_nametbl_init(void) |
1032 | { | 1036 | { |
diff --git a/net/tipc/net.c b/net/tipc/net.c index 074891ad4f09..f7c8223ddf7d 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c | |||
@@ -116,7 +116,7 @@ | |||
116 | */ | 116 | */ |
117 | 117 | ||
118 | rwlock_t tipc_net_lock = RW_LOCK_UNLOCKED; | 118 | rwlock_t tipc_net_lock = RW_LOCK_UNLOCKED; |
119 | struct network tipc_net = { 0 }; | 119 | struct network tipc_net = { NULL }; |
120 | 120 | ||
121 | struct node *tipc_net_select_remote_node(u32 addr, u32 ref) | 121 | struct node *tipc_net_select_remote_node(u32 addr, u32 ref) |
122 | { | 122 | { |
@@ -128,13 +128,14 @@ u32 tipc_net_select_router(u32 addr, u32 ref) | |||
128 | return tipc_zone_select_router(tipc_net.zones[tipc_zone(addr)], addr, ref); | 128 | return tipc_zone_select_router(tipc_net.zones[tipc_zone(addr)], addr, ref); |
129 | } | 129 | } |
130 | 130 | ||
131 | 131 | #if 0 | |
132 | u32 tipc_net_next_node(u32 a) | 132 | u32 tipc_net_next_node(u32 a) |
133 | { | 133 | { |
134 | if (tipc_net.zones[tipc_zone(a)]) | 134 | if (tipc_net.zones[tipc_zone(a)]) |
135 | return tipc_zone_next_node(a); | 135 | return tipc_zone_next_node(a); |
136 | return 0; | 136 | return 0; |
137 | } | 137 | } |
138 | #endif | ||
138 | 139 | ||
139 | void tipc_net_remove_as_router(u32 router) | 140 | void tipc_net_remove_as_router(u32 router) |
140 | { | 141 | { |
@@ -181,7 +182,7 @@ static void net_stop(void) | |||
181 | tipc_zone_delete(tipc_net.zones[z_num]); | 182 | tipc_zone_delete(tipc_net.zones[z_num]); |
182 | } | 183 | } |
183 | kfree(tipc_net.zones); | 184 | kfree(tipc_net.zones); |
184 | tipc_net.zones = 0; | 185 | tipc_net.zones = NULL; |
185 | } | 186 | } |
186 | 187 | ||
187 | static void net_route_named_msg(struct sk_buff *buf) | 188 | static void net_route_named_msg(struct sk_buff *buf) |
diff --git a/net/tipc/node.c b/net/tipc/node.c index 6d65010e5fa1..0d5db06e203f 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c | |||
@@ -155,7 +155,7 @@ static void node_select_active_links(struct node *n_ptr) | |||
155 | u32 i; | 155 | u32 i; |
156 | u32 highest_prio = 0; | 156 | u32 highest_prio = 0; |
157 | 157 | ||
158 | active[0] = active[1] = 0; | 158 | active[0] = active[1] = NULL; |
159 | 159 | ||
160 | for (i = 0; i < MAX_BEARERS; i++) { | 160 | for (i = 0; i < MAX_BEARERS; i++) { |
161 | struct link *l_ptr = n_ptr->links[i]; | 161 | struct link *l_ptr = n_ptr->links[i]; |
@@ -214,7 +214,7 @@ int tipc_node_has_redundant_links(struct node *n_ptr) | |||
214 | (n_ptr->active_links[0] != n_ptr->active_links[1])); | 214 | (n_ptr->active_links[0] != n_ptr->active_links[1])); |
215 | } | 215 | } |
216 | 216 | ||
217 | int tipc_node_has_active_routes(struct node *n_ptr) | 217 | static int tipc_node_has_active_routes(struct node *n_ptr) |
218 | { | 218 | { |
219 | return (n_ptr && (n_ptr->last_router >= 0)); | 219 | return (n_ptr && (n_ptr->last_router >= 0)); |
220 | } | 220 | } |
@@ -240,7 +240,7 @@ struct node *tipc_node_attach_link(struct link *l_ptr) | |||
240 | 240 | ||
241 | err("Attempt to create third link to %s\n", | 241 | err("Attempt to create third link to %s\n", |
242 | addr_string_fill(addr_string, n_ptr->addr)); | 242 | addr_string_fill(addr_string, n_ptr->addr)); |
243 | return 0; | 243 | return NULL; |
244 | } | 244 | } |
245 | 245 | ||
246 | if (!n_ptr->links[bearer_id]) { | 246 | if (!n_ptr->links[bearer_id]) { |
@@ -253,12 +253,12 @@ struct node *tipc_node_attach_link(struct link *l_ptr) | |||
253 | l_ptr->b_ptr->publ.name, | 253 | l_ptr->b_ptr->publ.name, |
254 | addr_string_fill(addr_string, l_ptr->addr)); | 254 | addr_string_fill(addr_string, l_ptr->addr)); |
255 | } | 255 | } |
256 | return 0; | 256 | return NULL; |
257 | } | 257 | } |
258 | 258 | ||
259 | void tipc_node_detach_link(struct node *n_ptr, struct link *l_ptr) | 259 | void tipc_node_detach_link(struct node *n_ptr, struct link *l_ptr) |
260 | { | 260 | { |
261 | n_ptr->links[l_ptr->b_ptr->identity] = 0; | 261 | n_ptr->links[l_ptr->b_ptr->identity] = NULL; |
262 | tipc_net.zones[tipc_zone(l_ptr->addr)]->links--; | 262 | tipc_net.zones[tipc_zone(l_ptr->addr)]->links--; |
263 | n_ptr->link_cnt--; | 263 | n_ptr->link_cnt--; |
264 | } | 264 | } |
@@ -424,7 +424,7 @@ static void node_lost_contact(struct node *n_ptr) | |||
424 | 424 | ||
425 | /* Notify subscribers */ | 425 | /* Notify subscribers */ |
426 | list_for_each_entry_safe(ns, tns, &n_ptr->nsub, nodesub_list) { | 426 | list_for_each_entry_safe(ns, tns, &n_ptr->nsub, nodesub_list) { |
427 | ns->node = 0; | 427 | ns->node = NULL; |
428 | list_del_init(&ns->nodesub_list); | 428 | list_del_init(&ns->nodesub_list); |
429 | tipc_k_signal((Handler)ns->handle_node_down, | 429 | tipc_k_signal((Handler)ns->handle_node_down, |
430 | (unsigned long)ns->usr_handle); | 430 | (unsigned long)ns->usr_handle); |
@@ -443,7 +443,7 @@ struct node *tipc_node_select_next_hop(u32 addr, u32 selector) | |||
443 | u32 router_addr; | 443 | u32 router_addr; |
444 | 444 | ||
445 | if (!tipc_addr_domain_valid(addr)) | 445 | if (!tipc_addr_domain_valid(addr)) |
446 | return 0; | 446 | return NULL; |
447 | 447 | ||
448 | /* Look for direct link to destination processsor */ | 448 | /* Look for direct link to destination processsor */ |
449 | n_ptr = tipc_node_find(addr); | 449 | n_ptr = tipc_node_find(addr); |
@@ -452,7 +452,7 @@ struct node *tipc_node_select_next_hop(u32 addr, u32 selector) | |||
452 | 452 | ||
453 | /* Cluster local system nodes *must* have direct links */ | 453 | /* Cluster local system nodes *must* have direct links */ |
454 | if (!is_slave(addr) && in_own_cluster(addr)) | 454 | if (!is_slave(addr) && in_own_cluster(addr)) |
455 | return 0; | 455 | return NULL; |
456 | 456 | ||
457 | /* Look for cluster local router with direct link to node */ | 457 | /* Look for cluster local router with direct link to node */ |
458 | router_addr = tipc_node_select_router(n_ptr, selector); | 458 | router_addr = tipc_node_select_router(n_ptr, selector); |
@@ -462,7 +462,7 @@ struct node *tipc_node_select_next_hop(u32 addr, u32 selector) | |||
462 | /* Slave nodes can only be accessed within own cluster via a | 462 | /* Slave nodes can only be accessed within own cluster via a |
463 | known router with direct link -- if no router was found,give up */ | 463 | known router with direct link -- if no router was found,give up */ |
464 | if (is_slave(addr)) | 464 | if (is_slave(addr)) |
465 | return 0; | 465 | return NULL; |
466 | 466 | ||
467 | /* Inter zone/cluster -- find any direct link to remote cluster */ | 467 | /* Inter zone/cluster -- find any direct link to remote cluster */ |
468 | addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0); | 468 | addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0); |
@@ -475,7 +475,7 @@ struct node *tipc_node_select_next_hop(u32 addr, u32 selector) | |||
475 | if (router_addr) | 475 | if (router_addr) |
476 | return tipc_node_select(router_addr, selector); | 476 | return tipc_node_select(router_addr, selector); |
477 | 477 | ||
478 | return 0; | 478 | return NULL; |
479 | } | 479 | } |
480 | 480 | ||
481 | /** | 481 | /** |
diff --git a/net/tipc/node.h b/net/tipc/node.h index 29f7ae6992d4..781126e084ae 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h | |||
@@ -121,7 +121,7 @@ static inline struct node *tipc_node_find(u32 addr) | |||
121 | if (c_ptr) | 121 | if (c_ptr) |
122 | return c_ptr->nodes[tipc_node(addr)]; | 122 | return c_ptr->nodes[tipc_node(addr)]; |
123 | } | 123 | } |
124 | return 0; | 124 | return NULL; |
125 | } | 125 | } |
126 | 126 | ||
127 | static inline struct node *tipc_node_select(u32 addr, u32 selector) | 127 | static inline struct node *tipc_node_select(u32 addr, u32 selector) |
diff --git a/net/tipc/node_subscr.c b/net/tipc/node_subscr.c index afeea121d8be..cff4068cc755 100644 --- a/net/tipc/node_subscr.c +++ b/net/tipc/node_subscr.c | |||
@@ -47,7 +47,7 @@ | |||
47 | void tipc_nodesub_subscribe(struct node_subscr *node_sub, u32 addr, | 47 | void tipc_nodesub_subscribe(struct node_subscr *node_sub, u32 addr, |
48 | void *usr_handle, net_ev_handler handle_down) | 48 | void *usr_handle, net_ev_handler handle_down) |
49 | { | 49 | { |
50 | node_sub->node = 0; | 50 | node_sub->node = NULL; |
51 | if (addr == tipc_own_addr) | 51 | if (addr == tipc_own_addr) |
52 | return; | 52 | return; |
53 | if (!tipc_addr_node_valid(addr)) { | 53 | if (!tipc_addr_node_valid(addr)) { |
diff --git a/net/tipc/port.c b/net/tipc/port.c index 72aae52bfec1..67e96cb1e825 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c | |||
@@ -54,8 +54,8 @@ | |||
54 | 54 | ||
55 | #define MAX_REJECT_SIZE 1024 | 55 | #define MAX_REJECT_SIZE 1024 |
56 | 56 | ||
57 | static struct sk_buff *msg_queue_head = 0; | 57 | static struct sk_buff *msg_queue_head = NULL; |
58 | static struct sk_buff *msg_queue_tail = 0; | 58 | static struct sk_buff *msg_queue_tail = NULL; |
59 | 59 | ||
60 | spinlock_t tipc_port_list_lock = SPIN_LOCK_UNLOCKED; | 60 | spinlock_t tipc_port_list_lock = SPIN_LOCK_UNLOCKED; |
61 | static spinlock_t queue_lock = SPIN_LOCK_UNLOCKED; | 61 | static spinlock_t queue_lock = SPIN_LOCK_UNLOCKED; |
@@ -67,27 +67,22 @@ static struct sk_buff* port_build_peer_abort_msg(struct port *,u32 err); | |||
67 | static void port_timeout(unsigned long ref); | 67 | static void port_timeout(unsigned long ref); |
68 | 68 | ||
69 | 69 | ||
70 | static inline u32 port_peernode(struct port *p_ptr) | 70 | static u32 port_peernode(struct port *p_ptr) |
71 | { | 71 | { |
72 | return msg_destnode(&p_ptr->publ.phdr); | 72 | return msg_destnode(&p_ptr->publ.phdr); |
73 | } | 73 | } |
74 | 74 | ||
75 | static inline u32 port_peerport(struct port *p_ptr) | 75 | static u32 port_peerport(struct port *p_ptr) |
76 | { | 76 | { |
77 | return msg_destport(&p_ptr->publ.phdr); | 77 | return msg_destport(&p_ptr->publ.phdr); |
78 | } | 78 | } |
79 | 79 | ||
80 | static inline u32 port_out_seqno(struct port *p_ptr) | 80 | static u32 port_out_seqno(struct port *p_ptr) |
81 | { | 81 | { |
82 | return msg_transp_seqno(&p_ptr->publ.phdr); | 82 | return msg_transp_seqno(&p_ptr->publ.phdr); |
83 | } | 83 | } |
84 | 84 | ||
85 | static inline void port_set_out_seqno(struct port *p_ptr, u32 seqno) | 85 | static void port_incr_out_seqno(struct port *p_ptr) |
86 | { | ||
87 | msg_set_transp_seqno(&p_ptr->publ.phdr,seqno); | ||
88 | } | ||
89 | |||
90 | static inline void port_incr_out_seqno(struct port *p_ptr) | ||
91 | { | 86 | { |
92 | struct tipc_msg *m = &p_ptr->publ.phdr; | 87 | struct tipc_msg *m = &p_ptr->publ.phdr; |
93 | 88 | ||
@@ -258,11 +253,11 @@ u32 tipc_createport_raw(void *usr_handle, | |||
258 | p_ptr->publ.usr_handle = usr_handle; | 253 | p_ptr->publ.usr_handle = usr_handle; |
259 | INIT_LIST_HEAD(&p_ptr->wait_list); | 254 | INIT_LIST_HEAD(&p_ptr->wait_list); |
260 | INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list); | 255 | INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list); |
261 | p_ptr->congested_link = 0; | 256 | p_ptr->congested_link = NULL; |
262 | p_ptr->max_pkt = MAX_PKT_DEFAULT; | 257 | p_ptr->max_pkt = MAX_PKT_DEFAULT; |
263 | p_ptr->dispatcher = dispatcher; | 258 | p_ptr->dispatcher = dispatcher; |
264 | p_ptr->wakeup = wakeup; | 259 | p_ptr->wakeup = wakeup; |
265 | p_ptr->user_port = 0; | 260 | p_ptr->user_port = NULL; |
266 | k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref); | 261 | k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref); |
267 | spin_lock_bh(&tipc_port_list_lock); | 262 | spin_lock_bh(&tipc_port_list_lock); |
268 | INIT_LIST_HEAD(&p_ptr->publications); | 263 | INIT_LIST_HEAD(&p_ptr->publications); |
@@ -276,9 +271,9 @@ u32 tipc_createport_raw(void *usr_handle, | |||
276 | int tipc_deleteport(u32 ref) | 271 | int tipc_deleteport(u32 ref) |
277 | { | 272 | { |
278 | struct port *p_ptr; | 273 | struct port *p_ptr; |
279 | struct sk_buff *buf = 0; | 274 | struct sk_buff *buf = NULL; |
280 | 275 | ||
281 | tipc_withdraw(ref, 0, 0); | 276 | tipc_withdraw(ref, 0, NULL); |
282 | p_ptr = tipc_port_lock(ref); | 277 | p_ptr = tipc_port_lock(ref); |
283 | if (!p_ptr) | 278 | if (!p_ptr) |
284 | return -EINVAL; | 279 | return -EINVAL; |
@@ -329,13 +324,13 @@ void *tipc_get_handle(const u32 ref) | |||
329 | 324 | ||
330 | p_ptr = tipc_port_lock(ref); | 325 | p_ptr = tipc_port_lock(ref); |
331 | if (!p_ptr) | 326 | if (!p_ptr) |
332 | return 0; | 327 | return NULL; |
333 | handle = p_ptr->publ.usr_handle; | 328 | handle = p_ptr->publ.usr_handle; |
334 | tipc_port_unlock(p_ptr); | 329 | tipc_port_unlock(p_ptr); |
335 | return handle; | 330 | return handle; |
336 | } | 331 | } |
337 | 332 | ||
338 | static inline int port_unreliable(struct port *p_ptr) | 333 | static int port_unreliable(struct port *p_ptr) |
339 | { | 334 | { |
340 | return msg_src_droppable(&p_ptr->publ.phdr); | 335 | return msg_src_droppable(&p_ptr->publ.phdr); |
341 | } | 336 | } |
@@ -364,7 +359,7 @@ int tipc_set_portunreliable(u32 ref, unsigned int isunreliable) | |||
364 | return TIPC_OK; | 359 | return TIPC_OK; |
365 | } | 360 | } |
366 | 361 | ||
367 | static inline int port_unreturnable(struct port *p_ptr) | 362 | static int port_unreturnable(struct port *p_ptr) |
368 | { | 363 | { |
369 | return msg_dest_droppable(&p_ptr->publ.phdr); | 364 | return msg_dest_droppable(&p_ptr->publ.phdr); |
370 | } | 365 | } |
@@ -475,7 +470,7 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err) | |||
475 | 470 | ||
476 | /* send self-abort message when rejecting on a connected port */ | 471 | /* send self-abort message when rejecting on a connected port */ |
477 | if (msg_connected(msg)) { | 472 | if (msg_connected(msg)) { |
478 | struct sk_buff *abuf = 0; | 473 | struct sk_buff *abuf = NULL; |
479 | struct port *p_ptr = tipc_port_lock(msg_destport(msg)); | 474 | struct port *p_ptr = tipc_port_lock(msg_destport(msg)); |
480 | 475 | ||
481 | if (p_ptr) { | 476 | if (p_ptr) { |
@@ -510,7 +505,7 @@ int tipc_port_reject_sections(struct port *p_ptr, struct tipc_msg *hdr, | |||
510 | static void port_timeout(unsigned long ref) | 505 | static void port_timeout(unsigned long ref) |
511 | { | 506 | { |
512 | struct port *p_ptr = tipc_port_lock(ref); | 507 | struct port *p_ptr = tipc_port_lock(ref); |
513 | struct sk_buff *buf = 0; | 508 | struct sk_buff *buf = NULL; |
514 | 509 | ||
515 | if (!p_ptr || !p_ptr->publ.connected) | 510 | if (!p_ptr || !p_ptr->publ.connected) |
516 | return; | 511 | return; |
@@ -540,7 +535,7 @@ static void port_timeout(unsigned long ref) | |||
540 | static void port_handle_node_down(unsigned long ref) | 535 | static void port_handle_node_down(unsigned long ref) |
541 | { | 536 | { |
542 | struct port *p_ptr = tipc_port_lock(ref); | 537 | struct port *p_ptr = tipc_port_lock(ref); |
543 | struct sk_buff* buf = 0; | 538 | struct sk_buff* buf = NULL; |
544 | 539 | ||
545 | if (!p_ptr) | 540 | if (!p_ptr) |
546 | return; | 541 | return; |
@@ -555,7 +550,7 @@ static struct sk_buff *port_build_self_abort_msg(struct port *p_ptr, u32 err) | |||
555 | u32 imp = msg_importance(&p_ptr->publ.phdr); | 550 | u32 imp = msg_importance(&p_ptr->publ.phdr); |
556 | 551 | ||
557 | if (!p_ptr->publ.connected) | 552 | if (!p_ptr->publ.connected) |
558 | return 0; | 553 | return NULL; |
559 | if (imp < TIPC_CRITICAL_IMPORTANCE) | 554 | if (imp < TIPC_CRITICAL_IMPORTANCE) |
560 | imp++; | 555 | imp++; |
561 | return port_build_proto_msg(p_ptr->publ.ref, | 556 | return port_build_proto_msg(p_ptr->publ.ref, |
@@ -575,7 +570,7 @@ static struct sk_buff *port_build_peer_abort_msg(struct port *p_ptr, u32 err) | |||
575 | u32 imp = msg_importance(&p_ptr->publ.phdr); | 570 | u32 imp = msg_importance(&p_ptr->publ.phdr); |
576 | 571 | ||
577 | if (!p_ptr->publ.connected) | 572 | if (!p_ptr->publ.connected) |
578 | return 0; | 573 | return NULL; |
579 | if (imp < TIPC_CRITICAL_IMPORTANCE) | 574 | if (imp < TIPC_CRITICAL_IMPORTANCE) |
580 | imp++; | 575 | imp++; |
581 | return port_build_proto_msg(port_peerport(p_ptr), | 576 | return port_build_proto_msg(port_peerport(p_ptr), |
@@ -594,8 +589,8 @@ void tipc_port_recv_proto_msg(struct sk_buff *buf) | |||
594 | struct tipc_msg *msg = buf_msg(buf); | 589 | struct tipc_msg *msg = buf_msg(buf); |
595 | struct port *p_ptr = tipc_port_lock(msg_destport(msg)); | 590 | struct port *p_ptr = tipc_port_lock(msg_destport(msg)); |
596 | u32 err = TIPC_OK; | 591 | u32 err = TIPC_OK; |
597 | struct sk_buff *r_buf = 0; | 592 | struct sk_buff *r_buf = NULL; |
598 | struct sk_buff *abort_buf = 0; | 593 | struct sk_buff *abort_buf = NULL; |
599 | 594 | ||
600 | msg_dbg(msg, "PORT<RECV<:"); | 595 | msg_dbg(msg, "PORT<RECV<:"); |
601 | 596 | ||
@@ -804,7 +799,7 @@ static void port_dispatcher_sigh(void *dummy) | |||
804 | 799 | ||
805 | spin_lock_bh(&queue_lock); | 800 | spin_lock_bh(&queue_lock); |
806 | buf = msg_queue_head; | 801 | buf = msg_queue_head; |
807 | msg_queue_head = 0; | 802 | msg_queue_head = NULL; |
808 | spin_unlock_bh(&queue_lock); | 803 | spin_unlock_bh(&queue_lock); |
809 | 804 | ||
810 | while (buf) { | 805 | while (buf) { |
@@ -991,8 +986,8 @@ static void port_wakeup_sh(unsigned long ref) | |||
991 | { | 986 | { |
992 | struct port *p_ptr; | 987 | struct port *p_ptr; |
993 | struct user_port *up_ptr; | 988 | struct user_port *up_ptr; |
994 | tipc_continue_event cb = 0; | 989 | tipc_continue_event cb = NULL; |
995 | void *uh = 0; | 990 | void *uh = NULL; |
996 | 991 | ||
997 | p_ptr = tipc_port_lock(ref); | 992 | p_ptr = tipc_port_lock(ref); |
998 | if (p_ptr) { | 993 | if (p_ptr) { |
@@ -1016,7 +1011,7 @@ static void port_wakeup(struct tipc_port *p_ptr) | |||
1016 | void tipc_acknowledge(u32 ref, u32 ack) | 1011 | void tipc_acknowledge(u32 ref, u32 ack) |
1017 | { | 1012 | { |
1018 | struct port *p_ptr; | 1013 | struct port *p_ptr; |
1019 | struct sk_buff *buf = 0; | 1014 | struct sk_buff *buf = NULL; |
1020 | 1015 | ||
1021 | p_ptr = tipc_port_lock(ref); | 1016 | p_ptr = tipc_port_lock(ref); |
1022 | if (!p_ptr) | 1017 | if (!p_ptr) |
@@ -1062,7 +1057,7 @@ int tipc_createport(u32 user_ref, | |||
1062 | if (up_ptr == NULL) { | 1057 | if (up_ptr == NULL) { |
1063 | return -ENOMEM; | 1058 | return -ENOMEM; |
1064 | } | 1059 | } |
1065 | ref = tipc_createport_raw(0, port_dispatcher, port_wakeup, importance); | 1060 | ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup, importance); |
1066 | p_ptr = tipc_port_lock(ref); | 1061 | p_ptr = tipc_port_lock(ref); |
1067 | if (!p_ptr) { | 1062 | if (!p_ptr) { |
1068 | kfree(up_ptr); | 1063 | kfree(up_ptr); |
@@ -1273,7 +1268,7 @@ int tipc_disconnect(u32 ref) | |||
1273 | int tipc_shutdown(u32 ref) | 1268 | int tipc_shutdown(u32 ref) |
1274 | { | 1269 | { |
1275 | struct port *p_ptr; | 1270 | struct port *p_ptr; |
1276 | struct sk_buff *buf = 0; | 1271 | struct sk_buff *buf = NULL; |
1277 | 1272 | ||
1278 | p_ptr = tipc_port_lock(ref); | 1273 | p_ptr = tipc_port_lock(ref); |
1279 | if (!p_ptr) | 1274 | if (!p_ptr) |
diff --git a/net/tipc/ref.c b/net/tipc/ref.c index 5a13c2defe4a..33bbf5095094 100644 --- a/net/tipc/ref.c +++ b/net/tipc/ref.c | |||
@@ -61,7 +61,7 @@ | |||
61 | * because entry 0's reference field has the form XXXX|1--1. | 61 | * because entry 0's reference field has the form XXXX|1--1. |
62 | */ | 62 | */ |
63 | 63 | ||
64 | struct ref_table tipc_ref_table = { 0 }; | 64 | struct ref_table tipc_ref_table = { NULL }; |
65 | 65 | ||
66 | static rwlock_t ref_table_lock = RW_LOCK_UNLOCKED; | 66 | static rwlock_t ref_table_lock = RW_LOCK_UNLOCKED; |
67 | 67 | ||
@@ -86,7 +86,7 @@ int tipc_ref_table_init(u32 requested_size, u32 start) | |||
86 | write_lock_bh(&ref_table_lock); | 86 | write_lock_bh(&ref_table_lock); |
87 | index_mask = sz - 1; | 87 | index_mask = sz - 1; |
88 | for (i = sz - 1; i >= 0; i--) { | 88 | for (i = sz - 1; i >= 0; i--) { |
89 | table[i].object = 0; | 89 | table[i].object = NULL; |
90 | table[i].lock = SPIN_LOCK_UNLOCKED; | 90 | table[i].lock = SPIN_LOCK_UNLOCKED; |
91 | table[i].data.next_plus_upper = (start & ~index_mask) + i - 1; | 91 | table[i].data.next_plus_upper = (start & ~index_mask) + i - 1; |
92 | } | 92 | } |
@@ -108,7 +108,7 @@ void tipc_ref_table_stop(void) | |||
108 | return; | 108 | return; |
109 | 109 | ||
110 | vfree(tipc_ref_table.entries); | 110 | vfree(tipc_ref_table.entries); |
111 | tipc_ref_table.entries = 0; | 111 | tipc_ref_table.entries = NULL; |
112 | } | 112 | } |
113 | 113 | ||
114 | /** | 114 | /** |
@@ -173,7 +173,7 @@ void tipc_ref_discard(u32 ref) | |||
173 | assert(entry->data.reference == ref); | 173 | assert(entry->data.reference == ref); |
174 | 174 | ||
175 | /* mark entry as unused */ | 175 | /* mark entry as unused */ |
176 | entry->object = 0; | 176 | entry->object = NULL; |
177 | if (tipc_ref_table.first_free == 0) | 177 | if (tipc_ref_table.first_free == 0) |
178 | tipc_ref_table.first_free = index; | 178 | tipc_ref_table.first_free = index; |
179 | else | 179 | else |
diff --git a/net/tipc/ref.h b/net/tipc/ref.h index 4f8f9f40dcac..6d20006be45b 100644 --- a/net/tipc/ref.h +++ b/net/tipc/ref.h | |||
@@ -92,7 +92,7 @@ static inline void *tipc_ref_lock(u32 ref) | |||
92 | return r->object; | 92 | return r->object; |
93 | spin_unlock_bh(&r->lock); | 93 | spin_unlock_bh(&r->lock); |
94 | } | 94 | } |
95 | return 0; | 95 | return NULL; |
96 | } | 96 | } |
97 | 97 | ||
98 | /** | 98 | /** |
@@ -125,7 +125,7 @@ static inline void *tipc_ref_deref(u32 ref) | |||
125 | if (likely(r->data.reference == ref)) | 125 | if (likely(r->data.reference == ref)) |
126 | return r->object; | 126 | return r->object; |
127 | } | 127 | } |
128 | return 0; | 128 | return NULL; |
129 | } | 129 | } |
130 | 130 | ||
131 | #endif | 131 | #endif |
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 67253bfcd702..648a734e6044 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -88,7 +88,7 @@ static atomic_t tipc_queue_size = ATOMIC_INIT(0); | |||
88 | * with non-socket interfaces. | 88 | * with non-socket interfaces. |
89 | * See net.c for description of locking policy. | 89 | * See net.c for description of locking policy. |
90 | */ | 90 | */ |
91 | static inline void sock_lock(struct tipc_sock* tsock) | 91 | static void sock_lock(struct tipc_sock* tsock) |
92 | { | 92 | { |
93 | spin_lock_bh(tsock->p->lock); | 93 | spin_lock_bh(tsock->p->lock); |
94 | } | 94 | } |
@@ -96,7 +96,7 @@ static inline void sock_lock(struct tipc_sock* tsock) | |||
96 | /* | 96 | /* |
97 | * sock_unlock(): Unlock a port/socket pair | 97 | * sock_unlock(): Unlock a port/socket pair |
98 | */ | 98 | */ |
99 | static inline void sock_unlock(struct tipc_sock* tsock) | 99 | static void sock_unlock(struct tipc_sock* tsock) |
100 | { | 100 | { |
101 | spin_unlock_bh(tsock->p->lock); | 101 | spin_unlock_bh(tsock->p->lock); |
102 | } | 102 | } |
@@ -119,7 +119,7 @@ static inline void sock_unlock(struct tipc_sock* tsock) | |||
119 | * Returns pollmask value | 119 | * Returns pollmask value |
120 | */ | 120 | */ |
121 | 121 | ||
122 | static inline u32 pollmask(struct socket *sock) | 122 | static u32 pollmask(struct socket *sock) |
123 | { | 123 | { |
124 | u32 mask; | 124 | u32 mask; |
125 | 125 | ||
@@ -144,7 +144,7 @@ static inline u32 pollmask(struct socket *sock) | |||
144 | * @tsock: TIPC socket | 144 | * @tsock: TIPC socket |
145 | */ | 145 | */ |
146 | 146 | ||
147 | static inline void advance_queue(struct tipc_sock *tsock) | 147 | static void advance_queue(struct tipc_sock *tsock) |
148 | { | 148 | { |
149 | sock_lock(tsock); | 149 | sock_lock(tsock); |
150 | buf_discard(skb_dequeue(&tsock->sk.sk_receive_queue)); | 150 | buf_discard(skb_dequeue(&tsock->sk.sk_receive_queue)); |
@@ -178,7 +178,7 @@ static int tipc_create(struct socket *sock, int protocol) | |||
178 | if (unlikely(protocol != 0)) | 178 | if (unlikely(protocol != 0)) |
179 | return -EPROTONOSUPPORT; | 179 | return -EPROTONOSUPPORT; |
180 | 180 | ||
181 | ref = tipc_createport_raw(0, &dispatch, &wakeupdispatch, TIPC_LOW_IMPORTANCE); | 181 | ref = tipc_createport_raw(NULL, &dispatch, &wakeupdispatch, TIPC_LOW_IMPORTANCE); |
182 | if (unlikely(!ref)) | 182 | if (unlikely(!ref)) |
183 | return -ENOMEM; | 183 | return -ENOMEM; |
184 | 184 | ||
@@ -265,7 +265,7 @@ static int release(struct socket *sock) | |||
265 | sock_lock(tsock); | 265 | sock_lock(tsock); |
266 | buf = skb_dequeue(&sk->sk_receive_queue); | 266 | buf = skb_dequeue(&sk->sk_receive_queue); |
267 | if (!buf) | 267 | if (!buf) |
268 | tsock->p->usr_handle = 0; | 268 | tsock->p->usr_handle = NULL; |
269 | sock_unlock(tsock); | 269 | sock_unlock(tsock); |
270 | if (!buf) | 270 | if (!buf) |
271 | break; | 271 | break; |
@@ -319,7 +319,7 @@ static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len) | |||
319 | return -ERESTARTSYS; | 319 | return -ERESTARTSYS; |
320 | 320 | ||
321 | if (unlikely(!uaddr_len)) { | 321 | if (unlikely(!uaddr_len)) { |
322 | res = tipc_withdraw(tsock->p->ref, 0, 0); | 322 | res = tipc_withdraw(tsock->p->ref, 0, NULL); |
323 | goto exit; | 323 | goto exit; |
324 | } | 324 | } |
325 | 325 | ||
@@ -412,7 +412,7 @@ static unsigned int poll(struct file *file, struct socket *sock, | |||
412 | * Returns 0 if permission is granted, otherwise errno | 412 | * Returns 0 if permission is granted, otherwise errno |
413 | */ | 413 | */ |
414 | 414 | ||
415 | static inline int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) | 415 | static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) |
416 | { | 416 | { |
417 | struct tipc_cfg_msg_hdr hdr; | 417 | struct tipc_cfg_msg_hdr hdr; |
418 | 418 | ||
@@ -695,7 +695,7 @@ static int auto_connect(struct socket *sock, struct tipc_sock *tsock, | |||
695 | * Note: Address is not captured if not requested by receiver. | 695 | * Note: Address is not captured if not requested by receiver. |
696 | */ | 696 | */ |
697 | 697 | ||
698 | static inline void set_orig_addr(struct msghdr *m, struct tipc_msg *msg) | 698 | static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg) |
699 | { | 699 | { |
700 | struct sockaddr_tipc *addr = (struct sockaddr_tipc *)m->msg_name; | 700 | struct sockaddr_tipc *addr = (struct sockaddr_tipc *)m->msg_name; |
701 | 701 | ||
@@ -721,7 +721,7 @@ static inline void set_orig_addr(struct msghdr *m, struct tipc_msg *msg) | |||
721 | * Returns 0 if successful, otherwise errno | 721 | * Returns 0 if successful, otherwise errno |
722 | */ | 722 | */ |
723 | 723 | ||
724 | static inline int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, | 724 | static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, |
725 | struct tipc_port *tport) | 725 | struct tipc_port *tport) |
726 | { | 726 | { |
727 | u32 anc_data[3]; | 727 | u32 anc_data[3]; |
@@ -1226,7 +1226,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
1226 | { | 1226 | { |
1227 | struct tipc_sock *tsock = tipc_sk(sock->sk); | 1227 | struct tipc_sock *tsock = tipc_sk(sock->sk); |
1228 | struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; | 1228 | struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; |
1229 | struct msghdr m = {0,}; | 1229 | struct msghdr m = {NULL,}; |
1230 | struct sk_buff *buf; | 1230 | struct sk_buff *buf; |
1231 | struct tipc_msg *msg; | 1231 | struct tipc_msg *msg; |
1232 | int res; | 1232 | int res; |
@@ -1251,7 +1251,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, | |||
1251 | /* Send a 'SYN-' to destination */ | 1251 | /* Send a 'SYN-' to destination */ |
1252 | 1252 | ||
1253 | m.msg_name = dest; | 1253 | m.msg_name = dest; |
1254 | if ((res = send_msg(0, sock, &m, 0)) < 0) { | 1254 | if ((res = send_msg(NULL, sock, &m, 0)) < 0) { |
1255 | sock->state = SS_DISCONNECTING; | 1255 | sock->state = SS_DISCONNECTING; |
1256 | return res; | 1256 | return res; |
1257 | } | 1257 | } |
@@ -1367,9 +1367,9 @@ static int accept(struct socket *sock, struct socket *newsock, int flags) | |||
1367 | 1367 | ||
1368 | msg_dbg(msg,"<ACC<: "); | 1368 | msg_dbg(msg,"<ACC<: "); |
1369 | if (!msg_data_sz(msg)) { | 1369 | if (!msg_data_sz(msg)) { |
1370 | struct msghdr m = {0,}; | 1370 | struct msghdr m = {NULL,}; |
1371 | 1371 | ||
1372 | send_packet(0, newsock, &m, 0); | 1372 | send_packet(NULL, newsock, &m, 0); |
1373 | advance_queue(tsock); | 1373 | advance_queue(tsock); |
1374 | } else { | 1374 | } else { |
1375 | sock_lock(tsock); | 1375 | sock_lock(tsock); |
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index 5ff38b9f3194..c5f026c7fd38 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c | |||
@@ -86,7 +86,7 @@ static struct top_srv topsrv = { 0 }; | |||
86 | * Returns converted value | 86 | * Returns converted value |
87 | */ | 87 | */ |
88 | 88 | ||
89 | static inline u32 htohl(u32 in, int swap) | 89 | static u32 htohl(u32 in, int swap) |
90 | { | 90 | { |
91 | char *c = (char *)∈ | 91 | char *c = (char *)∈ |
92 | 92 | ||
@@ -381,7 +381,7 @@ static void subscr_named_msg_event(void *usr_handle, | |||
381 | struct tipc_name_seq const *dest) | 381 | struct tipc_name_seq const *dest) |
382 | { | 382 | { |
383 | struct subscriber *subscriber; | 383 | struct subscriber *subscriber; |
384 | struct iovec msg_sect = {0, 0}; | 384 | struct iovec msg_sect = {NULL, 0}; |
385 | spinlock_t *subscriber_lock; | 385 | spinlock_t *subscriber_lock; |
386 | 386 | ||
387 | dbg("subscr_named_msg_event: orig = %x own = %x,\n", | 387 | dbg("subscr_named_msg_event: orig = %x own = %x,\n", |
@@ -413,13 +413,13 @@ static void subscr_named_msg_event(void *usr_handle, | |||
413 | tipc_createport(topsrv.user_ref, | 413 | tipc_createport(topsrv.user_ref, |
414 | (void *)(unsigned long)subscriber->ref, | 414 | (void *)(unsigned long)subscriber->ref, |
415 | importance, | 415 | importance, |
416 | 0, | 416 | NULL, |
417 | 0, | 417 | NULL, |
418 | subscr_conn_shutdown_event, | 418 | subscr_conn_shutdown_event, |
419 | 0, | 419 | NULL, |
420 | 0, | 420 | NULL, |
421 | subscr_conn_msg_event, | 421 | subscr_conn_msg_event, |
422 | 0, | 422 | NULL, |
423 | &subscriber->port_ref); | 423 | &subscriber->port_ref); |
424 | if (subscriber->port_ref == 0) { | 424 | if (subscriber->port_ref == 0) { |
425 | warn("Memory squeeze; failed to create subscription port\n"); | 425 | warn("Memory squeeze; failed to create subscription port\n"); |
@@ -461,22 +461,22 @@ int tipc_subscr_start(void) | |||
461 | INIT_LIST_HEAD(&topsrv.subscriber_list); | 461 | INIT_LIST_HEAD(&topsrv.subscriber_list); |
462 | 462 | ||
463 | spin_lock_bh(&topsrv.lock); | 463 | spin_lock_bh(&topsrv.lock); |
464 | res = tipc_attach(&topsrv.user_ref, 0, 0); | 464 | res = tipc_attach(&topsrv.user_ref, NULL, NULL); |
465 | if (res) { | 465 | if (res) { |
466 | spin_unlock_bh(&topsrv.lock); | 466 | spin_unlock_bh(&topsrv.lock); |
467 | return res; | 467 | return res; |
468 | } | 468 | } |
469 | 469 | ||
470 | res = tipc_createport(topsrv.user_ref, | 470 | res = tipc_createport(topsrv.user_ref, |
471 | 0, | 471 | NULL, |
472 | TIPC_CRITICAL_IMPORTANCE, | 472 | TIPC_CRITICAL_IMPORTANCE, |
473 | 0, | 473 | NULL, |
474 | 0, | 474 | NULL, |
475 | 0, | 475 | NULL, |
476 | 0, | 476 | NULL, |
477 | subscr_named_msg_event, | 477 | subscr_named_msg_event, |
478 | 0, | 478 | NULL, |
479 | 0, | 479 | NULL, |
480 | &topsrv.setup_port); | 480 | &topsrv.setup_port); |
481 | if (res) | 481 | if (res) |
482 | goto failed; | 482 | goto failed; |
diff --git a/net/tipc/user_reg.c b/net/tipc/user_reg.c index 106200d76587..3f3f933976e9 100644 --- a/net/tipc/user_reg.c +++ b/net/tipc/user_reg.c | |||
@@ -65,7 +65,7 @@ struct tipc_user { | |||
65 | #define MAX_USERID 64 | 65 | #define MAX_USERID 64 |
66 | #define USER_LIST_SIZE ((MAX_USERID + 1) * sizeof(struct tipc_user)) | 66 | #define USER_LIST_SIZE ((MAX_USERID + 1) * sizeof(struct tipc_user)) |
67 | 67 | ||
68 | static struct tipc_user *users = 0; | 68 | static struct tipc_user *users = NULL; |
69 | static u32 next_free_user = MAX_USERID + 1; | 69 | static u32 next_free_user = MAX_USERID + 1; |
70 | static spinlock_t reg_lock = SPIN_LOCK_UNLOCKED; | 70 | static spinlock_t reg_lock = SPIN_LOCK_UNLOCKED; |
71 | 71 | ||
@@ -149,7 +149,7 @@ void tipc_reg_stop(void) | |||
149 | reg_callback(&users[id]); | 149 | reg_callback(&users[id]); |
150 | } | 150 | } |
151 | kfree(users); | 151 | kfree(users); |
152 | users = 0; | 152 | users = NULL; |
153 | } | 153 | } |
154 | 154 | ||
155 | /** | 155 | /** |
diff --git a/net/tipc/zone.c b/net/tipc/zone.c index 7c11f7f83a21..2803e1b4f170 100644 --- a/net/tipc/zone.c +++ b/net/tipc/zone.c | |||
@@ -44,11 +44,11 @@ | |||
44 | 44 | ||
45 | struct _zone *tipc_zone_create(u32 addr) | 45 | struct _zone *tipc_zone_create(u32 addr) |
46 | { | 46 | { |
47 | struct _zone *z_ptr = 0; | 47 | struct _zone *z_ptr = NULL; |
48 | u32 z_num; | 48 | u32 z_num; |
49 | 49 | ||
50 | if (!tipc_addr_domain_valid(addr)) | 50 | if (!tipc_addr_domain_valid(addr)) |
51 | return 0; | 51 | return NULL; |
52 | 52 | ||
53 | z_ptr = (struct _zone *)kmalloc(sizeof(*z_ptr), GFP_ATOMIC); | 53 | z_ptr = (struct _zone *)kmalloc(sizeof(*z_ptr), GFP_ATOMIC); |
54 | if (z_ptr != NULL) { | 54 | if (z_ptr != NULL) { |
@@ -114,10 +114,10 @@ struct node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref | |||
114 | u32 c_num; | 114 | u32 c_num; |
115 | 115 | ||
116 | if (!z_ptr) | 116 | if (!z_ptr) |
117 | return 0; | 117 | return NULL; |
118 | c_ptr = z_ptr->clusters[tipc_cluster(addr)]; | 118 | c_ptr = z_ptr->clusters[tipc_cluster(addr)]; |
119 | if (!c_ptr) | 119 | if (!c_ptr) |
120 | return 0; | 120 | return NULL; |
121 | n_ptr = tipc_cltr_select_node(c_ptr, ref); | 121 | n_ptr = tipc_cltr_select_node(c_ptr, ref); |
122 | if (n_ptr) | 122 | if (n_ptr) |
123 | return n_ptr; | 123 | return n_ptr; |
@@ -126,12 +126,12 @@ struct node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref | |||
126 | for (c_num = 1; c_num <= tipc_max_clusters; c_num++) { | 126 | for (c_num = 1; c_num <= tipc_max_clusters; c_num++) { |
127 | c_ptr = z_ptr->clusters[c_num]; | 127 | c_ptr = z_ptr->clusters[c_num]; |
128 | if (!c_ptr) | 128 | if (!c_ptr) |
129 | return 0; | 129 | return NULL; |
130 | n_ptr = tipc_cltr_select_node(c_ptr, ref); | 130 | n_ptr = tipc_cltr_select_node(c_ptr, ref); |
131 | if (n_ptr) | 131 | if (n_ptr) |
132 | return n_ptr; | 132 | return n_ptr; |
133 | } | 133 | } |
134 | return 0; | 134 | return NULL; |
135 | } | 135 | } |
136 | 136 | ||
137 | u32 tipc_zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref) | 137 | u32 tipc_zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref) |
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index c323cc6a28b0..2b4cc2eea5b3 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
@@ -566,7 +566,7 @@ static struct sock * unix_create1(struct socket *sock) | |||
566 | u->mnt = NULL; | 566 | u->mnt = NULL; |
567 | spin_lock_init(&u->lock); | 567 | spin_lock_init(&u->lock); |
568 | atomic_set(&u->inflight, sock ? 0 : -1); | 568 | atomic_set(&u->inflight, sock ? 0 : -1); |
569 | init_MUTEX(&u->readsem); /* single task reading lock */ | 569 | mutex_init(&u->readlock); /* single task reading lock */ |
570 | init_waitqueue_head(&u->peer_wait); | 570 | init_waitqueue_head(&u->peer_wait); |
571 | unix_insert_socket(unix_sockets_unbound, sk); | 571 | unix_insert_socket(unix_sockets_unbound, sk); |
572 | out: | 572 | out: |
@@ -623,7 +623,7 @@ static int unix_autobind(struct socket *sock) | |||
623 | struct unix_address * addr; | 623 | struct unix_address * addr; |
624 | int err; | 624 | int err; |
625 | 625 | ||
626 | down(&u->readsem); | 626 | mutex_lock(&u->readlock); |
627 | 627 | ||
628 | err = 0; | 628 | err = 0; |
629 | if (u->addr) | 629 | if (u->addr) |
@@ -661,7 +661,7 @@ retry: | |||
661 | spin_unlock(&unix_table_lock); | 661 | spin_unlock(&unix_table_lock); |
662 | err = 0; | 662 | err = 0; |
663 | 663 | ||
664 | out: up(&u->readsem); | 664 | out: mutex_unlock(&u->readlock); |
665 | return err; | 665 | return err; |
666 | } | 666 | } |
667 | 667 | ||
@@ -744,7 +744,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
744 | goto out; | 744 | goto out; |
745 | addr_len = err; | 745 | addr_len = err; |
746 | 746 | ||
747 | down(&u->readsem); | 747 | mutex_lock(&u->readlock); |
748 | 748 | ||
749 | err = -EINVAL; | 749 | err = -EINVAL; |
750 | if (u->addr) | 750 | if (u->addr) |
@@ -816,7 +816,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
816 | out_unlock: | 816 | out_unlock: |
817 | spin_unlock(&unix_table_lock); | 817 | spin_unlock(&unix_table_lock); |
818 | out_up: | 818 | out_up: |
819 | up(&u->readsem); | 819 | mutex_unlock(&u->readlock); |
820 | out: | 820 | out: |
821 | return err; | 821 | return err; |
822 | 822 | ||
@@ -1427,15 +1427,15 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1427 | while(sent < len) | 1427 | while(sent < len) |
1428 | { | 1428 | { |
1429 | /* | 1429 | /* |
1430 | * Optimisation for the fact that under 0.01% of X messages typically | 1430 | * Optimisation for the fact that under 0.01% of X |
1431 | * need breaking up. | 1431 | * messages typically need breaking up. |
1432 | */ | 1432 | */ |
1433 | 1433 | ||
1434 | size=len-sent; | 1434 | size = len-sent; |
1435 | 1435 | ||
1436 | /* Keep two messages in the pipe so it schedules better */ | 1436 | /* Keep two messages in the pipe so it schedules better */ |
1437 | if (size > sk->sk_sndbuf / 2 - 64) | 1437 | if (size > ((sk->sk_sndbuf >> 1) - 64)) |
1438 | size = sk->sk_sndbuf / 2 - 64; | 1438 | size = (sk->sk_sndbuf >> 1) - 64; |
1439 | 1439 | ||
1440 | if (size > SKB_MAX_ALLOC) | 1440 | if (size > SKB_MAX_ALLOC) |
1441 | size = SKB_MAX_ALLOC; | 1441 | size = SKB_MAX_ALLOC; |
@@ -1545,7 +1545,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1545 | 1545 | ||
1546 | msg->msg_namelen = 0; | 1546 | msg->msg_namelen = 0; |
1547 | 1547 | ||
1548 | down(&u->readsem); | 1548 | mutex_lock(&u->readlock); |
1549 | 1549 | ||
1550 | skb = skb_recv_datagram(sk, flags, noblock, &err); | 1550 | skb = skb_recv_datagram(sk, flags, noblock, &err); |
1551 | if (!skb) | 1551 | if (!skb) |
@@ -1600,7 +1600,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1600 | out_free: | 1600 | out_free: |
1601 | skb_free_datagram(sk,skb); | 1601 | skb_free_datagram(sk,skb); |
1602 | out_unlock: | 1602 | out_unlock: |
1603 | up(&u->readsem); | 1603 | mutex_unlock(&u->readlock); |
1604 | out: | 1604 | out: |
1605 | return err; | 1605 | return err; |
1606 | } | 1606 | } |
@@ -1676,7 +1676,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1676 | memset(&tmp_scm, 0, sizeof(tmp_scm)); | 1676 | memset(&tmp_scm, 0, sizeof(tmp_scm)); |
1677 | } | 1677 | } |
1678 | 1678 | ||
1679 | down(&u->readsem); | 1679 | mutex_lock(&u->readlock); |
1680 | 1680 | ||
1681 | do | 1681 | do |
1682 | { | 1682 | { |
@@ -1700,7 +1700,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1700 | err = -EAGAIN; | 1700 | err = -EAGAIN; |
1701 | if (!timeo) | 1701 | if (!timeo) |
1702 | break; | 1702 | break; |
1703 | up(&u->readsem); | 1703 | mutex_unlock(&u->readlock); |
1704 | 1704 | ||
1705 | timeo = unix_stream_data_wait(sk, timeo); | 1705 | timeo = unix_stream_data_wait(sk, timeo); |
1706 | 1706 | ||
@@ -1708,7 +1708,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1708 | err = sock_intr_errno(timeo); | 1708 | err = sock_intr_errno(timeo); |
1709 | goto out; | 1709 | goto out; |
1710 | } | 1710 | } |
1711 | down(&u->readsem); | 1711 | mutex_lock(&u->readlock); |
1712 | continue; | 1712 | continue; |
1713 | } | 1713 | } |
1714 | 1714 | ||
@@ -1774,7 +1774,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1774 | } | 1774 | } |
1775 | } while (size); | 1775 | } while (size); |
1776 | 1776 | ||
1777 | up(&u->readsem); | 1777 | mutex_unlock(&u->readlock); |
1778 | scm_recv(sock, msg, siocb->scm, flags); | 1778 | scm_recv(sock, msg, siocb->scm, flags); |
1779 | out: | 1779 | out: |
1780 | return copied ? : err; | 1780 | return copied ? : err; |
diff --git a/net/unix/garbage.c b/net/unix/garbage.c index 411802bd4d37..746c2f4a5fa6 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c | |||
@@ -76,6 +76,7 @@ | |||
76 | #include <linux/netdevice.h> | 76 | #include <linux/netdevice.h> |
77 | #include <linux/file.h> | 77 | #include <linux/file.h> |
78 | #include <linux/proc_fs.h> | 78 | #include <linux/proc_fs.h> |
79 | #include <linux/mutex.h> | ||
79 | 80 | ||
80 | #include <net/sock.h> | 81 | #include <net/sock.h> |
81 | #include <net/af_unix.h> | 82 | #include <net/af_unix.h> |
@@ -169,7 +170,7 @@ static void maybe_unmark_and_push(struct sock *x) | |||
169 | 170 | ||
170 | void unix_gc(void) | 171 | void unix_gc(void) |
171 | { | 172 | { |
172 | static DECLARE_MUTEX(unix_gc_sem); | 173 | static DEFINE_MUTEX(unix_gc_sem); |
173 | int i; | 174 | int i; |
174 | struct sock *s; | 175 | struct sock *s; |
175 | struct sk_buff_head hitlist; | 176 | struct sk_buff_head hitlist; |
@@ -179,7 +180,7 @@ void unix_gc(void) | |||
179 | * Avoid a recursive GC. | 180 | * Avoid a recursive GC. |
180 | */ | 181 | */ |
181 | 182 | ||
182 | if (down_trylock(&unix_gc_sem)) | 183 | if (!mutex_trylock(&unix_gc_sem)) |
183 | return; | 184 | return; |
184 | 185 | ||
185 | spin_lock(&unix_table_lock); | 186 | spin_lock(&unix_table_lock); |
@@ -308,5 +309,5 @@ void unix_gc(void) | |||
308 | */ | 309 | */ |
309 | 310 | ||
310 | __skb_queue_purge(&hitlist); | 311 | __skb_queue_purge(&hitlist); |
311 | up(&unix_gc_sem); | 312 | mutex_unlock(&unix_gc_sem); |
312 | } | 313 | } |
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 72b6ff3299ba..282ce4e40d7b 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c | |||
@@ -54,7 +54,10 @@ | |||
54 | #include <linux/termios.h> /* For TIOCINQ/OUTQ */ | 54 | #include <linux/termios.h> /* For TIOCINQ/OUTQ */ |
55 | #include <linux/notifier.h> | 55 | #include <linux/notifier.h> |
56 | #include <linux/init.h> | 56 | #include <linux/init.h> |
57 | #include <linux/compat.h> | ||
58 | |||
57 | #include <net/x25.h> | 59 | #include <net/x25.h> |
60 | #include <net/compat.h> | ||
58 | 61 | ||
59 | int sysctl_x25_restart_request_timeout = X25_DEFAULT_T20; | 62 | int sysctl_x25_restart_request_timeout = X25_DEFAULT_T20; |
60 | int sysctl_x25_call_request_timeout = X25_DEFAULT_T21; | 63 | int sysctl_x25_call_request_timeout = X25_DEFAULT_T21; |
@@ -69,6 +72,14 @@ static const struct proto_ops x25_proto_ops; | |||
69 | 72 | ||
70 | static struct x25_address null_x25_address = {" "}; | 73 | static struct x25_address null_x25_address = {" "}; |
71 | 74 | ||
75 | #ifdef CONFIG_COMPAT | ||
76 | struct compat_x25_subscrip_struct { | ||
77 | char device[200-sizeof(compat_ulong_t)]; | ||
78 | compat_ulong_t global_facil_mask; | ||
79 | compat_uint_t extended; | ||
80 | }; | ||
81 | #endif | ||
82 | |||
72 | int x25_addr_ntoa(unsigned char *p, struct x25_address *called_addr, | 83 | int x25_addr_ntoa(unsigned char *p, struct x25_address *called_addr, |
73 | struct x25_address *calling_addr) | 84 | struct x25_address *calling_addr) |
74 | { | 85 | { |
@@ -514,6 +525,13 @@ static int x25_create(struct socket *sock, int protocol) | |||
514 | x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE; | 525 | x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE; |
515 | x25->facilities.throughput = X25_DEFAULT_THROUGHPUT; | 526 | x25->facilities.throughput = X25_DEFAULT_THROUGHPUT; |
516 | x25->facilities.reverse = X25_DEFAULT_REVERSE; | 527 | x25->facilities.reverse = X25_DEFAULT_REVERSE; |
528 | x25->dte_facilities.calling_len = 0; | ||
529 | x25->dte_facilities.called_len = 0; | ||
530 | memset(x25->dte_facilities.called_ae, '\0', | ||
531 | sizeof(x25->dte_facilities.called_ae)); | ||
532 | memset(x25->dte_facilities.calling_ae, '\0', | ||
533 | sizeof(x25->dte_facilities.calling_ae)); | ||
534 | |||
517 | rc = 0; | 535 | rc = 0; |
518 | out: | 536 | out: |
519 | return rc; | 537 | return rc; |
@@ -550,6 +568,7 @@ static struct sock *x25_make_new(struct sock *osk) | |||
550 | x25->t2 = ox25->t2; | 568 | x25->t2 = ox25->t2; |
551 | x25->facilities = ox25->facilities; | 569 | x25->facilities = ox25->facilities; |
552 | x25->qbitincl = ox25->qbitincl; | 570 | x25->qbitincl = ox25->qbitincl; |
571 | x25->dte_facilities = ox25->dte_facilities; | ||
553 | x25->cudmatchlength = ox25->cudmatchlength; | 572 | x25->cudmatchlength = ox25->cudmatchlength; |
554 | x25->accptapprv = ox25->accptapprv; | 573 | x25->accptapprv = ox25->accptapprv; |
555 | 574 | ||
@@ -733,7 +752,7 @@ out: | |||
733 | return rc; | 752 | return rc; |
734 | } | 753 | } |
735 | 754 | ||
736 | static int x25_wait_for_data(struct sock *sk, int timeout) | 755 | static int x25_wait_for_data(struct sock *sk, long timeout) |
737 | { | 756 | { |
738 | DECLARE_WAITQUEUE(wait, current); | 757 | DECLARE_WAITQUEUE(wait, current); |
739 | int rc = 0; | 758 | int rc = 0; |
@@ -829,6 +848,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, | |||
829 | struct x25_sock *makex25; | 848 | struct x25_sock *makex25; |
830 | struct x25_address source_addr, dest_addr; | 849 | struct x25_address source_addr, dest_addr; |
831 | struct x25_facilities facilities; | 850 | struct x25_facilities facilities; |
851 | struct x25_dte_facilities dte_facilities; | ||
832 | int len, rc; | 852 | int len, rc; |
833 | 853 | ||
834 | /* | 854 | /* |
@@ -865,7 +885,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, | |||
865 | /* | 885 | /* |
866 | * Try to reach a compromise on the requested facilities. | 886 | * Try to reach a compromise on the requested facilities. |
867 | */ | 887 | */ |
868 | if ((len = x25_negotiate_facilities(skb, sk, &facilities)) == -1) | 888 | len = x25_negotiate_facilities(skb, sk, &facilities, &dte_facilities); |
889 | if (len == -1) | ||
869 | goto out_sock_put; | 890 | goto out_sock_put; |
870 | 891 | ||
871 | /* | 892 | /* |
@@ -896,9 +917,12 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, | |||
896 | makex25->source_addr = source_addr; | 917 | makex25->source_addr = source_addr; |
897 | makex25->neighbour = nb; | 918 | makex25->neighbour = nb; |
898 | makex25->facilities = facilities; | 919 | makex25->facilities = facilities; |
920 | makex25->dte_facilities= dte_facilities; | ||
899 | makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask; | 921 | makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask; |
900 | /* ensure no reverse facil on accept */ | 922 | /* ensure no reverse facil on accept */ |
901 | makex25->vc_facil_mask &= ~X25_MASK_REVERSE; | 923 | makex25->vc_facil_mask &= ~X25_MASK_REVERSE; |
924 | /* ensure no calling address extension on accept */ | ||
925 | makex25->vc_facil_mask &= ~X25_MASK_CALLING_AE; | ||
902 | makex25->cudmatchlength = x25_sk(sk)->cudmatchlength; | 926 | makex25->cudmatchlength = x25_sk(sk)->cudmatchlength; |
903 | 927 | ||
904 | /* Normally all calls are accepted immediatly */ | 928 | /* Normally all calls are accepted immediatly */ |
@@ -1305,6 +1329,36 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1305 | break; | 1329 | break; |
1306 | } | 1330 | } |
1307 | 1331 | ||
1332 | case SIOCX25GDTEFACILITIES: { | ||
1333 | rc = copy_to_user(argp, &x25->dte_facilities, | ||
1334 | sizeof(x25->dte_facilities)); | ||
1335 | if (rc) | ||
1336 | rc = -EFAULT; | ||
1337 | break; | ||
1338 | } | ||
1339 | |||
1340 | case SIOCX25SDTEFACILITIES: { | ||
1341 | struct x25_dte_facilities dtefacs; | ||
1342 | rc = -EFAULT; | ||
1343 | if (copy_from_user(&dtefacs, argp, sizeof(dtefacs))) | ||
1344 | break; | ||
1345 | rc = -EINVAL; | ||
1346 | if (sk->sk_state != TCP_LISTEN && | ||
1347 | sk->sk_state != TCP_CLOSE) | ||
1348 | break; | ||
1349 | if (dtefacs.calling_len > X25_MAX_AE_LEN) | ||
1350 | break; | ||
1351 | if (dtefacs.calling_ae == NULL) | ||
1352 | break; | ||
1353 | if (dtefacs.called_len > X25_MAX_AE_LEN) | ||
1354 | break; | ||
1355 | if (dtefacs.called_ae == NULL) | ||
1356 | break; | ||
1357 | x25->dte_facilities = dtefacs; | ||
1358 | rc = 0; | ||
1359 | break; | ||
1360 | } | ||
1361 | |||
1308 | case SIOCX25GCALLUSERDATA: { | 1362 | case SIOCX25GCALLUSERDATA: { |
1309 | struct x25_calluserdata cud = x25->calluserdata; | 1363 | struct x25_calluserdata cud = x25->calluserdata; |
1310 | rc = copy_to_user(argp, &cud, | 1364 | rc = copy_to_user(argp, &cud, |
@@ -1387,6 +1441,118 @@ static struct net_proto_family x25_family_ops = { | |||
1387 | .owner = THIS_MODULE, | 1441 | .owner = THIS_MODULE, |
1388 | }; | 1442 | }; |
1389 | 1443 | ||
1444 | #ifdef CONFIG_COMPAT | ||
1445 | static int compat_x25_subscr_ioctl(unsigned int cmd, | ||
1446 | struct compat_x25_subscrip_struct __user *x25_subscr32) | ||
1447 | { | ||
1448 | struct compat_x25_subscrip_struct x25_subscr; | ||
1449 | struct x25_neigh *nb; | ||
1450 | struct net_device *dev; | ||
1451 | int rc = -EINVAL; | ||
1452 | |||
1453 | rc = -EFAULT; | ||
1454 | if (copy_from_user(&x25_subscr, x25_subscr32, sizeof(*x25_subscr32))) | ||
1455 | goto out; | ||
1456 | |||
1457 | rc = -EINVAL; | ||
1458 | dev = x25_dev_get(x25_subscr.device); | ||
1459 | if (dev == NULL) | ||
1460 | goto out; | ||
1461 | |||
1462 | nb = x25_get_neigh(dev); | ||
1463 | if (nb == NULL) | ||
1464 | goto out_dev_put; | ||
1465 | |||
1466 | dev_put(dev); | ||
1467 | |||
1468 | if (cmd == SIOCX25GSUBSCRIP) { | ||
1469 | x25_subscr.extended = nb->extended; | ||
1470 | x25_subscr.global_facil_mask = nb->global_facil_mask; | ||
1471 | rc = copy_to_user(x25_subscr32, &x25_subscr, | ||
1472 | sizeof(*x25_subscr32)) ? -EFAULT : 0; | ||
1473 | } else { | ||
1474 | rc = -EINVAL; | ||
1475 | if (x25_subscr.extended == 0 || x25_subscr.extended == 1) { | ||
1476 | rc = 0; | ||
1477 | nb->extended = x25_subscr.extended; | ||
1478 | nb->global_facil_mask = x25_subscr.global_facil_mask; | ||
1479 | } | ||
1480 | } | ||
1481 | x25_neigh_put(nb); | ||
1482 | out: | ||
1483 | return rc; | ||
1484 | out_dev_put: | ||
1485 | dev_put(dev); | ||
1486 | goto out; | ||
1487 | } | ||
1488 | |||
1489 | static int compat_x25_ioctl(struct socket *sock, unsigned int cmd, | ||
1490 | unsigned long arg) | ||
1491 | { | ||
1492 | void __user *argp = compat_ptr(arg); | ||
1493 | struct sock *sk = sock->sk; | ||
1494 | |||
1495 | int rc = -ENOIOCTLCMD; | ||
1496 | |||
1497 | switch(cmd) { | ||
1498 | case TIOCOUTQ: | ||
1499 | case TIOCINQ: | ||
1500 | rc = x25_ioctl(sock, cmd, (unsigned long)argp); | ||
1501 | break; | ||
1502 | case SIOCGSTAMP: | ||
1503 | rc = -EINVAL; | ||
1504 | if (sk) | ||
1505 | rc = compat_sock_get_timestamp(sk, | ||
1506 | (struct timeval __user*)argp); | ||
1507 | break; | ||
1508 | case SIOCGIFADDR: | ||
1509 | case SIOCSIFADDR: | ||
1510 | case SIOCGIFDSTADDR: | ||
1511 | case SIOCSIFDSTADDR: | ||
1512 | case SIOCGIFBRDADDR: | ||
1513 | case SIOCSIFBRDADDR: | ||
1514 | case SIOCGIFNETMASK: | ||
1515 | case SIOCSIFNETMASK: | ||
1516 | case SIOCGIFMETRIC: | ||
1517 | case SIOCSIFMETRIC: | ||
1518 | rc = -EINVAL; | ||
1519 | break; | ||
1520 | case SIOCADDRT: | ||
1521 | case SIOCDELRT: | ||
1522 | rc = -EPERM; | ||
1523 | if (!capable(CAP_NET_ADMIN)) | ||
1524 | break; | ||
1525 | rc = x25_route_ioctl(cmd, argp); | ||
1526 | break; | ||
1527 | case SIOCX25GSUBSCRIP: | ||
1528 | rc = compat_x25_subscr_ioctl(cmd, argp); | ||
1529 | break; | ||
1530 | case SIOCX25SSUBSCRIP: | ||
1531 | rc = -EPERM; | ||
1532 | if (!capable(CAP_NET_ADMIN)) | ||
1533 | break; | ||
1534 | rc = compat_x25_subscr_ioctl(cmd, argp); | ||
1535 | break; | ||
1536 | case SIOCX25GFACILITIES: | ||
1537 | case SIOCX25SFACILITIES: | ||
1538 | case SIOCX25GDTEFACILITIES: | ||
1539 | case SIOCX25SDTEFACILITIES: | ||
1540 | case SIOCX25GCALLUSERDATA: | ||
1541 | case SIOCX25SCALLUSERDATA: | ||
1542 | case SIOCX25GCAUSEDIAG: | ||
1543 | case SIOCX25SCUDMATCHLEN: | ||
1544 | case SIOCX25CALLACCPTAPPRV: | ||
1545 | case SIOCX25SENDCALLACCPT: | ||
1546 | rc = x25_ioctl(sock, cmd, (unsigned long)argp); | ||
1547 | break; | ||
1548 | default: | ||
1549 | rc = -ENOIOCTLCMD; | ||
1550 | break; | ||
1551 | } | ||
1552 | return rc; | ||
1553 | } | ||
1554 | #endif | ||
1555 | |||
1390 | static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = { | 1556 | static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = { |
1391 | .family = AF_X25, | 1557 | .family = AF_X25, |
1392 | .owner = THIS_MODULE, | 1558 | .owner = THIS_MODULE, |
@@ -1398,6 +1564,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = { | |||
1398 | .getname = x25_getname, | 1564 | .getname = x25_getname, |
1399 | .poll = datagram_poll, | 1565 | .poll = datagram_poll, |
1400 | .ioctl = x25_ioctl, | 1566 | .ioctl = x25_ioctl, |
1567 | #ifdef CONFIG_COMPAT | ||
1568 | .compat_ioctl = compat_x25_ioctl, | ||
1569 | #endif | ||
1401 | .listen = x25_listen, | 1570 | .listen = x25_listen, |
1402 | .shutdown = sock_no_shutdown, | 1571 | .shutdown = sock_no_shutdown, |
1403 | .setsockopt = x25_setsockopt, | 1572 | .setsockopt = x25_setsockopt, |
diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c index 54278b962f4c..9f42b9c9de37 100644 --- a/net/x25/x25_facilities.c +++ b/net/x25/x25_facilities.c | |||
@@ -28,18 +28,28 @@ | |||
28 | #include <net/x25.h> | 28 | #include <net/x25.h> |
29 | 29 | ||
30 | /* | 30 | /* |
31 | * Parse a set of facilities into the facilities structure. Unrecognised | 31 | * Parse a set of facilities into the facilities structures. Unrecognised |
32 | * facilities are written to the debug log file. | 32 | * facilities are written to the debug log file. |
33 | */ | 33 | */ |
34 | int x25_parse_facilities(struct sk_buff *skb, | 34 | int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, |
35 | struct x25_facilities *facilities, | 35 | struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask) |
36 | unsigned long *vc_fac_mask) | ||
37 | { | 36 | { |
38 | unsigned char *p = skb->data; | 37 | unsigned char *p = skb->data; |
39 | unsigned int len = *p++; | 38 | unsigned int len = *p++; |
40 | 39 | ||
41 | *vc_fac_mask = 0; | 40 | *vc_fac_mask = 0; |
42 | 41 | ||
42 | /* | ||
43 | * The kernel knows which facilities were set on an incoming call but | ||
44 | * currently this information is not available to userspace. Here we | ||
45 | * give userspace who read incoming call facilities 0 length to indicate | ||
46 | * it wasn't set. | ||
47 | */ | ||
48 | dte_facs->calling_len = 0; | ||
49 | dte_facs->called_len = 0; | ||
50 | memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae)); | ||
51 | memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae)); | ||
52 | |||
43 | while (len > 0) { | 53 | while (len > 0) { |
44 | switch (*p & X25_FAC_CLASS_MASK) { | 54 | switch (*p & X25_FAC_CLASS_MASK) { |
45 | case X25_FAC_CLASS_A: | 55 | case X25_FAC_CLASS_A: |
@@ -74,6 +84,8 @@ int x25_parse_facilities(struct sk_buff *skb, | |||
74 | facilities->throughput = p[1]; | 84 | facilities->throughput = p[1]; |
75 | *vc_fac_mask |= X25_MASK_THROUGHPUT; | 85 | *vc_fac_mask |= X25_MASK_THROUGHPUT; |
76 | break; | 86 | break; |
87 | case X25_MARKER: | ||
88 | break; | ||
77 | default: | 89 | default: |
78 | printk(KERN_DEBUG "X.25: unknown facility " | 90 | printk(KERN_DEBUG "X.25: unknown facility " |
79 | "%02X, value %02X\n", | 91 | "%02X, value %02X\n", |
@@ -112,11 +124,30 @@ int x25_parse_facilities(struct sk_buff *skb, | |||
112 | len -= 4; | 124 | len -= 4; |
113 | break; | 125 | break; |
114 | case X25_FAC_CLASS_D: | 126 | case X25_FAC_CLASS_D: |
115 | printk(KERN_DEBUG "X.25: unknown facility %02X, " | 127 | switch (*p) { |
116 | "length %d, values %02X, %02X, %02X, %02X\n", | 128 | case X25_FAC_CALLING_AE: |
117 | p[0], p[1], p[2], p[3], p[4], p[5]); | 129 | if (p[1] > X25_MAX_DTE_FACIL_LEN) |
130 | break; | ||
131 | dte_facs->calling_len = p[2]; | ||
132 | memcpy(dte_facs->calling_ae, &p[3], p[1] - 1); | ||
133 | *vc_fac_mask |= X25_MASK_CALLING_AE; | ||
134 | break; | ||
135 | case X25_FAC_CALLED_AE: | ||
136 | if (p[1] > X25_MAX_DTE_FACIL_LEN) | ||
137 | break; | ||
138 | dte_facs->called_len = p[2]; | ||
139 | memcpy(dte_facs->called_ae, &p[3], p[1] - 1); | ||
140 | *vc_fac_mask |= X25_MASK_CALLED_AE; | ||
141 | break; | ||
142 | default: | ||
143 | printk(KERN_DEBUG "X.25: unknown facility %02X," | ||
144 | "length %d, values %02X, %02X, " | ||
145 | "%02X, %02X\n", | ||
146 | p[0], p[1], p[2], p[3], p[4], p[5]); | ||
147 | break; | ||
148 | } | ||
118 | len -= p[1] + 2; | 149 | len -= p[1] + 2; |
119 | p += p[1] + 2; | 150 | p += p[1] + 2; |
120 | break; | 151 | break; |
121 | } | 152 | } |
122 | } | 153 | } |
@@ -128,8 +159,8 @@ int x25_parse_facilities(struct sk_buff *skb, | |||
128 | * Create a set of facilities. | 159 | * Create a set of facilities. |
129 | */ | 160 | */ |
130 | int x25_create_facilities(unsigned char *buffer, | 161 | int x25_create_facilities(unsigned char *buffer, |
131 | struct x25_facilities *facilities, | 162 | struct x25_facilities *facilities, |
132 | unsigned long facil_mask) | 163 | struct x25_dte_facilities *dte_facs, unsigned long facil_mask) |
133 | { | 164 | { |
134 | unsigned char *p = buffer + 1; | 165 | unsigned char *p = buffer + 1; |
135 | int len; | 166 | int len; |
@@ -168,6 +199,33 @@ int x25_create_facilities(unsigned char *buffer, | |||
168 | *p++ = facilities->winsize_out ? : facilities->winsize_in; | 199 | *p++ = facilities->winsize_out ? : facilities->winsize_in; |
169 | } | 200 | } |
170 | 201 | ||
202 | if (facil_mask & (X25_MASK_CALLING_AE|X25_MASK_CALLED_AE)) { | ||
203 | *p++ = X25_MARKER; | ||
204 | *p++ = X25_DTE_SERVICES; | ||
205 | } | ||
206 | |||
207 | if (dte_facs->calling_len && (facil_mask & X25_MASK_CALLING_AE)) { | ||
208 | unsigned bytecount = (dte_facs->calling_len % 2) ? | ||
209 | dte_facs->calling_len / 2 + 1 : | ||
210 | dte_facs->calling_len / 2; | ||
211 | *p++ = X25_FAC_CALLING_AE; | ||
212 | *p++ = 1 + bytecount; | ||
213 | *p++ = dte_facs->calling_len; | ||
214 | memcpy(p, dte_facs->calling_ae, bytecount); | ||
215 | p += bytecount; | ||
216 | } | ||
217 | |||
218 | if (dte_facs->called_len && (facil_mask & X25_MASK_CALLED_AE)) { | ||
219 | unsigned bytecount = (dte_facs->called_len % 2) ? | ||
220 | dte_facs->called_len / 2 + 1 : | ||
221 | dte_facs->called_len / 2; | ||
222 | *p++ = X25_FAC_CALLED_AE; | ||
223 | *p++ = 1 + bytecount; | ||
224 | *p++ = dte_facs->called_len; | ||
225 | memcpy(p, dte_facs->called_ae, bytecount); | ||
226 | p+=bytecount; | ||
227 | } | ||
228 | |||
171 | len = p - buffer; | 229 | len = p - buffer; |
172 | buffer[0] = len - 1; | 230 | buffer[0] = len - 1; |
173 | 231 | ||
@@ -180,7 +238,7 @@ int x25_create_facilities(unsigned char *buffer, | |||
180 | * The only real problem is with reverse charging. | 238 | * The only real problem is with reverse charging. |
181 | */ | 239 | */ |
182 | int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, | 240 | int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, |
183 | struct x25_facilities *new) | 241 | struct x25_facilities *new, struct x25_dte_facilities *dte) |
184 | { | 242 | { |
185 | struct x25_sock *x25 = x25_sk(sk); | 243 | struct x25_sock *x25 = x25_sk(sk); |
186 | struct x25_facilities *ours = &x25->facilities; | 244 | struct x25_facilities *ours = &x25->facilities; |
@@ -190,7 +248,7 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, | |||
190 | memset(&theirs, 0, sizeof(theirs)); | 248 | memset(&theirs, 0, sizeof(theirs)); |
191 | memcpy(new, ours, sizeof(*new)); | 249 | memcpy(new, ours, sizeof(*new)); |
192 | 250 | ||
193 | len = x25_parse_facilities(skb, &theirs, &x25->vc_facil_mask); | 251 | len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask); |
194 | 252 | ||
195 | /* | 253 | /* |
196 | * They want reverse charging, we won't accept it. | 254 | * They want reverse charging, we won't accept it. |
diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c index 26146874b839..eed50e10f09b 100644 --- a/net/x25/x25_in.c +++ b/net/x25/x25_in.c | |||
@@ -106,7 +106,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp | |||
106 | skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr)); | 106 | skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr)); |
107 | skb_pull(skb, | 107 | skb_pull(skb, |
108 | x25_parse_facilities(skb, &x25->facilities, | 108 | x25_parse_facilities(skb, &x25->facilities, |
109 | &x25->vc_facil_mask)); | 109 | &x25->dte_facilities, |
110 | &x25->vc_facil_mask)); | ||
110 | /* | 111 | /* |
111 | * Copy any Call User Data. | 112 | * Copy any Call User Data. |
112 | */ | 113 | */ |
diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c index 8be9b8fbc24d..8d6220aa5d0f 100644 --- a/net/x25/x25_subr.c +++ b/net/x25/x25_subr.c | |||
@@ -190,8 +190,9 @@ void x25_write_internal(struct sock *sk, int frametype) | |||
190 | dptr = skb_put(skb, len); | 190 | dptr = skb_put(skb, len); |
191 | memcpy(dptr, addresses, len); | 191 | memcpy(dptr, addresses, len); |
192 | len = x25_create_facilities(facilities, | 192 | len = x25_create_facilities(facilities, |
193 | &x25->facilities, | 193 | &x25->facilities, |
194 | x25->neighbour->global_facil_mask); | 194 | &x25->dte_facilities, |
195 | x25->neighbour->global_facil_mask); | ||
195 | dptr = skb_put(skb, len); | 196 | dptr = skb_put(skb, len); |
196 | memcpy(dptr, facilities, len); | 197 | memcpy(dptr, facilities, len); |
197 | dptr = skb_put(skb, x25->calluserdata.cudlength); | 198 | dptr = skb_put(skb, x25->calluserdata.cudlength); |
@@ -206,6 +207,7 @@ void x25_write_internal(struct sock *sk, int frametype) | |||
206 | *dptr++ = 0x00; /* Address lengths */ | 207 | *dptr++ = 0x00; /* Address lengths */ |
207 | len = x25_create_facilities(facilities, | 208 | len = x25_create_facilities(facilities, |
208 | &x25->facilities, | 209 | &x25->facilities, |
210 | &x25->dte_facilities, | ||
209 | x25->vc_facil_mask); | 211 | x25->vc_facil_mask); |
210 | dptr = skb_put(skb, len); | 212 | dptr = skb_put(skb, len); |
211 | memcpy(dptr, facilities, len); | 213 | memcpy(dptr, facilities, len); |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index ae62054a9fc4..f5eae9febd26 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -26,8 +26,8 @@ | |||
26 | #include <net/xfrm.h> | 26 | #include <net/xfrm.h> |
27 | #include <net/ip.h> | 27 | #include <net/ip.h> |
28 | 28 | ||
29 | DECLARE_MUTEX(xfrm_cfg_sem); | 29 | DEFINE_MUTEX(xfrm_cfg_mutex); |
30 | EXPORT_SYMBOL(xfrm_cfg_sem); | 30 | EXPORT_SYMBOL(xfrm_cfg_mutex); |
31 | 31 | ||
32 | static DEFINE_RWLOCK(xfrm_policy_lock); | 32 | static DEFINE_RWLOCK(xfrm_policy_lock); |
33 | 33 | ||
@@ -203,7 +203,7 @@ static void xfrm_policy_timer(unsigned long data) | |||
203 | } | 203 | } |
204 | 204 | ||
205 | if (warn) | 205 | if (warn) |
206 | km_policy_expired(xp, dir, 0); | 206 | km_policy_expired(xp, dir, 0, 0); |
207 | if (next != LONG_MAX && | 207 | if (next != LONG_MAX && |
208 | !mod_timer(&xp->timer, jiffies + make_jiffies(next))) | 208 | !mod_timer(&xp->timer, jiffies + make_jiffies(next))) |
209 | xfrm_pol_hold(xp); | 209 | xfrm_pol_hold(xp); |
@@ -216,7 +216,7 @@ out: | |||
216 | expired: | 216 | expired: |
217 | read_unlock(&xp->lock); | 217 | read_unlock(&xp->lock); |
218 | if (!xfrm_policy_delete(xp, dir)) | 218 | if (!xfrm_policy_delete(xp, dir)) |
219 | km_policy_expired(xp, dir, 1); | 219 | km_policy_expired(xp, dir, 1, 0); |
220 | xfrm_pol_put(xp); | 220 | xfrm_pol_put(xp); |
221 | } | 221 | } |
222 | 222 | ||
@@ -621,6 +621,7 @@ int xfrm_policy_delete(struct xfrm_policy *pol, int dir) | |||
621 | } | 621 | } |
622 | return -ENOENT; | 622 | return -ENOENT; |
623 | } | 623 | } |
624 | EXPORT_SYMBOL(xfrm_policy_delete); | ||
624 | 625 | ||
625 | int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) | 626 | int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) |
626 | { | 627 | { |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index c656cbaf35e8..a8e14dc1b04e 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -20,6 +20,15 @@ | |||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
22 | 22 | ||
23 | struct sock *xfrm_nl; | ||
24 | EXPORT_SYMBOL(xfrm_nl); | ||
25 | |||
26 | u32 sysctl_xfrm_aevent_etime = XFRM_AE_ETIME; | ||
27 | EXPORT_SYMBOL(sysctl_xfrm_aevent_etime); | ||
28 | |||
29 | u32 sysctl_xfrm_aevent_rseqth = XFRM_AE_SEQT_SIZE; | ||
30 | EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth); | ||
31 | |||
23 | /* Each xfrm_state may be linked to two tables: | 32 | /* Each xfrm_state may be linked to two tables: |
24 | 33 | ||
25 | 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) | 34 | 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) |
@@ -50,18 +59,20 @@ static DEFINE_SPINLOCK(xfrm_state_gc_lock); | |||
50 | 59 | ||
51 | static int xfrm_state_gc_flush_bundles; | 60 | static int xfrm_state_gc_flush_bundles; |
52 | 61 | ||
53 | static int __xfrm_state_delete(struct xfrm_state *x); | 62 | int __xfrm_state_delete(struct xfrm_state *x); |
54 | 63 | ||
55 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); | 64 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); |
56 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | 65 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); |
57 | 66 | ||
58 | static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); | 67 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); |
59 | static void km_state_expired(struct xfrm_state *x, int hard); | 68 | void km_state_expired(struct xfrm_state *x, int hard, u32 pid); |
60 | 69 | ||
61 | static void xfrm_state_gc_destroy(struct xfrm_state *x) | 70 | static void xfrm_state_gc_destroy(struct xfrm_state *x) |
62 | { | 71 | { |
63 | if (del_timer(&x->timer)) | 72 | if (del_timer(&x->timer)) |
64 | BUG(); | 73 | BUG(); |
74 | if (del_timer(&x->rtimer)) | ||
75 | BUG(); | ||
65 | kfree(x->aalg); | 76 | kfree(x->aalg); |
66 | kfree(x->ealg); | 77 | kfree(x->ealg); |
67 | kfree(x->calg); | 78 | kfree(x->calg); |
@@ -153,7 +164,7 @@ static void xfrm_timer_handler(unsigned long data) | |||
153 | 164 | ||
154 | x->km.dying = warn; | 165 | x->km.dying = warn; |
155 | if (warn) | 166 | if (warn) |
156 | km_state_expired(x, 0); | 167 | km_state_expired(x, 0, 0); |
157 | resched: | 168 | resched: |
158 | if (next != LONG_MAX && | 169 | if (next != LONG_MAX && |
159 | !mod_timer(&x->timer, jiffies + make_jiffies(next))) | 170 | !mod_timer(&x->timer, jiffies + make_jiffies(next))) |
@@ -168,13 +179,15 @@ expired: | |||
168 | goto resched; | 179 | goto resched; |
169 | } | 180 | } |
170 | if (!__xfrm_state_delete(x) && x->id.spi) | 181 | if (!__xfrm_state_delete(x) && x->id.spi) |
171 | km_state_expired(x, 1); | 182 | km_state_expired(x, 1, 0); |
172 | 183 | ||
173 | out: | 184 | out: |
174 | spin_unlock(&x->lock); | 185 | spin_unlock(&x->lock); |
175 | xfrm_state_put(x); | 186 | xfrm_state_put(x); |
176 | } | 187 | } |
177 | 188 | ||
189 | static void xfrm_replay_timer_handler(unsigned long data); | ||
190 | |||
178 | struct xfrm_state *xfrm_state_alloc(void) | 191 | struct xfrm_state *xfrm_state_alloc(void) |
179 | { | 192 | { |
180 | struct xfrm_state *x; | 193 | struct xfrm_state *x; |
@@ -190,11 +203,16 @@ struct xfrm_state *xfrm_state_alloc(void) | |||
190 | init_timer(&x->timer); | 203 | init_timer(&x->timer); |
191 | x->timer.function = xfrm_timer_handler; | 204 | x->timer.function = xfrm_timer_handler; |
192 | x->timer.data = (unsigned long)x; | 205 | x->timer.data = (unsigned long)x; |
206 | init_timer(&x->rtimer); | ||
207 | x->rtimer.function = xfrm_replay_timer_handler; | ||
208 | x->rtimer.data = (unsigned long)x; | ||
193 | x->curlft.add_time = (unsigned long)xtime.tv_sec; | 209 | x->curlft.add_time = (unsigned long)xtime.tv_sec; |
194 | x->lft.soft_byte_limit = XFRM_INF; | 210 | x->lft.soft_byte_limit = XFRM_INF; |
195 | x->lft.soft_packet_limit = XFRM_INF; | 211 | x->lft.soft_packet_limit = XFRM_INF; |
196 | x->lft.hard_byte_limit = XFRM_INF; | 212 | x->lft.hard_byte_limit = XFRM_INF; |
197 | x->lft.hard_packet_limit = XFRM_INF; | 213 | x->lft.hard_packet_limit = XFRM_INF; |
214 | x->replay_maxage = 0; | ||
215 | x->replay_maxdiff = 0; | ||
198 | spin_lock_init(&x->lock); | 216 | spin_lock_init(&x->lock); |
199 | } | 217 | } |
200 | return x; | 218 | return x; |
@@ -212,7 +230,7 @@ void __xfrm_state_destroy(struct xfrm_state *x) | |||
212 | } | 230 | } |
213 | EXPORT_SYMBOL(__xfrm_state_destroy); | 231 | EXPORT_SYMBOL(__xfrm_state_destroy); |
214 | 232 | ||
215 | static int __xfrm_state_delete(struct xfrm_state *x) | 233 | int __xfrm_state_delete(struct xfrm_state *x) |
216 | { | 234 | { |
217 | int err = -ESRCH; | 235 | int err = -ESRCH; |
218 | 236 | ||
@@ -228,6 +246,8 @@ static int __xfrm_state_delete(struct xfrm_state *x) | |||
228 | spin_unlock(&xfrm_state_lock); | 246 | spin_unlock(&xfrm_state_lock); |
229 | if (del_timer(&x->timer)) | 247 | if (del_timer(&x->timer)) |
230 | __xfrm_state_put(x); | 248 | __xfrm_state_put(x); |
249 | if (del_timer(&x->rtimer)) | ||
250 | __xfrm_state_put(x); | ||
231 | 251 | ||
232 | /* The number two in this test is the reference | 252 | /* The number two in this test is the reference |
233 | * mentioned in the comment below plus the reference | 253 | * mentioned in the comment below plus the reference |
@@ -249,6 +269,7 @@ static int __xfrm_state_delete(struct xfrm_state *x) | |||
249 | 269 | ||
250 | return err; | 270 | return err; |
251 | } | 271 | } |
272 | EXPORT_SYMBOL(__xfrm_state_delete); | ||
252 | 273 | ||
253 | int xfrm_state_delete(struct xfrm_state *x) | 274 | int xfrm_state_delete(struct xfrm_state *x) |
254 | { | 275 | { |
@@ -426,6 +447,10 @@ static void __xfrm_state_insert(struct xfrm_state *x) | |||
426 | if (!mod_timer(&x->timer, jiffies + HZ)) | 447 | if (!mod_timer(&x->timer, jiffies + HZ)) |
427 | xfrm_state_hold(x); | 448 | xfrm_state_hold(x); |
428 | 449 | ||
450 | if (x->replay_maxage && | ||
451 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) | ||
452 | xfrm_state_hold(x); | ||
453 | |||
429 | wake_up(&km_waitq); | 454 | wake_up(&km_waitq); |
430 | } | 455 | } |
431 | 456 | ||
@@ -580,7 +605,7 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
580 | (x->curlft.bytes >= x->lft.soft_byte_limit || | 605 | (x->curlft.bytes >= x->lft.soft_byte_limit || |
581 | x->curlft.packets >= x->lft.soft_packet_limit)) { | 606 | x->curlft.packets >= x->lft.soft_packet_limit)) { |
582 | x->km.dying = 1; | 607 | x->km.dying = 1; |
583 | km_state_expired(x, 0); | 608 | km_state_expired(x, 0, 0); |
584 | } | 609 | } |
585 | return 0; | 610 | return 0; |
586 | } | 611 | } |
@@ -762,6 +787,61 @@ out: | |||
762 | } | 787 | } |
763 | EXPORT_SYMBOL(xfrm_state_walk); | 788 | EXPORT_SYMBOL(xfrm_state_walk); |
764 | 789 | ||
790 | |||
791 | void xfrm_replay_notify(struct xfrm_state *x, int event) | ||
792 | { | ||
793 | struct km_event c; | ||
794 | /* we send notify messages in case | ||
795 | * 1. we updated on of the sequence numbers, and the seqno difference | ||
796 | * is at least x->replay_maxdiff, in this case we also update the | ||
797 | * timeout of our timer function | ||
798 | * 2. if x->replay_maxage has elapsed since last update, | ||
799 | * and there were changes | ||
800 | * | ||
801 | * The state structure must be locked! | ||
802 | */ | ||
803 | |||
804 | switch (event) { | ||
805 | case XFRM_REPLAY_UPDATE: | ||
806 | if (x->replay_maxdiff && | ||
807 | (x->replay.seq - x->preplay.seq < x->replay_maxdiff) && | ||
808 | (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) | ||
809 | return; | ||
810 | |||
811 | break; | ||
812 | |||
813 | case XFRM_REPLAY_TIMEOUT: | ||
814 | if ((x->replay.seq == x->preplay.seq) && | ||
815 | (x->replay.bitmap == x->preplay.bitmap) && | ||
816 | (x->replay.oseq == x->preplay.oseq)) | ||
817 | return; | ||
818 | |||
819 | break; | ||
820 | } | ||
821 | |||
822 | memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state)); | ||
823 | c.event = XFRM_MSG_NEWAE; | ||
824 | c.data.aevent = event; | ||
825 | km_state_notify(x, &c); | ||
826 | |||
827 | if (x->replay_maxage && | ||
828 | !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) | ||
829 | xfrm_state_hold(x); | ||
830 | } | ||
831 | EXPORT_SYMBOL(xfrm_replay_notify); | ||
832 | |||
833 | static void xfrm_replay_timer_handler(unsigned long data) | ||
834 | { | ||
835 | struct xfrm_state *x = (struct xfrm_state*)data; | ||
836 | |||
837 | spin_lock(&x->lock); | ||
838 | |||
839 | if (xfrm_aevent_is_on() && x->km.state == XFRM_STATE_VALID) | ||
840 | xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT); | ||
841 | |||
842 | spin_unlock(&x->lock); | ||
843 | } | ||
844 | |||
765 | int xfrm_replay_check(struct xfrm_state *x, u32 seq) | 845 | int xfrm_replay_check(struct xfrm_state *x, u32 seq) |
766 | { | 846 | { |
767 | u32 diff; | 847 | u32 diff; |
@@ -805,6 +885,9 @@ void xfrm_replay_advance(struct xfrm_state *x, u32 seq) | |||
805 | diff = x->replay.seq - seq; | 885 | diff = x->replay.seq - seq; |
806 | x->replay.bitmap |= (1U << diff); | 886 | x->replay.bitmap |= (1U << diff); |
807 | } | 887 | } |
888 | |||
889 | if (xfrm_aevent_is_on()) | ||
890 | xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); | ||
808 | } | 891 | } |
809 | EXPORT_SYMBOL(xfrm_replay_advance); | 892 | EXPORT_SYMBOL(xfrm_replay_advance); |
810 | 893 | ||
@@ -835,11 +918,12 @@ void km_state_notify(struct xfrm_state *x, struct km_event *c) | |||
835 | EXPORT_SYMBOL(km_policy_notify); | 918 | EXPORT_SYMBOL(km_policy_notify); |
836 | EXPORT_SYMBOL(km_state_notify); | 919 | EXPORT_SYMBOL(km_state_notify); |
837 | 920 | ||
838 | static void km_state_expired(struct xfrm_state *x, int hard) | 921 | void km_state_expired(struct xfrm_state *x, int hard, u32 pid) |
839 | { | 922 | { |
840 | struct km_event c; | 923 | struct km_event c; |
841 | 924 | ||
842 | c.data.hard = hard; | 925 | c.data.hard = hard; |
926 | c.pid = pid; | ||
843 | c.event = XFRM_MSG_EXPIRE; | 927 | c.event = XFRM_MSG_EXPIRE; |
844 | km_state_notify(x, &c); | 928 | km_state_notify(x, &c); |
845 | 929 | ||
@@ -847,11 +931,12 @@ static void km_state_expired(struct xfrm_state *x, int hard) | |||
847 | wake_up(&km_waitq); | 931 | wake_up(&km_waitq); |
848 | } | 932 | } |
849 | 933 | ||
934 | EXPORT_SYMBOL(km_state_expired); | ||
850 | /* | 935 | /* |
851 | * We send to all registered managers regardless of failure | 936 | * We send to all registered managers regardless of failure |
852 | * We are happy with one success | 937 | * We are happy with one success |
853 | */ | 938 | */ |
854 | static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) | 939 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) |
855 | { | 940 | { |
856 | int err = -EINVAL, acqret; | 941 | int err = -EINVAL, acqret; |
857 | struct xfrm_mgr *km; | 942 | struct xfrm_mgr *km; |
@@ -865,6 +950,7 @@ static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_polic | |||
865 | read_unlock(&xfrm_km_lock); | 950 | read_unlock(&xfrm_km_lock); |
866 | return err; | 951 | return err; |
867 | } | 952 | } |
953 | EXPORT_SYMBOL(km_query); | ||
868 | 954 | ||
869 | int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport) | 955 | int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport) |
870 | { | 956 | { |
@@ -883,17 +969,19 @@ int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport) | |||
883 | } | 969 | } |
884 | EXPORT_SYMBOL(km_new_mapping); | 970 | EXPORT_SYMBOL(km_new_mapping); |
885 | 971 | ||
886 | void km_policy_expired(struct xfrm_policy *pol, int dir, int hard) | 972 | void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid) |
887 | { | 973 | { |
888 | struct km_event c; | 974 | struct km_event c; |
889 | 975 | ||
890 | c.data.hard = hard; | 976 | c.data.hard = hard; |
977 | c.pid = pid; | ||
891 | c.event = XFRM_MSG_POLEXPIRE; | 978 | c.event = XFRM_MSG_POLEXPIRE; |
892 | km_policy_notify(pol, dir, &c); | 979 | km_policy_notify(pol, dir, &c); |
893 | 980 | ||
894 | if (hard) | 981 | if (hard) |
895 | wake_up(&km_waitq); | 982 | wake_up(&km_waitq); |
896 | } | 983 | } |
984 | EXPORT_SYMBOL(km_policy_expired); | ||
897 | 985 | ||
898 | int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) | 986 | int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) |
899 | { | 987 | { |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 7de17559249a..81d1005830f4 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -28,8 +28,6 @@ | |||
28 | #include <net/netlink.h> | 28 | #include <net/netlink.h> |
29 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
30 | 30 | ||
31 | static struct sock *xfrm_nl; | ||
32 | |||
33 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) | 31 | static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type) |
34 | { | 32 | { |
35 | struct rtattr *rt = xfrma[type - 1]; | 33 | struct rtattr *rt = xfrma[type - 1]; |
@@ -103,9 +101,6 @@ static inline int verify_sec_ctx_len(struct rtattr **xfrma) | |||
103 | 101 | ||
104 | uctx = RTA_DATA(rt); | 102 | uctx = RTA_DATA(rt); |
105 | 103 | ||
106 | if (uctx->ctx_len > PAGE_SIZE) | ||
107 | return -EINVAL; | ||
108 | |||
109 | len += sizeof(struct xfrm_user_sec_ctx); | 104 | len += sizeof(struct xfrm_user_sec_ctx); |
110 | len += uctx->ctx_len; | 105 | len += uctx->ctx_len; |
111 | 106 | ||
@@ -276,6 +271,56 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info * | |||
276 | x->props.flags = p->flags; | 271 | x->props.flags = p->flags; |
277 | } | 272 | } |
278 | 273 | ||
274 | /* | ||
275 | * someday when pfkey also has support, we could have the code | ||
276 | * somehow made shareable and move it to xfrm_state.c - JHS | ||
277 | * | ||
278 | */ | ||
279 | static int xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma) | ||
280 | { | ||
281 | int err = - EINVAL; | ||
282 | struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; | ||
283 | struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; | ||
284 | struct rtattr *et = xfrma[XFRMA_ETIMER_THRESH-1]; | ||
285 | struct rtattr *rt = xfrma[XFRMA_REPLAY_THRESH-1]; | ||
286 | |||
287 | if (rp) { | ||
288 | struct xfrm_replay_state *replay; | ||
289 | if (RTA_PAYLOAD(rp) < sizeof(*replay)) | ||
290 | goto error; | ||
291 | replay = RTA_DATA(rp); | ||
292 | memcpy(&x->replay, replay, sizeof(*replay)); | ||
293 | memcpy(&x->preplay, replay, sizeof(*replay)); | ||
294 | } | ||
295 | |||
296 | if (lt) { | ||
297 | struct xfrm_lifetime_cur *ltime; | ||
298 | if (RTA_PAYLOAD(lt) < sizeof(*ltime)) | ||
299 | goto error; | ||
300 | ltime = RTA_DATA(lt); | ||
301 | x->curlft.bytes = ltime->bytes; | ||
302 | x->curlft.packets = ltime->packets; | ||
303 | x->curlft.add_time = ltime->add_time; | ||
304 | x->curlft.use_time = ltime->use_time; | ||
305 | } | ||
306 | |||
307 | if (et) { | ||
308 | if (RTA_PAYLOAD(et) < sizeof(u32)) | ||
309 | goto error; | ||
310 | x->replay_maxage = *(u32*)RTA_DATA(et); | ||
311 | } | ||
312 | |||
313 | if (rt) { | ||
314 | if (RTA_PAYLOAD(rt) < sizeof(u32)) | ||
315 | goto error; | ||
316 | x->replay_maxdiff = *(u32*)RTA_DATA(rt); | ||
317 | } | ||
318 | |||
319 | return 0; | ||
320 | error: | ||
321 | return err; | ||
322 | } | ||
323 | |||
279 | static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, | 324 | static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, |
280 | struct rtattr **xfrma, | 325 | struct rtattr **xfrma, |
281 | int *errp) | 326 | int *errp) |
@@ -311,6 +356,18 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, | |||
311 | goto error; | 356 | goto error; |
312 | 357 | ||
313 | x->km.seq = p->seq; | 358 | x->km.seq = p->seq; |
359 | x->replay_maxdiff = sysctl_xfrm_aevent_rseqth; | ||
360 | /* sysctl_xfrm_aevent_etime is in 100ms units */ | ||
361 | x->replay_maxage = (sysctl_xfrm_aevent_etime*HZ)/XFRM_AE_ETH_M; | ||
362 | x->preplay.bitmap = 0; | ||
363 | x->preplay.seq = x->replay.seq+x->replay_maxdiff; | ||
364 | x->preplay.oseq = x->replay.oseq +x->replay_maxdiff; | ||
365 | |||
366 | /* override default values from above */ | ||
367 | |||
368 | err = xfrm_update_ae_params(x, (struct rtattr **)xfrma); | ||
369 | if (err < 0) | ||
370 | goto error; | ||
314 | 371 | ||
315 | return x; | 372 | return x; |
316 | 373 | ||
@@ -1025,9 +1082,142 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma | |||
1025 | return 0; | 1082 | return 0; |
1026 | } | 1083 | } |
1027 | 1084 | ||
1028 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | 1085 | |
1086 | static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) | ||
1087 | { | ||
1088 | struct xfrm_aevent_id *id; | ||
1089 | struct nlmsghdr *nlh; | ||
1090 | struct xfrm_lifetime_cur ltime; | ||
1091 | unsigned char *b = skb->tail; | ||
1092 | |||
1093 | nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id)); | ||
1094 | id = NLMSG_DATA(nlh); | ||
1095 | nlh->nlmsg_flags = 0; | ||
1096 | |||
1097 | id->sa_id.daddr = x->id.daddr; | ||
1098 | id->sa_id.spi = x->id.spi; | ||
1099 | id->sa_id.family = x->props.family; | ||
1100 | id->sa_id.proto = x->id.proto; | ||
1101 | id->flags = c->data.aevent; | ||
1102 | |||
1103 | RTA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay); | ||
1104 | |||
1105 | ltime.bytes = x->curlft.bytes; | ||
1106 | ltime.packets = x->curlft.packets; | ||
1107 | ltime.add_time = x->curlft.add_time; | ||
1108 | ltime.use_time = x->curlft.use_time; | ||
1109 | |||
1110 | RTA_PUT(skb, XFRMA_LTIME_VAL, sizeof(struct xfrm_lifetime_cur), <ime); | ||
1111 | |||
1112 | if (id->flags&XFRM_AE_RTHR) { | ||
1113 | RTA_PUT(skb,XFRMA_REPLAY_THRESH,sizeof(u32),&x->replay_maxdiff); | ||
1114 | } | ||
1115 | |||
1116 | if (id->flags&XFRM_AE_ETHR) { | ||
1117 | u32 etimer = x->replay_maxage*10/HZ; | ||
1118 | RTA_PUT(skb,XFRMA_ETIMER_THRESH,sizeof(u32),&etimer); | ||
1119 | } | ||
1120 | |||
1121 | nlh->nlmsg_len = skb->tail - b; | ||
1122 | return skb->len; | ||
1123 | |||
1124 | rtattr_failure: | ||
1125 | nlmsg_failure: | ||
1126 | skb_trim(skb, b - skb->data); | ||
1127 | return -1; | ||
1128 | } | ||
1129 | |||
1130 | static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1131 | { | ||
1132 | struct xfrm_state *x; | ||
1133 | struct sk_buff *r_skb; | ||
1134 | int err; | ||
1135 | struct km_event c; | ||
1136 | struct xfrm_aevent_id *p = NLMSG_DATA(nlh); | ||
1137 | int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); | ||
1138 | struct xfrm_usersa_id *id = &p->sa_id; | ||
1139 | |||
1140 | len += RTA_SPACE(sizeof(struct xfrm_replay_state)); | ||
1141 | len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); | ||
1142 | |||
1143 | if (p->flags&XFRM_AE_RTHR) | ||
1144 | len+=RTA_SPACE(sizeof(u32)); | ||
1145 | |||
1146 | if (p->flags&XFRM_AE_ETHR) | ||
1147 | len+=RTA_SPACE(sizeof(u32)); | ||
1148 | |||
1149 | r_skb = alloc_skb(len, GFP_ATOMIC); | ||
1150 | if (r_skb == NULL) | ||
1151 | return -ENOMEM; | ||
1152 | |||
1153 | x = xfrm_state_lookup(&id->daddr, id->spi, id->proto, id->family); | ||
1154 | if (x == NULL) { | ||
1155 | kfree(r_skb); | ||
1156 | return -ESRCH; | ||
1157 | } | ||
1158 | |||
1159 | /* | ||
1160 | * XXX: is this lock really needed - none of the other | ||
1161 | * gets lock (the concern is things getting updated | ||
1162 | * while we are still reading) - jhs | ||
1163 | */ | ||
1164 | spin_lock_bh(&x->lock); | ||
1165 | c.data.aevent = p->flags; | ||
1166 | c.seq = nlh->nlmsg_seq; | ||
1167 | c.pid = nlh->nlmsg_pid; | ||
1168 | |||
1169 | if (build_aevent(r_skb, x, &c) < 0) | ||
1170 | BUG(); | ||
1171 | err = netlink_unicast(xfrm_nl, r_skb, | ||
1172 | NETLINK_CB(skb).pid, MSG_DONTWAIT); | ||
1173 | spin_unlock_bh(&x->lock); | ||
1174 | xfrm_state_put(x); | ||
1175 | return err; | ||
1176 | } | ||
1177 | |||
1178 | static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1029 | { | 1179 | { |
1180 | struct xfrm_state *x; | ||
1030 | struct km_event c; | 1181 | struct km_event c; |
1182 | int err = - EINVAL; | ||
1183 | struct xfrm_aevent_id *p = NLMSG_DATA(nlh); | ||
1184 | struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1]; | ||
1185 | struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1]; | ||
1186 | |||
1187 | if (!lt && !rp) | ||
1188 | return err; | ||
1189 | |||
1190 | /* pedantic mode - thou shalt sayeth replaceth */ | ||
1191 | if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) | ||
1192 | return err; | ||
1193 | |||
1194 | x = xfrm_state_lookup(&p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); | ||
1195 | if (x == NULL) | ||
1196 | return -ESRCH; | ||
1197 | |||
1198 | if (x->km.state != XFRM_STATE_VALID) | ||
1199 | goto out; | ||
1200 | |||
1201 | spin_lock_bh(&x->lock); | ||
1202 | err = xfrm_update_ae_params(x,(struct rtattr **)xfrma); | ||
1203 | spin_unlock_bh(&x->lock); | ||
1204 | if (err < 0) | ||
1205 | goto out; | ||
1206 | |||
1207 | c.event = nlh->nlmsg_type; | ||
1208 | c.seq = nlh->nlmsg_seq; | ||
1209 | c.pid = nlh->nlmsg_pid; | ||
1210 | c.data.aevent = XFRM_AE_CU; | ||
1211 | km_state_notify(x, &c); | ||
1212 | err = 0; | ||
1213 | out: | ||
1214 | xfrm_state_put(x); | ||
1215 | return err; | ||
1216 | } | ||
1217 | |||
1218 | static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1219 | { | ||
1220 | struct km_event c; | ||
1031 | 1221 | ||
1032 | xfrm_policy_flush(); | 1222 | xfrm_policy_flush(); |
1033 | c.event = nlh->nlmsg_type; | 1223 | c.event = nlh->nlmsg_type; |
@@ -1037,6 +1227,139 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **x | |||
1037 | return 0; | 1227 | return 0; |
1038 | } | 1228 | } |
1039 | 1229 | ||
1230 | static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1231 | { | ||
1232 | struct xfrm_policy *xp; | ||
1233 | struct xfrm_user_polexpire *up = NLMSG_DATA(nlh); | ||
1234 | struct xfrm_userpolicy_info *p = &up->pol; | ||
1235 | int err = -ENOENT; | ||
1236 | |||
1237 | if (p->index) | ||
1238 | xp = xfrm_policy_byid(p->dir, p->index, 0); | ||
1239 | else { | ||
1240 | struct rtattr **rtattrs = (struct rtattr **)xfrma; | ||
1241 | struct rtattr *rt = rtattrs[XFRMA_SEC_CTX-1]; | ||
1242 | struct xfrm_policy tmp; | ||
1243 | |||
1244 | err = verify_sec_ctx_len(rtattrs); | ||
1245 | if (err) | ||
1246 | return err; | ||
1247 | |||
1248 | memset(&tmp, 0, sizeof(struct xfrm_policy)); | ||
1249 | if (rt) { | ||
1250 | struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt); | ||
1251 | |||
1252 | if ((err = security_xfrm_policy_alloc(&tmp, uctx))) | ||
1253 | return err; | ||
1254 | } | ||
1255 | xp = xfrm_policy_bysel_ctx(p->dir, &p->sel, tmp.security, 0); | ||
1256 | security_xfrm_policy_free(&tmp); | ||
1257 | } | ||
1258 | |||
1259 | if (xp == NULL) | ||
1260 | return err; | ||
1261 | read_lock(&xp->lock); | ||
1262 | if (xp->dead) { | ||
1263 | read_unlock(&xp->lock); | ||
1264 | goto out; | ||
1265 | } | ||
1266 | |||
1267 | read_unlock(&xp->lock); | ||
1268 | err = 0; | ||
1269 | if (up->hard) { | ||
1270 | xfrm_policy_delete(xp, p->dir); | ||
1271 | } else { | ||
1272 | // reset the timers here? | ||
1273 | printk("Dont know what to do with soft policy expire\n"); | ||
1274 | } | ||
1275 | km_policy_expired(xp, p->dir, up->hard, current->pid); | ||
1276 | |||
1277 | out: | ||
1278 | xfrm_pol_put(xp); | ||
1279 | return err; | ||
1280 | } | ||
1281 | |||
1282 | static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1283 | { | ||
1284 | struct xfrm_state *x; | ||
1285 | int err; | ||
1286 | struct xfrm_user_expire *ue = NLMSG_DATA(nlh); | ||
1287 | struct xfrm_usersa_info *p = &ue->state; | ||
1288 | |||
1289 | x = xfrm_state_lookup(&p->id.daddr, p->id.spi, p->id.proto, p->family); | ||
1290 | err = -ENOENT; | ||
1291 | |||
1292 | if (x == NULL) | ||
1293 | return err; | ||
1294 | |||
1295 | err = -EINVAL; | ||
1296 | |||
1297 | spin_lock_bh(&x->lock); | ||
1298 | if (x->km.state != XFRM_STATE_VALID) | ||
1299 | goto out; | ||
1300 | km_state_expired(x, ue->hard, current->pid); | ||
1301 | |||
1302 | if (ue->hard) | ||
1303 | __xfrm_state_delete(x); | ||
1304 | out: | ||
1305 | spin_unlock_bh(&x->lock); | ||
1306 | xfrm_state_put(x); | ||
1307 | return err; | ||
1308 | } | ||
1309 | |||
1310 | static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) | ||
1311 | { | ||
1312 | struct xfrm_policy *xp; | ||
1313 | struct xfrm_user_tmpl *ut; | ||
1314 | int i; | ||
1315 | struct rtattr *rt = xfrma[XFRMA_TMPL-1]; | ||
1316 | |||
1317 | struct xfrm_user_acquire *ua = NLMSG_DATA(nlh); | ||
1318 | struct xfrm_state *x = xfrm_state_alloc(); | ||
1319 | int err = -ENOMEM; | ||
1320 | |||
1321 | if (!x) | ||
1322 | return err; | ||
1323 | |||
1324 | err = verify_newpolicy_info(&ua->policy); | ||
1325 | if (err) { | ||
1326 | printk("BAD policy passed\n"); | ||
1327 | kfree(x); | ||
1328 | return err; | ||
1329 | } | ||
1330 | |||
1331 | /* build an XP */ | ||
1332 | xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err); if (!xp) { | ||
1333 | kfree(x); | ||
1334 | return err; | ||
1335 | } | ||
1336 | |||
1337 | memcpy(&x->id, &ua->id, sizeof(ua->id)); | ||
1338 | memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); | ||
1339 | memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); | ||
1340 | |||
1341 | ut = RTA_DATA(rt); | ||
1342 | /* extract the templates and for each call km_key */ | ||
1343 | for (i = 0; i < xp->xfrm_nr; i++, ut++) { | ||
1344 | struct xfrm_tmpl *t = &xp->xfrm_vec[i]; | ||
1345 | memcpy(&x->id, &t->id, sizeof(x->id)); | ||
1346 | x->props.mode = t->mode; | ||
1347 | x->props.reqid = t->reqid; | ||
1348 | x->props.family = ut->family; | ||
1349 | t->aalgos = ua->aalgos; | ||
1350 | t->ealgos = ua->ealgos; | ||
1351 | t->calgos = ua->calgos; | ||
1352 | err = km_query(x, t, xp); | ||
1353 | |||
1354 | } | ||
1355 | |||
1356 | kfree(x); | ||
1357 | kfree(xp); | ||
1358 | |||
1359 | return 0; | ||
1360 | } | ||
1361 | |||
1362 | |||
1040 | #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type)) | 1363 | #define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type)) |
1041 | 1364 | ||
1042 | static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | 1365 | static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { |
@@ -1054,6 +1377,8 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | |||
1054 | [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire), | 1377 | [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire), |
1055 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), | 1378 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), |
1056 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), | 1379 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0), |
1380 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | ||
1381 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), | ||
1057 | }; | 1382 | }; |
1058 | 1383 | ||
1059 | #undef XMSGSIZE | 1384 | #undef XMSGSIZE |
@@ -1071,10 +1396,15 @@ static struct xfrm_link { | |||
1071 | [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, | 1396 | [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, |
1072 | .dump = xfrm_dump_policy }, | 1397 | .dump = xfrm_dump_policy }, |
1073 | [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, | 1398 | [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, |
1399 | [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, | ||
1400 | [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, | ||
1074 | [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, | 1401 | [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, |
1075 | [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, | 1402 | [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, |
1403 | [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire}, | ||
1076 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa }, | 1404 | [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa }, |
1077 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, | 1405 | [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, |
1406 | [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae }, | ||
1407 | [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae }, | ||
1078 | }; | 1408 | }; |
1079 | 1409 | ||
1080 | static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) | 1410 | static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) |
@@ -1156,26 +1486,26 @@ static void xfrm_netlink_rcv(struct sock *sk, int len) | |||
1156 | unsigned int qlen = 0; | 1486 | unsigned int qlen = 0; |
1157 | 1487 | ||
1158 | do { | 1488 | do { |
1159 | down(&xfrm_cfg_sem); | 1489 | mutex_lock(&xfrm_cfg_mutex); |
1160 | netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg); | 1490 | netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg); |
1161 | up(&xfrm_cfg_sem); | 1491 | mutex_unlock(&xfrm_cfg_mutex); |
1162 | 1492 | ||
1163 | } while (qlen); | 1493 | } while (qlen); |
1164 | } | 1494 | } |
1165 | 1495 | ||
1166 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int hard) | 1496 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) |
1167 | { | 1497 | { |
1168 | struct xfrm_user_expire *ue; | 1498 | struct xfrm_user_expire *ue; |
1169 | struct nlmsghdr *nlh; | 1499 | struct nlmsghdr *nlh; |
1170 | unsigned char *b = skb->tail; | 1500 | unsigned char *b = skb->tail; |
1171 | 1501 | ||
1172 | nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_EXPIRE, | 1502 | nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_EXPIRE, |
1173 | sizeof(*ue)); | 1503 | sizeof(*ue)); |
1174 | ue = NLMSG_DATA(nlh); | 1504 | ue = NLMSG_DATA(nlh); |
1175 | nlh->nlmsg_flags = 0; | 1505 | nlh->nlmsg_flags = 0; |
1176 | 1506 | ||
1177 | copy_to_user_state(x, &ue->state); | 1507 | copy_to_user_state(x, &ue->state); |
1178 | ue->hard = (hard != 0) ? 1 : 0; | 1508 | ue->hard = (c->data.hard != 0) ? 1 : 0; |
1179 | 1509 | ||
1180 | nlh->nlmsg_len = skb->tail - b; | 1510 | nlh->nlmsg_len = skb->tail - b; |
1181 | return skb->len; | 1511 | return skb->len; |
@@ -1194,13 +1524,31 @@ static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) | |||
1194 | if (skb == NULL) | 1524 | if (skb == NULL) |
1195 | return -ENOMEM; | 1525 | return -ENOMEM; |
1196 | 1526 | ||
1197 | if (build_expire(skb, x, c->data.hard) < 0) | 1527 | if (build_expire(skb, x, c) < 0) |
1198 | BUG(); | 1528 | BUG(); |
1199 | 1529 | ||
1200 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; | 1530 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; |
1201 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); | 1531 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); |
1202 | } | 1532 | } |
1203 | 1533 | ||
1534 | static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c) | ||
1535 | { | ||
1536 | struct sk_buff *skb; | ||
1537 | int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id)); | ||
1538 | |||
1539 | len += RTA_SPACE(sizeof(struct xfrm_replay_state)); | ||
1540 | len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur)); | ||
1541 | skb = alloc_skb(len, GFP_ATOMIC); | ||
1542 | if (skb == NULL) | ||
1543 | return -ENOMEM; | ||
1544 | |||
1545 | if (build_aevent(skb, x, c) < 0) | ||
1546 | BUG(); | ||
1547 | |||
1548 | NETLINK_CB(skb).dst_group = XFRMNLGRP_AEVENTS; | ||
1549 | return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC); | ||
1550 | } | ||
1551 | |||
1204 | static int xfrm_notify_sa_flush(struct km_event *c) | 1552 | static int xfrm_notify_sa_flush(struct km_event *c) |
1205 | { | 1553 | { |
1206 | struct xfrm_usersa_flush *p; | 1554 | struct xfrm_usersa_flush *p; |
@@ -1313,6 +1661,8 @@ static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c) | |||
1313 | switch (c->event) { | 1661 | switch (c->event) { |
1314 | case XFRM_MSG_EXPIRE: | 1662 | case XFRM_MSG_EXPIRE: |
1315 | return xfrm_exp_state_notify(x, c); | 1663 | return xfrm_exp_state_notify(x, c); |
1664 | case XFRM_MSG_NEWAE: | ||
1665 | return xfrm_aevent_state_notify(x, c); | ||
1316 | case XFRM_MSG_DELSA: | 1666 | case XFRM_MSG_DELSA: |
1317 | case XFRM_MSG_UPDSA: | 1667 | case XFRM_MSG_UPDSA: |
1318 | case XFRM_MSG_NEWSA: | 1668 | case XFRM_MSG_NEWSA: |
@@ -1443,13 +1793,14 @@ static struct xfrm_policy *xfrm_compile_policy(u16 family, int opt, | |||
1443 | } | 1793 | } |
1444 | 1794 | ||
1445 | static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, | 1795 | static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, |
1446 | int dir, int hard) | 1796 | int dir, struct km_event *c) |
1447 | { | 1797 | { |
1448 | struct xfrm_user_polexpire *upe; | 1798 | struct xfrm_user_polexpire *upe; |
1449 | struct nlmsghdr *nlh; | 1799 | struct nlmsghdr *nlh; |
1800 | int hard = c->data.hard; | ||
1450 | unsigned char *b = skb->tail; | 1801 | unsigned char *b = skb->tail; |
1451 | 1802 | ||
1452 | nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe)); | 1803 | nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe)); |
1453 | upe = NLMSG_DATA(nlh); | 1804 | upe = NLMSG_DATA(nlh); |
1454 | nlh->nlmsg_flags = 0; | 1805 | nlh->nlmsg_flags = 0; |
1455 | 1806 | ||
@@ -1480,7 +1831,7 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve | |||
1480 | if (skb == NULL) | 1831 | if (skb == NULL) |
1481 | return -ENOMEM; | 1832 | return -ENOMEM; |
1482 | 1833 | ||
1483 | if (build_polexpire(skb, xp, dir, c->data.hard) < 0) | 1834 | if (build_polexpire(skb, xp, dir, c) < 0) |
1484 | BUG(); | 1835 | BUG(); |
1485 | 1836 | ||
1486 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; | 1837 | NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE; |
@@ -1596,12 +1947,15 @@ static struct xfrm_mgr netlink_mgr = { | |||
1596 | 1947 | ||
1597 | static int __init xfrm_user_init(void) | 1948 | static int __init xfrm_user_init(void) |
1598 | { | 1949 | { |
1950 | struct sock *nlsk; | ||
1951 | |||
1599 | printk(KERN_INFO "Initializing IPsec netlink socket\n"); | 1952 | printk(KERN_INFO "Initializing IPsec netlink socket\n"); |
1600 | 1953 | ||
1601 | xfrm_nl = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, | 1954 | nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX, |
1602 | xfrm_netlink_rcv, THIS_MODULE); | 1955 | xfrm_netlink_rcv, THIS_MODULE); |
1603 | if (xfrm_nl == NULL) | 1956 | if (nlsk == NULL) |
1604 | return -ENOMEM; | 1957 | return -ENOMEM; |
1958 | rcu_assign_pointer(xfrm_nl, nlsk); | ||
1605 | 1959 | ||
1606 | xfrm_register_km(&netlink_mgr); | 1960 | xfrm_register_km(&netlink_mgr); |
1607 | 1961 | ||
@@ -1610,11 +1964,16 @@ static int __init xfrm_user_init(void) | |||
1610 | 1964 | ||
1611 | static void __exit xfrm_user_exit(void) | 1965 | static void __exit xfrm_user_exit(void) |
1612 | { | 1966 | { |
1967 | struct sock *nlsk = xfrm_nl; | ||
1968 | |||
1613 | xfrm_unregister_km(&netlink_mgr); | 1969 | xfrm_unregister_km(&netlink_mgr); |
1614 | sock_release(xfrm_nl->sk_socket); | 1970 | rcu_assign_pointer(xfrm_nl, NULL); |
1971 | synchronize_rcu(); | ||
1972 | sock_release(nlsk->sk_socket); | ||
1615 | } | 1973 | } |
1616 | 1974 | ||
1617 | module_init(xfrm_user_init); | 1975 | module_init(xfrm_user_init); |
1618 | module_exit(xfrm_user_exit); | 1976 | module_exit(xfrm_user_exit); |
1619 | MODULE_LICENSE("GPL"); | 1977 | MODULE_LICENSE("GPL"); |
1620 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); | 1978 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); |
1979 | |||