diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2005-09-08 05:39:55 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-09-08 05:39:55 -0400 |
commit | c324b44c34050cf2a9b58830e11c974806bd85d8 (patch) | |
tree | 3ac45a783221283925cd698334a8f5e7dd4c1df8 /net | |
parent | 2fcf522509cceea524b6e7ece8fd6759b682175a (diff) | |
parent | caf39e87cc1182f7dae84eefc43ca14d54c78ef9 (diff) |
Merge /spare/repo/linux-2.6/
Diffstat (limited to 'net')
76 files changed, 4645 insertions, 364 deletions
diff --git a/net/Kconfig b/net/Kconfig index c07aafb59a0f..2bdd5623fdd5 100644 --- a/net/Kconfig +++ b/net/Kconfig | |||
@@ -215,6 +215,7 @@ endmenu | |||
215 | source "net/ax25/Kconfig" | 215 | source "net/ax25/Kconfig" |
216 | source "net/irda/Kconfig" | 216 | source "net/irda/Kconfig" |
217 | source "net/bluetooth/Kconfig" | 217 | source "net/bluetooth/Kconfig" |
218 | source "net/ieee80211/Kconfig" | ||
218 | 219 | ||
219 | endif # if NET | 220 | endif # if NET |
220 | endmenu # Networking | 221 | endmenu # Networking |
diff --git a/net/Makefile b/net/Makefile index 7e6eff206c81..4aa2f46d2a56 100644 --- a/net/Makefile +++ b/net/Makefile | |||
@@ -44,6 +44,7 @@ obj-$(CONFIG_ECONET) += econet/ | |||
44 | obj-$(CONFIG_VLAN_8021Q) += 8021q/ | 44 | obj-$(CONFIG_VLAN_8021Q) += 8021q/ |
45 | obj-$(CONFIG_IP_DCCP) += dccp/ | 45 | obj-$(CONFIG_IP_DCCP) += dccp/ |
46 | obj-$(CONFIG_IP_SCTP) += sctp/ | 46 | obj-$(CONFIG_IP_SCTP) += sctp/ |
47 | obj-$(CONFIG_IEEE80211) += ieee80211/ | ||
47 | 48 | ||
48 | ifeq ($(CONFIG_NET),y) | 49 | ifeq ($(CONFIG_NET),y) |
49 | obj-$(CONFIG_SYSCTL) += sysctl_net.o | 50 | obj-$(CONFIG_SYSCTL) += sysctl_net.o |
diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c index 4dbb5af34a5e..d89056ec44d4 100644 --- a/net/atm/ioctl.c +++ b/net/atm/ioctl.c | |||
@@ -21,6 +21,7 @@ | |||
21 | 21 | ||
22 | #include "resources.h" | 22 | #include "resources.h" |
23 | #include "signaling.h" /* for WAITING and sigd_attach */ | 23 | #include "signaling.h" /* for WAITING and sigd_attach */ |
24 | #include "common.h" | ||
24 | 25 | ||
25 | 26 | ||
26 | static DECLARE_MUTEX(ioctl_mutex); | 27 | static DECLARE_MUTEX(ioctl_mutex); |
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index ea43dfb774e2..ed705ddad56b 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c | |||
@@ -1874,6 +1874,7 @@ static void ax25_info_stop(struct seq_file *seq, void *v) | |||
1874 | static int ax25_info_show(struct seq_file *seq, void *v) | 1874 | static int ax25_info_show(struct seq_file *seq, void *v) |
1875 | { | 1875 | { |
1876 | ax25_cb *ax25 = v; | 1876 | ax25_cb *ax25 = v; |
1877 | char buf[11]; | ||
1877 | int k; | 1878 | int k; |
1878 | 1879 | ||
1879 | 1880 | ||
@@ -1885,13 +1886,13 @@ static int ax25_info_show(struct seq_file *seq, void *v) | |||
1885 | seq_printf(seq, "%8.8lx %s %s%s ", | 1886 | seq_printf(seq, "%8.8lx %s %s%s ", |
1886 | (long) ax25, | 1887 | (long) ax25, |
1887 | ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name, | 1888 | ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name, |
1888 | ax2asc(&ax25->source_addr), | 1889 | ax2asc(buf, &ax25->source_addr), |
1889 | ax25->iamdigi? "*":""); | 1890 | ax25->iamdigi? "*":""); |
1890 | seq_printf(seq, "%s", ax2asc(&ax25->dest_addr)); | 1891 | seq_printf(seq, "%s", ax2asc(buf, &ax25->dest_addr)); |
1891 | 1892 | ||
1892 | for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) { | 1893 | for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) { |
1893 | seq_printf(seq, ",%s%s", | 1894 | seq_printf(seq, ",%s%s", |
1894 | ax2asc(&ax25->digipeat->calls[k]), | 1895 | ax2asc(buf, &ax25->digipeat->calls[k]), |
1895 | ax25->digipeat->repeated[k]? "*":""); | 1896 | ax25->digipeat->repeated[k]? "*":""); |
1896 | } | 1897 | } |
1897 | 1898 | ||
diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c index f4fa6dfb846e..dca179daf415 100644 --- a/net/ax25/ax25_addr.c +++ b/net/ax25/ax25_addr.c | |||
@@ -36,9 +36,8 @@ ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}}; | |||
36 | /* | 36 | /* |
37 | * ax25 -> ascii conversion | 37 | * ax25 -> ascii conversion |
38 | */ | 38 | */ |
39 | char *ax2asc(ax25_address *a) | 39 | char *ax2asc(char *buf, ax25_address *a) |
40 | { | 40 | { |
41 | static char buf[11]; | ||
42 | char c, *s; | 41 | char c, *s; |
43 | int n; | 42 | int n; |
44 | 43 | ||
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c index c288526da4ce..26b77d972220 100644 --- a/net/ax25/ax25_route.c +++ b/net/ax25/ax25_route.c | |||
@@ -298,6 +298,8 @@ static void ax25_rt_seq_stop(struct seq_file *seq, void *v) | |||
298 | 298 | ||
299 | static int ax25_rt_seq_show(struct seq_file *seq, void *v) | 299 | static int ax25_rt_seq_show(struct seq_file *seq, void *v) |
300 | { | 300 | { |
301 | char buf[11]; | ||
302 | |||
301 | if (v == SEQ_START_TOKEN) | 303 | if (v == SEQ_START_TOKEN) |
302 | seq_puts(seq, "callsign dev mode digipeaters\n"); | 304 | seq_puts(seq, "callsign dev mode digipeaters\n"); |
303 | else { | 305 | else { |
@@ -308,7 +310,7 @@ static int ax25_rt_seq_show(struct seq_file *seq, void *v) | |||
308 | if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0) | 310 | if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0) |
309 | callsign = "default"; | 311 | callsign = "default"; |
310 | else | 312 | else |
311 | callsign = ax2asc(&ax25_rt->callsign); | 313 | callsign = ax2asc(buf, &ax25_rt->callsign); |
312 | 314 | ||
313 | seq_printf(seq, "%-9s %-4s", | 315 | seq_printf(seq, "%-9s %-4s", |
314 | callsign, | 316 | callsign, |
@@ -328,7 +330,8 @@ static int ax25_rt_seq_show(struct seq_file *seq, void *v) | |||
328 | 330 | ||
329 | if (ax25_rt->digipeat != NULL) | 331 | if (ax25_rt->digipeat != NULL) |
330 | for (i = 0; i < ax25_rt->digipeat->ndigi; i++) | 332 | for (i = 0; i < ax25_rt->digipeat->ndigi; i++) |
331 | seq_printf(seq, " %s", ax2asc(&ax25_rt->digipeat->calls[i])); | 333 | seq_printf(seq, " %s", |
334 | ax2asc(buf, &ax25_rt->digipeat->calls[i])); | ||
332 | 335 | ||
333 | seq_puts(seq, "\n"); | 336 | seq_puts(seq, "\n"); |
334 | } | 337 | } |
diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c index a8b3822f3ee4..d53cc8615865 100644 --- a/net/ax25/ax25_uid.c +++ b/net/ax25/ax25_uid.c | |||
@@ -168,12 +168,14 @@ static void ax25_uid_seq_stop(struct seq_file *seq, void *v) | |||
168 | 168 | ||
169 | static int ax25_uid_seq_show(struct seq_file *seq, void *v) | 169 | static int ax25_uid_seq_show(struct seq_file *seq, void *v) |
170 | { | 170 | { |
171 | char buf[11]; | ||
172 | |||
171 | if (v == SEQ_START_TOKEN) | 173 | if (v == SEQ_START_TOKEN) |
172 | seq_printf(seq, "Policy: %d\n", ax25_uid_policy); | 174 | seq_printf(seq, "Policy: %d\n", ax25_uid_policy); |
173 | else { | 175 | else { |
174 | struct ax25_uid_assoc *pt = v; | 176 | struct ax25_uid_assoc *pt = v; |
175 | 177 | ||
176 | seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(&pt->call)); | 178 | seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(buf, &pt->call)); |
177 | } | 179 | } |
178 | return 0; | 180 | return 0; |
179 | } | 181 | } |
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 289c1b5a8e4a..404b761e82ce 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -695,7 +695,7 @@ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr) | |||
695 | return ret; | 695 | return ret; |
696 | } | 696 | } |
697 | 697 | ||
698 | static int ethtool_get_perm_addr(struct net_device *dev, void *useraddr) | 698 | static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr) |
699 | { | 699 | { |
700 | struct ethtool_perm_addr epaddr; | 700 | struct ethtool_perm_addr epaddr; |
701 | u8 *data; | 701 | u8 *data; |
diff --git a/net/core/filter.c b/net/core/filter.c index cd91a24f9720..079c2edff789 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -182,7 +182,7 @@ int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen) | |||
182 | A = ntohl(*(u32 *)ptr); | 182 | A = ntohl(*(u32 *)ptr); |
183 | continue; | 183 | continue; |
184 | } | 184 | } |
185 | return 0; | 185 | break; |
186 | case BPF_LD|BPF_H|BPF_ABS: | 186 | case BPF_LD|BPF_H|BPF_ABS: |
187 | k = fentry->k; | 187 | k = fentry->k; |
188 | load_h: | 188 | load_h: |
@@ -191,7 +191,7 @@ int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen) | |||
191 | A = ntohs(*(u16 *)ptr); | 191 | A = ntohs(*(u16 *)ptr); |
192 | continue; | 192 | continue; |
193 | } | 193 | } |
194 | return 0; | 194 | break; |
195 | case BPF_LD|BPF_B|BPF_ABS: | 195 | case BPF_LD|BPF_B|BPF_ABS: |
196 | k = fentry->k; | 196 | k = fentry->k; |
197 | load_b: | 197 | load_b: |
@@ -200,7 +200,7 @@ load_b: | |||
200 | A = *(u8 *)ptr; | 200 | A = *(u8 *)ptr; |
201 | continue; | 201 | continue; |
202 | } | 202 | } |
203 | return 0; | 203 | break; |
204 | case BPF_LD|BPF_W|BPF_LEN: | 204 | case BPF_LD|BPF_W|BPF_LEN: |
205 | A = skb->len; | 205 | A = skb->len; |
206 | continue; | 206 | continue; |
diff --git a/net/core/sock.c b/net/core/sock.c index ccd10fd65682..ac63b56e23b2 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -341,11 +341,11 @@ set_rcvbuf: | |||
341 | sock_reset_flag(sk, SOCK_LINGER); | 341 | sock_reset_flag(sk, SOCK_LINGER); |
342 | else { | 342 | else { |
343 | #if (BITS_PER_LONG == 32) | 343 | #if (BITS_PER_LONG == 32) |
344 | if (ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ) | 344 | if ((unsigned int)ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ) |
345 | sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT; | 345 | sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT; |
346 | else | 346 | else |
347 | #endif | 347 | #endif |
348 | sk->sk_lingertime = ling.l_linger * HZ; | 348 | sk->sk_lingertime = (unsigned int)ling.l_linger * HZ; |
349 | sock_set_flag(sk, SOCK_LINGER); | 349 | sock_set_flag(sk, SOCK_LINGER); |
350 | } | 350 | } |
351 | break; | 351 | break; |
@@ -1529,6 +1529,8 @@ EXPORT_SYMBOL(proto_register); | |||
1529 | void proto_unregister(struct proto *prot) | 1529 | void proto_unregister(struct proto *prot) |
1530 | { | 1530 | { |
1531 | write_lock(&proto_list_lock); | 1531 | write_lock(&proto_list_lock); |
1532 | list_del(&prot->node); | ||
1533 | write_unlock(&proto_list_lock); | ||
1532 | 1534 | ||
1533 | if (prot->slab != NULL) { | 1535 | if (prot->slab != NULL) { |
1534 | kmem_cache_destroy(prot->slab); | 1536 | kmem_cache_destroy(prot->slab); |
@@ -1550,9 +1552,6 @@ void proto_unregister(struct proto *prot) | |||
1550 | kfree(name); | 1552 | kfree(name); |
1551 | prot->twsk_slab = NULL; | 1553 | prot->twsk_slab = NULL; |
1552 | } | 1554 | } |
1553 | |||
1554 | list_del(&prot->node); | ||
1555 | write_unlock(&proto_list_lock); | ||
1556 | } | 1555 | } |
1557 | 1556 | ||
1558 | EXPORT_SYMBOL(proto_unregister); | 1557 | EXPORT_SYMBOL(proto_unregister); |
@@ -1719,8 +1718,8 @@ EXPORT_SYMBOL(sock_wfree); | |||
1719 | EXPORT_SYMBOL(sock_wmalloc); | 1718 | EXPORT_SYMBOL(sock_wmalloc); |
1720 | EXPORT_SYMBOL(sock_i_uid); | 1719 | EXPORT_SYMBOL(sock_i_uid); |
1721 | EXPORT_SYMBOL(sock_i_ino); | 1720 | EXPORT_SYMBOL(sock_i_ino); |
1722 | #ifdef CONFIG_SYSCTL | ||
1723 | EXPORT_SYMBOL(sysctl_optmem_max); | 1721 | EXPORT_SYMBOL(sysctl_optmem_max); |
1722 | #ifdef CONFIG_SYSCTL | ||
1724 | EXPORT_SYMBOL(sysctl_rmem_max); | 1723 | EXPORT_SYMBOL(sysctl_rmem_max); |
1725 | EXPORT_SYMBOL(sysctl_wmem_max); | 1724 | EXPORT_SYMBOL(sysctl_wmem_max); |
1726 | #endif | 1725 | #endif |
diff --git a/net/core/wireless.c b/net/core/wireless.c index 5caae2399f3a..d17f1583ea3e 100644 --- a/net/core/wireless.c +++ b/net/core/wireless.c | |||
@@ -58,6 +58,13 @@ | |||
58 | * o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus | 58 | * o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus |
59 | * Based on patch from Pavel Roskin <proski@gnu.org> : | 59 | * Based on patch from Pavel Roskin <proski@gnu.org> : |
60 | * o Fix kernel data leak to user space in private handler handling | 60 | * o Fix kernel data leak to user space in private handler handling |
61 | * | ||
62 | * v7 - 18.3.05 - Jean II | ||
63 | * o Remove (struct iw_point *)->pointer from events and streams | ||
64 | * o Remove spy_offset from struct iw_handler_def | ||
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 | ||
67 | * o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats) | ||
61 | */ | 68 | */ |
62 | 69 | ||
63 | /***************************** INCLUDES *****************************/ | 70 | /***************************** INCLUDES *****************************/ |
@@ -446,10 +453,14 @@ static inline struct iw_statistics *get_wireless_stats(struct net_device *dev) | |||
446 | (dev->wireless_handlers->get_wireless_stats != NULL)) | 453 | (dev->wireless_handlers->get_wireless_stats != NULL)) |
447 | return dev->wireless_handlers->get_wireless_stats(dev); | 454 | return dev->wireless_handlers->get_wireless_stats(dev); |
448 | 455 | ||
449 | /* Old location, will be phased out in next WE */ | 456 | /* Old location, field to be removed in next WE */ |
450 | return (dev->get_wireless_stats ? | 457 | if(dev->get_wireless_stats) { |
451 | dev->get_wireless_stats(dev) : | 458 | printk(KERN_DEBUG "%s (WE) : Driver using old /proc/net/wireless support, please fix driver !\n", |
452 | (struct iw_statistics *) NULL); | 459 | dev->name); |
460 | return dev->get_wireless_stats(dev); | ||
461 | } | ||
462 | /* Not found */ | ||
463 | return (struct iw_statistics *) NULL; | ||
453 | } | 464 | } |
454 | 465 | ||
455 | /* ---------------------------------------------------------------- */ | 466 | /* ---------------------------------------------------------------- */ |
@@ -541,16 +552,18 @@ static __inline__ void wireless_seq_printf_stats(struct seq_file *seq, | |||
541 | dev->name, stats->status, stats->qual.qual, | 552 | dev->name, stats->status, stats->qual.qual, |
542 | stats->qual.updated & IW_QUAL_QUAL_UPDATED | 553 | stats->qual.updated & IW_QUAL_QUAL_UPDATED |
543 | ? '.' : ' ', | 554 | ? '.' : ' ', |
544 | ((__u8) stats->qual.level), | 555 | ((__s32) stats->qual.level) - |
556 | ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), | ||
545 | stats->qual.updated & IW_QUAL_LEVEL_UPDATED | 557 | stats->qual.updated & IW_QUAL_LEVEL_UPDATED |
546 | ? '.' : ' ', | 558 | ? '.' : ' ', |
547 | ((__u8) stats->qual.noise), | 559 | ((__s32) stats->qual.noise) - |
560 | ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), | ||
548 | stats->qual.updated & IW_QUAL_NOISE_UPDATED | 561 | stats->qual.updated & IW_QUAL_NOISE_UPDATED |
549 | ? '.' : ' ', | 562 | ? '.' : ' ', |
550 | stats->discard.nwid, stats->discard.code, | 563 | stats->discard.nwid, stats->discard.code, |
551 | stats->discard.fragment, stats->discard.retries, | 564 | stats->discard.fragment, stats->discard.retries, |
552 | stats->discard.misc, stats->miss.beacon); | 565 | stats->discard.misc, stats->miss.beacon); |
553 | stats->qual.updated = 0; | 566 | stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; |
554 | } | 567 | } |
555 | } | 568 | } |
556 | 569 | ||
@@ -593,6 +606,7 @@ static struct file_operations wireless_seq_fops = { | |||
593 | 606 | ||
594 | int __init wireless_proc_init(void) | 607 | int __init wireless_proc_init(void) |
595 | { | 608 | { |
609 | /* Create /proc/net/wireless entry */ | ||
596 | if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops)) | 610 | if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops)) |
597 | return -ENOMEM; | 611 | return -ENOMEM; |
598 | 612 | ||
@@ -627,9 +641,9 @@ static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr) | |||
627 | sizeof(struct iw_statistics))) | 641 | sizeof(struct iw_statistics))) |
628 | return -EFAULT; | 642 | return -EFAULT; |
629 | 643 | ||
630 | /* Check if we need to clear the update flag */ | 644 | /* Check if we need to clear the updated flag */ |
631 | if(wrq->u.data.flags != 0) | 645 | if(wrq->u.data.flags != 0) |
632 | stats->qual.updated = 0; | 646 | stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; |
633 | return 0; | 647 | return 0; |
634 | } else | 648 | } else |
635 | return -EOPNOTSUPP; | 649 | return -EOPNOTSUPP; |
@@ -1161,10 +1175,11 @@ void wireless_send_event(struct net_device * dev, | |||
1161 | struct iw_event *event; /* Mallocated whole event */ | 1175 | struct iw_event *event; /* Mallocated whole event */ |
1162 | int event_len; /* Its size */ | 1176 | int event_len; /* Its size */ |
1163 | int hdr_len; /* Size of the event header */ | 1177 | int hdr_len; /* Size of the event header */ |
1178 | int wrqu_off = 0; /* Offset in wrqu */ | ||
1164 | /* Don't "optimise" the following variable, it will crash */ | 1179 | /* Don't "optimise" the following variable, it will crash */ |
1165 | unsigned cmd_index; /* *MUST* be unsigned */ | 1180 | unsigned cmd_index; /* *MUST* be unsigned */ |
1166 | 1181 | ||
1167 | /* Get the description of the IOCTL */ | 1182 | /* Get the description of the Event */ |
1168 | if(cmd <= SIOCIWLAST) { | 1183 | if(cmd <= SIOCIWLAST) { |
1169 | cmd_index = cmd - SIOCIWFIRST; | 1184 | cmd_index = cmd - SIOCIWFIRST; |
1170 | if(cmd_index < standard_ioctl_num) | 1185 | if(cmd_index < standard_ioctl_num) |
@@ -1207,6 +1222,8 @@ void wireless_send_event(struct net_device * dev, | |||
1207 | /* Calculate extra_len - extra is NULL for restricted events */ | 1222 | /* Calculate extra_len - extra is NULL for restricted events */ |
1208 | if(extra != NULL) | 1223 | if(extra != NULL) |
1209 | extra_len = wrqu->data.length * descr->token_size; | 1224 | extra_len = wrqu->data.length * descr->token_size; |
1225 | /* Always at an offset in wrqu */ | ||
1226 | wrqu_off = IW_EV_POINT_OFF; | ||
1210 | #ifdef WE_EVENT_DEBUG | 1227 | #ifdef WE_EVENT_DEBUG |
1211 | printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len); | 1228 | printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len); |
1212 | #endif /* WE_EVENT_DEBUG */ | 1229 | #endif /* WE_EVENT_DEBUG */ |
@@ -1217,7 +1234,7 @@ void wireless_send_event(struct net_device * dev, | |||
1217 | event_len = hdr_len + extra_len; | 1234 | event_len = hdr_len + extra_len; |
1218 | 1235 | ||
1219 | #ifdef WE_EVENT_DEBUG | 1236 | #ifdef WE_EVENT_DEBUG |
1220 | printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len); | 1237 | printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, wrqu_off %d, event_len %d\n", dev->name, cmd, hdr_len, wrqu_off, event_len); |
1221 | #endif /* WE_EVENT_DEBUG */ | 1238 | #endif /* WE_EVENT_DEBUG */ |
1222 | 1239 | ||
1223 | /* Create temporary buffer to hold the event */ | 1240 | /* Create temporary buffer to hold the event */ |
@@ -1228,7 +1245,7 @@ void wireless_send_event(struct net_device * dev, | |||
1228 | /* Fill event */ | 1245 | /* Fill event */ |
1229 | event->len = event_len; | 1246 | event->len = event_len; |
1230 | event->cmd = cmd; | 1247 | event->cmd = cmd; |
1231 | memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN); | 1248 | memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN); |
1232 | if(extra != NULL) | 1249 | if(extra != NULL) |
1233 | memcpy(((char *) event) + hdr_len, extra, extra_len); | 1250 | memcpy(((char *) event) + hdr_len, extra, extra_len); |
1234 | 1251 | ||
@@ -1249,7 +1266,7 @@ void wireless_send_event(struct net_device * dev, | |||
1249 | * Now, the driver can delegate this task to Wireless Extensions. | 1266 | * Now, the driver can delegate this task to Wireless Extensions. |
1250 | * It needs to use those standard spy iw_handler in struct iw_handler_def, | 1267 | * It needs to use those standard spy iw_handler in struct iw_handler_def, |
1251 | * push data to us via wireless_spy_update() and include struct iw_spy_data | 1268 | * push data to us via wireless_spy_update() and include struct iw_spy_data |
1252 | * in its private part (and advertise it in iw_handler_def->spy_offset). | 1269 | * in its private part (and export it in net_device->wireless_data->spy_data). |
1253 | * One of the main advantage of centralising spy support here is that | 1270 | * One of the main advantage of centralising spy support here is that |
1254 | * it becomes much easier to improve and extend it without having to touch | 1271 | * it becomes much easier to improve and extend it without having to touch |
1255 | * the drivers. One example is the addition of the Spy-Threshold events. | 1272 | * the drivers. One example is the addition of the Spy-Threshold events. |
@@ -1266,10 +1283,7 @@ static inline struct iw_spy_data * get_spydata(struct net_device *dev) | |||
1266 | /* This is the new way */ | 1283 | /* This is the new way */ |
1267 | if(dev->wireless_data) | 1284 | if(dev->wireless_data) |
1268 | return(dev->wireless_data->spy_data); | 1285 | return(dev->wireless_data->spy_data); |
1269 | 1286 | return NULL; | |
1270 | /* This is the old way. Doesn't work for multi-headed drivers. | ||
1271 | * It will be removed in the next version of WE. */ | ||
1272 | return (dev->priv + dev->wireless_handlers->spy_offset); | ||
1273 | } | 1287 | } |
1274 | 1288 | ||
1275 | /*------------------------------------------------------------------*/ | 1289 | /*------------------------------------------------------------------*/ |
@@ -1284,10 +1298,6 @@ int iw_handler_set_spy(struct net_device * dev, | |||
1284 | struct iw_spy_data * spydata = get_spydata(dev); | 1298 | struct iw_spy_data * spydata = get_spydata(dev); |
1285 | struct sockaddr * address = (struct sockaddr *) extra; | 1299 | struct sockaddr * address = (struct sockaddr *) extra; |
1286 | 1300 | ||
1287 | if(!dev->wireless_data) | ||
1288 | /* Help user know that driver needs updating */ | ||
1289 | printk(KERN_DEBUG "%s (WE) : Driver using old/buggy spy support, please fix driver !\n", | ||
1290 | dev->name); | ||
1291 | /* Make sure driver is not buggy or using the old API */ | 1301 | /* Make sure driver is not buggy or using the old API */ |
1292 | if(!spydata) | 1302 | if(!spydata) |
1293 | return -EOPNOTSUPP; | 1303 | return -EOPNOTSUPP; |
@@ -1318,7 +1328,7 @@ int iw_handler_set_spy(struct net_device * dev, | |||
1318 | sizeof(struct iw_quality) * IW_MAX_SPY); | 1328 | sizeof(struct iw_quality) * IW_MAX_SPY); |
1319 | 1329 | ||
1320 | #ifdef WE_SPY_DEBUG | 1330 | #ifdef WE_SPY_DEBUG |
1321 | printk(KERN_DEBUG "iw_handler_set_spy() : offset %ld, spydata %p, num %d\n", dev->wireless_handlers->spy_offset, spydata, wrqu->data.length); | 1331 | printk(KERN_DEBUG "iw_handler_set_spy() : wireless_data %p, spydata %p, num %d\n", dev->wireless_data, spydata, wrqu->data.length); |
1322 | for (i = 0; i < wrqu->data.length; i++) | 1332 | for (i = 0; i < wrqu->data.length; i++) |
1323 | printk(KERN_DEBUG | 1333 | printk(KERN_DEBUG |
1324 | "%02X:%02X:%02X:%02X:%02X:%02X \n", | 1334 | "%02X:%02X:%02X:%02X:%02X:%02X \n", |
@@ -1371,7 +1381,7 @@ int iw_handler_get_spy(struct net_device * dev, | |||
1371 | sizeof(struct iw_quality) * spydata->spy_number); | 1381 | sizeof(struct iw_quality) * spydata->spy_number); |
1372 | /* Reset updated flags. */ | 1382 | /* Reset updated flags. */ |
1373 | for(i = 0; i < spydata->spy_number; i++) | 1383 | for(i = 0; i < spydata->spy_number; i++) |
1374 | spydata->spy_stat[i].updated = 0; | 1384 | spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED; |
1375 | return 0; | 1385 | return 0; |
1376 | } | 1386 | } |
1377 | 1387 | ||
@@ -1486,7 +1496,7 @@ void wireless_spy_update(struct net_device * dev, | |||
1486 | return; | 1496 | return; |
1487 | 1497 | ||
1488 | #ifdef WE_SPY_DEBUG | 1498 | #ifdef WE_SPY_DEBUG |
1489 | printk(KERN_DEBUG "wireless_spy_update() : offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]); | 1499 | printk(KERN_DEBUG "wireless_spy_update() : wireless_data %p, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_data, spydata, address[0], address[1], address[2], address[3], address[4], address[5]); |
1490 | #endif /* WE_SPY_DEBUG */ | 1500 | #endif /* WE_SPY_DEBUG */ |
1491 | 1501 | ||
1492 | /* Update all records that match */ | 1502 | /* Update all records that match */ |
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 621680f127af..348f36b529f7 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c | |||
@@ -1876,8 +1876,27 @@ static inline unsigned int dn_current_mss(struct sock *sk, int flags) | |||
1876 | return mss_now; | 1876 | return mss_now; |
1877 | } | 1877 | } |
1878 | 1878 | ||
1879 | /* | ||
1880 | * N.B. We get the timeout wrong here, but then we always did get it | ||
1881 | * wrong before and this is another step along the road to correcting | ||
1882 | * it. It ought to get updated each time we pass through the routine, | ||
1883 | * but in practise it probably doesn't matter too much for now. | ||
1884 | */ | ||
1885 | static inline struct sk_buff *dn_alloc_send_pskb(struct sock *sk, | ||
1886 | unsigned long datalen, int noblock, | ||
1887 | int *errcode) | ||
1888 | { | ||
1889 | struct sk_buff *skb = sock_alloc_send_skb(sk, datalen, | ||
1890 | noblock, errcode); | ||
1891 | if (skb) { | ||
1892 | skb->protocol = __constant_htons(ETH_P_DNA_RT); | ||
1893 | skb->pkt_type = PACKET_OUTGOING; | ||
1894 | } | ||
1895 | return skb; | ||
1896 | } | ||
1897 | |||
1879 | static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, | 1898 | static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, |
1880 | struct msghdr *msg, size_t size) | 1899 | struct msghdr *msg, size_t size) |
1881 | { | 1900 | { |
1882 | struct sock *sk = sock->sk; | 1901 | struct sock *sk = sock->sk; |
1883 | struct dn_scp *scp = DN_SK(sk); | 1902 | struct dn_scp *scp = DN_SK(sk); |
@@ -1892,7 +1911,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
1892 | struct dn_skb_cb *cb; | 1911 | struct dn_skb_cb *cb; |
1893 | size_t len; | 1912 | size_t len; |
1894 | unsigned char fctype; | 1913 | unsigned char fctype; |
1895 | long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); | 1914 | long timeo; |
1896 | 1915 | ||
1897 | if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE|MSG_CMSG_COMPAT)) | 1916 | if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE|MSG_CMSG_COMPAT)) |
1898 | return -EOPNOTSUPP; | 1917 | return -EOPNOTSUPP; |
@@ -1900,18 +1919,21 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
1900 | if (addr_len && (addr_len != sizeof(struct sockaddr_dn))) | 1919 | if (addr_len && (addr_len != sizeof(struct sockaddr_dn))) |
1901 | return -EINVAL; | 1920 | return -EINVAL; |
1902 | 1921 | ||
1922 | lock_sock(sk); | ||
1923 | timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); | ||
1903 | /* | 1924 | /* |
1904 | * The only difference between stream sockets and sequenced packet | 1925 | * The only difference between stream sockets and sequenced packet |
1905 | * sockets is that the stream sockets always behave as if MSG_EOR | 1926 | * sockets is that the stream sockets always behave as if MSG_EOR |
1906 | * has been set. | 1927 | * has been set. |
1907 | */ | 1928 | */ |
1908 | if (sock->type == SOCK_STREAM) { | 1929 | if (sock->type == SOCK_STREAM) { |
1909 | if (flags & MSG_EOR) | 1930 | if (flags & MSG_EOR) { |
1910 | return -EINVAL; | 1931 | err = -EINVAL; |
1932 | goto out; | ||
1933 | } | ||
1911 | flags |= MSG_EOR; | 1934 | flags |= MSG_EOR; |
1912 | } | 1935 | } |
1913 | 1936 | ||
1914 | lock_sock(sk); | ||
1915 | 1937 | ||
1916 | err = dn_check_state(sk, addr, addr_len, &timeo, flags); | 1938 | err = dn_check_state(sk, addr, addr_len, &timeo, flags); |
1917 | if (err) | 1939 | if (err) |
@@ -1980,8 +2002,12 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
1980 | 2002 | ||
1981 | /* | 2003 | /* |
1982 | * Get a suitably sized skb. | 2004 | * Get a suitably sized skb. |
2005 | * 64 is a bit of a hack really, but its larger than any | ||
2006 | * link-layer headers and has served us well as a good | ||
2007 | * guess as to their real length. | ||
1983 | */ | 2008 | */ |
1984 | skb = dn_alloc_send_skb(sk, &len, flags & MSG_DONTWAIT, timeo, &err); | 2009 | skb = dn_alloc_send_pskb(sk, len + 64 + DN_MAX_NSP_DATA_HEADER, |
2010 | flags & MSG_DONTWAIT, &err); | ||
1985 | 2011 | ||
1986 | if (err) | 2012 | if (err) |
1987 | break; | 2013 | break; |
@@ -1991,7 +2017,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
1991 | 2017 | ||
1992 | cb = DN_SKB_CB(skb); | 2018 | cb = DN_SKB_CB(skb); |
1993 | 2019 | ||
1994 | skb_reserve(skb, DN_MAX_NSP_DATA_HEADER); | 2020 | skb_reserve(skb, 64 + DN_MAX_NSP_DATA_HEADER); |
1995 | 2021 | ||
1996 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { | 2022 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { |
1997 | err = -EFAULT; | 2023 | err = -EFAULT; |
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c index e0bebf4bbcad..53633d352868 100644 --- a/net/decnet/dn_nsp_out.c +++ b/net/decnet/dn_nsp_out.c | |||
@@ -137,69 +137,6 @@ struct sk_buff *dn_alloc_skb(struct sock *sk, int size, int pri) | |||
137 | } | 137 | } |
138 | 138 | ||
139 | /* | 139 | /* |
140 | * Wrapper for the above, for allocs of data skbs. We try and get the | ||
141 | * whole size thats been asked for (plus 11 bytes of header). If this | ||
142 | * fails, then we try for any size over 16 bytes for SOCK_STREAMS. | ||
143 | */ | ||
144 | struct sk_buff *dn_alloc_send_skb(struct sock *sk, size_t *size, int noblock, long timeo, int *err) | ||
145 | { | ||
146 | int space; | ||
147 | int len; | ||
148 | struct sk_buff *skb = NULL; | ||
149 | |||
150 | *err = 0; | ||
151 | |||
152 | while(skb == NULL) { | ||
153 | if (signal_pending(current)) { | ||
154 | *err = sock_intr_errno(timeo); | ||
155 | break; | ||
156 | } | ||
157 | |||
158 | if (sk->sk_shutdown & SEND_SHUTDOWN) { | ||
159 | *err = EINVAL; | ||
160 | break; | ||
161 | } | ||
162 | |||
163 | if (sk->sk_err) | ||
164 | break; | ||
165 | |||
166 | len = *size + 11; | ||
167 | space = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); | ||
168 | |||
169 | if (space < len) { | ||
170 | if ((sk->sk_socket->type == SOCK_STREAM) && | ||
171 | (space >= (16 + 11))) | ||
172 | len = space; | ||
173 | } | ||
174 | |||
175 | if (space < len) { | ||
176 | set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); | ||
177 | if (noblock) { | ||
178 | *err = EWOULDBLOCK; | ||
179 | break; | ||
180 | } | ||
181 | |||
182 | clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); | ||
183 | SOCK_SLEEP_PRE(sk) | ||
184 | |||
185 | if ((sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc)) < | ||
186 | len) | ||
187 | schedule(); | ||
188 | |||
189 | SOCK_SLEEP_POST(sk) | ||
190 | continue; | ||
191 | } | ||
192 | |||
193 | if ((skb = dn_alloc_skb(sk, len, sk->sk_allocation)) == NULL) | ||
194 | continue; | ||
195 | |||
196 | *size = len - 11; | ||
197 | } | ||
198 | |||
199 | return skb; | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * Calculate persist timer based upon the smoothed round | 140 | * Calculate persist timer based upon the smoothed round |
204 | * trip time and the variance. Backoff according to the | 141 | * trip time and the variance. Backoff according to the |
205 | * nsp_backoff[] array. | 142 | * nsp_backoff[] array. |
diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig new file mode 100644 index 000000000000..58ed4319e693 --- /dev/null +++ b/net/ieee80211/Kconfig | |||
@@ -0,0 +1,69 @@ | |||
1 | config IEEE80211 | ||
2 | tristate "Generic IEEE 802.11 Networking Stack" | ||
3 | select NET_RADIO | ||
4 | ---help--- | ||
5 | This option enables the hardware independent IEEE 802.11 | ||
6 | networking stack. | ||
7 | |||
8 | config IEEE80211_DEBUG | ||
9 | bool "Enable full debugging output" | ||
10 | depends on IEEE80211 | ||
11 | ---help--- | ||
12 | This option will enable debug tracing output for the | ||
13 | ieee80211 network stack. | ||
14 | |||
15 | This will result in the kernel module being ~70k larger. You | ||
16 | can control which debug output is sent to the kernel log by | ||
17 | setting the value in | ||
18 | |||
19 | /proc/net/ieee80211/debug_level | ||
20 | |||
21 | For example: | ||
22 | |||
23 | % echo 0x00000FFO > /proc/net/ieee80211/debug_level | ||
24 | |||
25 | For a list of values you can assign to debug_level, you | ||
26 | can look at the bit mask values in <net/ieee80211.h> | ||
27 | |||
28 | If you are not trying to debug or develop the ieee80211 | ||
29 | subsystem, you most likely want to say N here. | ||
30 | |||
31 | config IEEE80211_CRYPT_WEP | ||
32 | tristate "IEEE 802.11 WEP encryption (802.1x)" | ||
33 | depends on IEEE80211 | ||
34 | select CRYPTO | ||
35 | select CRYPTO_ARC4 | ||
36 | select CRC32 | ||
37 | ---help--- | ||
38 | Include software based cipher suites in support of IEEE | ||
39 | 802.11's WEP. This is needed for WEP as well as 802.1x. | ||
40 | |||
41 | This can be compiled as a modules and it will be called | ||
42 | "ieee80211_crypt_wep". | ||
43 | |||
44 | config IEEE80211_CRYPT_CCMP | ||
45 | tristate "IEEE 802.11i CCMP support" | ||
46 | depends on IEEE80211 | ||
47 | select CRYPTO | ||
48 | select CRYPTO_AES | ||
49 | ---help--- | ||
50 | Include software based cipher suites in support of IEEE 802.11i | ||
51 | (aka TGi, WPA, WPA2, WPA-PSK, etc.) for use with CCMP enabled | ||
52 | networks. | ||
53 | |||
54 | This can be compiled as a modules and it will be called | ||
55 | "ieee80211_crypt_ccmp". | ||
56 | |||
57 | config IEEE80211_CRYPT_TKIP | ||
58 | tristate "IEEE 802.11i TKIP encryption" | ||
59 | depends on IEEE80211 | ||
60 | select CRYPTO | ||
61 | select CRYPTO_MICHAEL_MIC | ||
62 | ---help--- | ||
63 | Include software based cipher suites in support of IEEE 802.11i | ||
64 | (aka TGi, WPA, WPA2, WPA-PSK, etc.) for use with TKIP enabled | ||
65 | networks. | ||
66 | |||
67 | This can be compiled as a modules and it will be called | ||
68 | "ieee80211_crypt_tkip". | ||
69 | |||
diff --git a/net/ieee80211/Makefile b/net/ieee80211/Makefile new file mode 100644 index 000000000000..a6ccac5baea8 --- /dev/null +++ b/net/ieee80211/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | obj-$(CONFIG_IEEE80211) += ieee80211.o | ||
2 | obj-$(CONFIG_IEEE80211) += ieee80211_crypt.o | ||
3 | obj-$(CONFIG_IEEE80211_CRYPT_WEP) += ieee80211_crypt_wep.o | ||
4 | obj-$(CONFIG_IEEE80211_CRYPT_CCMP) += ieee80211_crypt_ccmp.o | ||
5 | obj-$(CONFIG_IEEE80211_CRYPT_TKIP) += ieee80211_crypt_tkip.o | ||
6 | ieee80211-objs := \ | ||
7 | ieee80211_module.o \ | ||
8 | ieee80211_tx.o \ | ||
9 | ieee80211_rx.o \ | ||
10 | ieee80211_wx.o | ||
11 | |||
diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c new file mode 100644 index 000000000000..61a9d92e455b --- /dev/null +++ b/net/ieee80211/ieee80211_crypt.c | |||
@@ -0,0 +1,258 @@ | |||
1 | /* | ||
2 | * Host AP crypto routines | ||
3 | * | ||
4 | * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> | ||
5 | * Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. See README and COPYING for | ||
10 | * more details. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/version.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <asm/string.h> | ||
20 | #include <asm/errno.h> | ||
21 | |||
22 | #include <net/ieee80211.h> | ||
23 | |||
24 | MODULE_AUTHOR("Jouni Malinen"); | ||
25 | MODULE_DESCRIPTION("HostAP crypto"); | ||
26 | MODULE_LICENSE("GPL"); | ||
27 | |||
28 | struct ieee80211_crypto_alg { | ||
29 | struct list_head list; | ||
30 | struct ieee80211_crypto_ops *ops; | ||
31 | }; | ||
32 | |||
33 | struct ieee80211_crypto { | ||
34 | struct list_head algs; | ||
35 | spinlock_t lock; | ||
36 | }; | ||
37 | |||
38 | static struct ieee80211_crypto *hcrypt; | ||
39 | |||
40 | void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force) | ||
41 | { | ||
42 | struct list_head *ptr, *n; | ||
43 | struct ieee80211_crypt_data *entry; | ||
44 | |||
45 | for (ptr = ieee->crypt_deinit_list.next, n = ptr->next; | ||
46 | ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) { | ||
47 | entry = list_entry(ptr, struct ieee80211_crypt_data, list); | ||
48 | |||
49 | if (atomic_read(&entry->refcnt) != 0 && !force) | ||
50 | continue; | ||
51 | |||
52 | list_del(ptr); | ||
53 | |||
54 | if (entry->ops) { | ||
55 | entry->ops->deinit(entry->priv); | ||
56 | module_put(entry->ops->owner); | ||
57 | } | ||
58 | kfree(entry); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | void ieee80211_crypt_deinit_handler(unsigned long data) | ||
63 | { | ||
64 | struct ieee80211_device *ieee = (struct ieee80211_device *)data; | ||
65 | unsigned long flags; | ||
66 | |||
67 | spin_lock_irqsave(&ieee->lock, flags); | ||
68 | ieee80211_crypt_deinit_entries(ieee, 0); | ||
69 | if (!list_empty(&ieee->crypt_deinit_list)) { | ||
70 | printk(KERN_DEBUG "%s: entries remaining in delayed crypt " | ||
71 | "deletion list\n", ieee->dev->name); | ||
72 | ieee->crypt_deinit_timer.expires = jiffies + HZ; | ||
73 | add_timer(&ieee->crypt_deinit_timer); | ||
74 | } | ||
75 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
76 | |||
77 | } | ||
78 | |||
79 | void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, | ||
80 | struct ieee80211_crypt_data **crypt) | ||
81 | { | ||
82 | struct ieee80211_crypt_data *tmp; | ||
83 | unsigned long flags; | ||
84 | |||
85 | if (*crypt == NULL) | ||
86 | return; | ||
87 | |||
88 | tmp = *crypt; | ||
89 | *crypt = NULL; | ||
90 | |||
91 | /* must not run ops->deinit() while there may be pending encrypt or | ||
92 | * decrypt operations. Use a list of delayed deinits to avoid needing | ||
93 | * locking. */ | ||
94 | |||
95 | spin_lock_irqsave(&ieee->lock, flags); | ||
96 | list_add(&tmp->list, &ieee->crypt_deinit_list); | ||
97 | if (!timer_pending(&ieee->crypt_deinit_timer)) { | ||
98 | ieee->crypt_deinit_timer.expires = jiffies + HZ; | ||
99 | add_timer(&ieee->crypt_deinit_timer); | ||
100 | } | ||
101 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
102 | } | ||
103 | |||
104 | int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops) | ||
105 | { | ||
106 | unsigned long flags; | ||
107 | struct ieee80211_crypto_alg *alg; | ||
108 | |||
109 | if (hcrypt == NULL) | ||
110 | return -1; | ||
111 | |||
112 | alg = kmalloc(sizeof(*alg), GFP_KERNEL); | ||
113 | if (alg == NULL) | ||
114 | return -ENOMEM; | ||
115 | |||
116 | memset(alg, 0, sizeof(*alg)); | ||
117 | alg->ops = ops; | ||
118 | |||
119 | spin_lock_irqsave(&hcrypt->lock, flags); | ||
120 | list_add(&alg->list, &hcrypt->algs); | ||
121 | spin_unlock_irqrestore(&hcrypt->lock, flags); | ||
122 | |||
123 | printk(KERN_DEBUG "ieee80211_crypt: registered algorithm '%s'\n", | ||
124 | ops->name); | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops) | ||
130 | { | ||
131 | unsigned long flags; | ||
132 | struct list_head *ptr; | ||
133 | struct ieee80211_crypto_alg *del_alg = NULL; | ||
134 | |||
135 | if (hcrypt == NULL) | ||
136 | return -1; | ||
137 | |||
138 | spin_lock_irqsave(&hcrypt->lock, flags); | ||
139 | for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { | ||
140 | struct ieee80211_crypto_alg *alg = | ||
141 | (struct ieee80211_crypto_alg *)ptr; | ||
142 | if (alg->ops == ops) { | ||
143 | list_del(&alg->list); | ||
144 | del_alg = alg; | ||
145 | break; | ||
146 | } | ||
147 | } | ||
148 | spin_unlock_irqrestore(&hcrypt->lock, flags); | ||
149 | |||
150 | if (del_alg) { | ||
151 | printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm " | ||
152 | "'%s'\n", ops->name); | ||
153 | kfree(del_alg); | ||
154 | } | ||
155 | |||
156 | return del_alg ? 0 : -1; | ||
157 | } | ||
158 | |||
159 | struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name) | ||
160 | { | ||
161 | unsigned long flags; | ||
162 | struct list_head *ptr; | ||
163 | struct ieee80211_crypto_alg *found_alg = NULL; | ||
164 | |||
165 | if (hcrypt == NULL) | ||
166 | return NULL; | ||
167 | |||
168 | spin_lock_irqsave(&hcrypt->lock, flags); | ||
169 | for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { | ||
170 | struct ieee80211_crypto_alg *alg = | ||
171 | (struct ieee80211_crypto_alg *)ptr; | ||
172 | if (strcmp(alg->ops->name, name) == 0) { | ||
173 | found_alg = alg; | ||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | spin_unlock_irqrestore(&hcrypt->lock, flags); | ||
178 | |||
179 | if (found_alg) | ||
180 | return found_alg->ops; | ||
181 | else | ||
182 | return NULL; | ||
183 | } | ||
184 | |||
185 | static void *ieee80211_crypt_null_init(int keyidx) | ||
186 | { | ||
187 | return (void *)1; | ||
188 | } | ||
189 | static void ieee80211_crypt_null_deinit(void *priv) | ||
190 | { | ||
191 | } | ||
192 | |||
193 | static struct ieee80211_crypto_ops ieee80211_crypt_null = { | ||
194 | .name = "NULL", | ||
195 | .init = ieee80211_crypt_null_init, | ||
196 | .deinit = ieee80211_crypt_null_deinit, | ||
197 | .encrypt_mpdu = NULL, | ||
198 | .decrypt_mpdu = NULL, | ||
199 | .encrypt_msdu = NULL, | ||
200 | .decrypt_msdu = NULL, | ||
201 | .set_key = NULL, | ||
202 | .get_key = NULL, | ||
203 | .extra_prefix_len = 0, | ||
204 | .extra_postfix_len = 0, | ||
205 | .owner = THIS_MODULE, | ||
206 | }; | ||
207 | |||
208 | static int __init ieee80211_crypto_init(void) | ||
209 | { | ||
210 | int ret = -ENOMEM; | ||
211 | |||
212 | hcrypt = kmalloc(sizeof(*hcrypt), GFP_KERNEL); | ||
213 | if (!hcrypt) | ||
214 | goto out; | ||
215 | |||
216 | memset(hcrypt, 0, sizeof(*hcrypt)); | ||
217 | INIT_LIST_HEAD(&hcrypt->algs); | ||
218 | spin_lock_init(&hcrypt->lock); | ||
219 | |||
220 | ret = ieee80211_register_crypto_ops(&ieee80211_crypt_null); | ||
221 | if (ret < 0) { | ||
222 | kfree(hcrypt); | ||
223 | hcrypt = NULL; | ||
224 | } | ||
225 | out: | ||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | static void __exit ieee80211_crypto_deinit(void) | ||
230 | { | ||
231 | struct list_head *ptr, *n; | ||
232 | |||
233 | if (hcrypt == NULL) | ||
234 | return; | ||
235 | |||
236 | for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs; | ||
237 | ptr = n, n = ptr->next) { | ||
238 | struct ieee80211_crypto_alg *alg = | ||
239 | (struct ieee80211_crypto_alg *)ptr; | ||
240 | list_del(ptr); | ||
241 | printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm " | ||
242 | "'%s' (deinit)\n", alg->ops->name); | ||
243 | kfree(alg); | ||
244 | } | ||
245 | |||
246 | kfree(hcrypt); | ||
247 | } | ||
248 | |||
249 | EXPORT_SYMBOL(ieee80211_crypt_deinit_entries); | ||
250 | EXPORT_SYMBOL(ieee80211_crypt_deinit_handler); | ||
251 | EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit); | ||
252 | |||
253 | EXPORT_SYMBOL(ieee80211_register_crypto_ops); | ||
254 | EXPORT_SYMBOL(ieee80211_unregister_crypto_ops); | ||
255 | EXPORT_SYMBOL(ieee80211_get_crypto_ops); | ||
256 | |||
257 | module_init(ieee80211_crypto_init); | ||
258 | module_exit(ieee80211_crypto_deinit); | ||
diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c new file mode 100644 index 000000000000..8fc13f45971e --- /dev/null +++ b/net/ieee80211/ieee80211_crypt_ccmp.c | |||
@@ -0,0 +1,455 @@ | |||
1 | /* | ||
2 | * Host AP crypt: host-based CCMP encryption implementation for Host AP driver | ||
3 | * | ||
4 | * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi> | ||
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 version 2 as | ||
8 | * published by the Free Software Foundation. See README and COPYING for | ||
9 | * more details. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/version.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/random.h> | ||
18 | #include <linux/skbuff.h> | ||
19 | #include <linux/netdevice.h> | ||
20 | #include <linux/if_ether.h> | ||
21 | #include <linux/if_arp.h> | ||
22 | #include <asm/string.h> | ||
23 | #include <linux/wireless.h> | ||
24 | |||
25 | #include <net/ieee80211.h> | ||
26 | |||
27 | #include <linux/crypto.h> | ||
28 | #include <asm/scatterlist.h> | ||
29 | |||
30 | MODULE_AUTHOR("Jouni Malinen"); | ||
31 | MODULE_DESCRIPTION("Host AP crypt: CCMP"); | ||
32 | MODULE_LICENSE("GPL"); | ||
33 | |||
34 | #define AES_BLOCK_LEN 16 | ||
35 | #define CCMP_HDR_LEN 8 | ||
36 | #define CCMP_MIC_LEN 8 | ||
37 | #define CCMP_TK_LEN 16 | ||
38 | #define CCMP_PN_LEN 6 | ||
39 | |||
40 | struct ieee80211_ccmp_data { | ||
41 | u8 key[CCMP_TK_LEN]; | ||
42 | int key_set; | ||
43 | |||
44 | u8 tx_pn[CCMP_PN_LEN]; | ||
45 | u8 rx_pn[CCMP_PN_LEN]; | ||
46 | |||
47 | u32 dot11RSNAStatsCCMPFormatErrors; | ||
48 | u32 dot11RSNAStatsCCMPReplays; | ||
49 | u32 dot11RSNAStatsCCMPDecryptErrors; | ||
50 | |||
51 | int key_idx; | ||
52 | |||
53 | struct crypto_tfm *tfm; | ||
54 | |||
55 | /* scratch buffers for virt_to_page() (crypto API) */ | ||
56 | u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN], | ||
57 | tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN]; | ||
58 | u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN]; | ||
59 | }; | ||
60 | |||
61 | static void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm, | ||
62 | const u8 pt[16], u8 ct[16]) | ||
63 | { | ||
64 | struct scatterlist src, dst; | ||
65 | |||
66 | src.page = virt_to_page(pt); | ||
67 | src.offset = offset_in_page(pt); | ||
68 | src.length = AES_BLOCK_LEN; | ||
69 | |||
70 | dst.page = virt_to_page(ct); | ||
71 | dst.offset = offset_in_page(ct); | ||
72 | dst.length = AES_BLOCK_LEN; | ||
73 | |||
74 | crypto_cipher_encrypt(tfm, &dst, &src, AES_BLOCK_LEN); | ||
75 | } | ||
76 | |||
77 | static void *ieee80211_ccmp_init(int key_idx) | ||
78 | { | ||
79 | struct ieee80211_ccmp_data *priv; | ||
80 | |||
81 | priv = kmalloc(sizeof(*priv), GFP_ATOMIC); | ||
82 | if (priv == NULL) | ||
83 | goto fail; | ||
84 | memset(priv, 0, sizeof(*priv)); | ||
85 | priv->key_idx = key_idx; | ||
86 | |||
87 | priv->tfm = crypto_alloc_tfm("aes", 0); | ||
88 | if (priv->tfm == NULL) { | ||
89 | printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate " | ||
90 | "crypto API aes\n"); | ||
91 | goto fail; | ||
92 | } | ||
93 | |||
94 | return priv; | ||
95 | |||
96 | fail: | ||
97 | if (priv) { | ||
98 | if (priv->tfm) | ||
99 | crypto_free_tfm(priv->tfm); | ||
100 | kfree(priv); | ||
101 | } | ||
102 | |||
103 | return NULL; | ||
104 | } | ||
105 | |||
106 | static void ieee80211_ccmp_deinit(void *priv) | ||
107 | { | ||
108 | struct ieee80211_ccmp_data *_priv = priv; | ||
109 | if (_priv && _priv->tfm) | ||
110 | crypto_free_tfm(_priv->tfm); | ||
111 | kfree(priv); | ||
112 | } | ||
113 | |||
114 | static inline void xor_block(u8 * b, u8 * a, size_t len) | ||
115 | { | ||
116 | int i; | ||
117 | for (i = 0; i < len; i++) | ||
118 | b[i] ^= a[i]; | ||
119 | } | ||
120 | |||
121 | static void ccmp_init_blocks(struct crypto_tfm *tfm, | ||
122 | struct ieee80211_hdr *hdr, | ||
123 | u8 * pn, size_t dlen, u8 * b0, u8 * auth, u8 * s0) | ||
124 | { | ||
125 | u8 *pos, qc = 0; | ||
126 | size_t aad_len; | ||
127 | u16 fc; | ||
128 | int a4_included, qc_included; | ||
129 | u8 aad[2 * AES_BLOCK_LEN]; | ||
130 | |||
131 | fc = le16_to_cpu(hdr->frame_ctl); | ||
132 | a4_included = ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | ||
133 | (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)); | ||
134 | qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && | ||
135 | (WLAN_FC_GET_STYPE(fc) & 0x08)); | ||
136 | aad_len = 22; | ||
137 | if (a4_included) | ||
138 | aad_len += 6; | ||
139 | if (qc_included) { | ||
140 | pos = (u8 *) & hdr->addr4; | ||
141 | if (a4_included) | ||
142 | pos += 6; | ||
143 | qc = *pos & 0x0f; | ||
144 | aad_len += 2; | ||
145 | } | ||
146 | |||
147 | /* CCM Initial Block: | ||
148 | * Flag (Include authentication header, M=3 (8-octet MIC), | ||
149 | * L=1 (2-octet Dlen)) | ||
150 | * Nonce: 0x00 | A2 | PN | ||
151 | * Dlen */ | ||
152 | b0[0] = 0x59; | ||
153 | b0[1] = qc; | ||
154 | memcpy(b0 + 2, hdr->addr2, ETH_ALEN); | ||
155 | memcpy(b0 + 8, pn, CCMP_PN_LEN); | ||
156 | b0[14] = (dlen >> 8) & 0xff; | ||
157 | b0[15] = dlen & 0xff; | ||
158 | |||
159 | /* AAD: | ||
160 | * FC with bits 4..6 and 11..13 masked to zero; 14 is always one | ||
161 | * A1 | A2 | A3 | ||
162 | * SC with bits 4..15 (seq#) masked to zero | ||
163 | * A4 (if present) | ||
164 | * QC (if present) | ||
165 | */ | ||
166 | pos = (u8 *) hdr; | ||
167 | aad[0] = 0; /* aad_len >> 8 */ | ||
168 | aad[1] = aad_len & 0xff; | ||
169 | aad[2] = pos[0] & 0x8f; | ||
170 | aad[3] = pos[1] & 0xc7; | ||
171 | memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN); | ||
172 | pos = (u8 *) & hdr->seq_ctl; | ||
173 | aad[22] = pos[0] & 0x0f; | ||
174 | aad[23] = 0; /* all bits masked */ | ||
175 | memset(aad + 24, 0, 8); | ||
176 | if (a4_included) | ||
177 | memcpy(aad + 24, hdr->addr4, ETH_ALEN); | ||
178 | if (qc_included) { | ||
179 | aad[a4_included ? 30 : 24] = qc; | ||
180 | /* rest of QC masked */ | ||
181 | } | ||
182 | |||
183 | /* Start with the first block and AAD */ | ||
184 | ieee80211_ccmp_aes_encrypt(tfm, b0, auth); | ||
185 | xor_block(auth, aad, AES_BLOCK_LEN); | ||
186 | ieee80211_ccmp_aes_encrypt(tfm, auth, auth); | ||
187 | xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN); | ||
188 | ieee80211_ccmp_aes_encrypt(tfm, auth, auth); | ||
189 | b0[0] &= 0x07; | ||
190 | b0[14] = b0[15] = 0; | ||
191 | ieee80211_ccmp_aes_encrypt(tfm, b0, s0); | ||
192 | } | ||
193 | |||
194 | static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | ||
195 | { | ||
196 | struct ieee80211_ccmp_data *key = priv; | ||
197 | int data_len, i, blocks, last, len; | ||
198 | u8 *pos, *mic; | ||
199 | struct ieee80211_hdr *hdr; | ||
200 | u8 *b0 = key->tx_b0; | ||
201 | u8 *b = key->tx_b; | ||
202 | u8 *e = key->tx_e; | ||
203 | u8 *s0 = key->tx_s0; | ||
204 | |||
205 | if (skb_headroom(skb) < CCMP_HDR_LEN || | ||
206 | skb_tailroom(skb) < CCMP_MIC_LEN || skb->len < hdr_len) | ||
207 | return -1; | ||
208 | |||
209 | data_len = skb->len - hdr_len; | ||
210 | pos = skb_push(skb, CCMP_HDR_LEN); | ||
211 | memmove(pos, pos + CCMP_HDR_LEN, hdr_len); | ||
212 | pos += hdr_len; | ||
213 | mic = skb_put(skb, CCMP_MIC_LEN); | ||
214 | |||
215 | i = CCMP_PN_LEN - 1; | ||
216 | while (i >= 0) { | ||
217 | key->tx_pn[i]++; | ||
218 | if (key->tx_pn[i] != 0) | ||
219 | break; | ||
220 | i--; | ||
221 | } | ||
222 | |||
223 | *pos++ = key->tx_pn[5]; | ||
224 | *pos++ = key->tx_pn[4]; | ||
225 | *pos++ = 0; | ||
226 | *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */ ; | ||
227 | *pos++ = key->tx_pn[3]; | ||
228 | *pos++ = key->tx_pn[2]; | ||
229 | *pos++ = key->tx_pn[1]; | ||
230 | *pos++ = key->tx_pn[0]; | ||
231 | |||
232 | hdr = (struct ieee80211_hdr *)skb->data; | ||
233 | ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); | ||
234 | |||
235 | blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; | ||
236 | last = data_len % AES_BLOCK_LEN; | ||
237 | |||
238 | for (i = 1; i <= blocks; i++) { | ||
239 | len = (i == blocks && last) ? last : AES_BLOCK_LEN; | ||
240 | /* Authentication */ | ||
241 | xor_block(b, pos, len); | ||
242 | ieee80211_ccmp_aes_encrypt(key->tfm, b, b); | ||
243 | /* Encryption, with counter */ | ||
244 | b0[14] = (i >> 8) & 0xff; | ||
245 | b0[15] = i & 0xff; | ||
246 | ieee80211_ccmp_aes_encrypt(key->tfm, b0, e); | ||
247 | xor_block(pos, e, len); | ||
248 | pos += len; | ||
249 | } | ||
250 | |||
251 | for (i = 0; i < CCMP_MIC_LEN; i++) | ||
252 | mic[i] = b[i] ^ s0[i]; | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) | ||
258 | { | ||
259 | struct ieee80211_ccmp_data *key = priv; | ||
260 | u8 keyidx, *pos; | ||
261 | struct ieee80211_hdr *hdr; | ||
262 | u8 *b0 = key->rx_b0; | ||
263 | u8 *b = key->rx_b; | ||
264 | u8 *a = key->rx_a; | ||
265 | u8 pn[6]; | ||
266 | int i, blocks, last, len; | ||
267 | size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN; | ||
268 | u8 *mic = skb->data + skb->len - CCMP_MIC_LEN; | ||
269 | |||
270 | if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { | ||
271 | key->dot11RSNAStatsCCMPFormatErrors++; | ||
272 | return -1; | ||
273 | } | ||
274 | |||
275 | hdr = (struct ieee80211_hdr *)skb->data; | ||
276 | pos = skb->data + hdr_len; | ||
277 | keyidx = pos[3]; | ||
278 | if (!(keyidx & (1 << 5))) { | ||
279 | if (net_ratelimit()) { | ||
280 | printk(KERN_DEBUG "CCMP: received packet without ExtIV" | ||
281 | " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); | ||
282 | } | ||
283 | key->dot11RSNAStatsCCMPFormatErrors++; | ||
284 | return -2; | ||
285 | } | ||
286 | keyidx >>= 6; | ||
287 | if (key->key_idx != keyidx) { | ||
288 | printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame " | ||
289 | "keyidx=%d priv=%p\n", key->key_idx, keyidx, priv); | ||
290 | return -6; | ||
291 | } | ||
292 | if (!key->key_set) { | ||
293 | if (net_ratelimit()) { | ||
294 | printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT | ||
295 | " with keyid=%d that does not have a configured" | ||
296 | " key\n", MAC_ARG(hdr->addr2), keyidx); | ||
297 | } | ||
298 | return -3; | ||
299 | } | ||
300 | |||
301 | pn[0] = pos[7]; | ||
302 | pn[1] = pos[6]; | ||
303 | pn[2] = pos[5]; | ||
304 | pn[3] = pos[4]; | ||
305 | pn[4] = pos[1]; | ||
306 | pn[5] = pos[0]; | ||
307 | pos += 8; | ||
308 | |||
309 | if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) { | ||
310 | if (net_ratelimit()) { | ||
311 | printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT | ||
312 | " previous PN %02x%02x%02x%02x%02x%02x " | ||
313 | "received PN %02x%02x%02x%02x%02x%02x\n", | ||
314 | MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn), | ||
315 | MAC_ARG(pn)); | ||
316 | } | ||
317 | key->dot11RSNAStatsCCMPReplays++; | ||
318 | return -4; | ||
319 | } | ||
320 | |||
321 | ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b); | ||
322 | xor_block(mic, b, CCMP_MIC_LEN); | ||
323 | |||
324 | blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; | ||
325 | last = data_len % AES_BLOCK_LEN; | ||
326 | |||
327 | for (i = 1; i <= blocks; i++) { | ||
328 | len = (i == blocks && last) ? last : AES_BLOCK_LEN; | ||
329 | /* Decrypt, with counter */ | ||
330 | b0[14] = (i >> 8) & 0xff; | ||
331 | b0[15] = i & 0xff; | ||
332 | ieee80211_ccmp_aes_encrypt(key->tfm, b0, b); | ||
333 | xor_block(pos, b, len); | ||
334 | /* Authentication */ | ||
335 | xor_block(a, pos, len); | ||
336 | ieee80211_ccmp_aes_encrypt(key->tfm, a, a); | ||
337 | pos += len; | ||
338 | } | ||
339 | |||
340 | if (memcmp(mic, a, CCMP_MIC_LEN) != 0) { | ||
341 | if (net_ratelimit()) { | ||
342 | printk(KERN_DEBUG "CCMP: decrypt failed: STA=" | ||
343 | MAC_FMT "\n", MAC_ARG(hdr->addr2)); | ||
344 | } | ||
345 | key->dot11RSNAStatsCCMPDecryptErrors++; | ||
346 | return -5; | ||
347 | } | ||
348 | |||
349 | memcpy(key->rx_pn, pn, CCMP_PN_LEN); | ||
350 | |||
351 | /* Remove hdr and MIC */ | ||
352 | memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len); | ||
353 | skb_pull(skb, CCMP_HDR_LEN); | ||
354 | skb_trim(skb, skb->len - CCMP_MIC_LEN); | ||
355 | |||
356 | return keyidx; | ||
357 | } | ||
358 | |||
359 | static int ieee80211_ccmp_set_key(void *key, int len, u8 * seq, void *priv) | ||
360 | { | ||
361 | struct ieee80211_ccmp_data *data = priv; | ||
362 | int keyidx; | ||
363 | struct crypto_tfm *tfm = data->tfm; | ||
364 | |||
365 | keyidx = data->key_idx; | ||
366 | memset(data, 0, sizeof(*data)); | ||
367 | data->key_idx = keyidx; | ||
368 | data->tfm = tfm; | ||
369 | if (len == CCMP_TK_LEN) { | ||
370 | memcpy(data->key, key, CCMP_TK_LEN); | ||
371 | data->key_set = 1; | ||
372 | if (seq) { | ||
373 | data->rx_pn[0] = seq[5]; | ||
374 | data->rx_pn[1] = seq[4]; | ||
375 | data->rx_pn[2] = seq[3]; | ||
376 | data->rx_pn[3] = seq[2]; | ||
377 | data->rx_pn[4] = seq[1]; | ||
378 | data->rx_pn[5] = seq[0]; | ||
379 | } | ||
380 | crypto_cipher_setkey(data->tfm, data->key, CCMP_TK_LEN); | ||
381 | } else if (len == 0) | ||
382 | data->key_set = 0; | ||
383 | else | ||
384 | return -1; | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static int ieee80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv) | ||
390 | { | ||
391 | struct ieee80211_ccmp_data *data = priv; | ||
392 | |||
393 | if (len < CCMP_TK_LEN) | ||
394 | return -1; | ||
395 | |||
396 | if (!data->key_set) | ||
397 | return 0; | ||
398 | memcpy(key, data->key, CCMP_TK_LEN); | ||
399 | |||
400 | if (seq) { | ||
401 | seq[0] = data->tx_pn[5]; | ||
402 | seq[1] = data->tx_pn[4]; | ||
403 | seq[2] = data->tx_pn[3]; | ||
404 | seq[3] = data->tx_pn[2]; | ||
405 | seq[4] = data->tx_pn[1]; | ||
406 | seq[5] = data->tx_pn[0]; | ||
407 | } | ||
408 | |||
409 | return CCMP_TK_LEN; | ||
410 | } | ||
411 | |||
412 | static char *ieee80211_ccmp_print_stats(char *p, void *priv) | ||
413 | { | ||
414 | struct ieee80211_ccmp_data *ccmp = priv; | ||
415 | p += sprintf(p, "key[%d] alg=CCMP key_set=%d " | ||
416 | "tx_pn=%02x%02x%02x%02x%02x%02x " | ||
417 | "rx_pn=%02x%02x%02x%02x%02x%02x " | ||
418 | "format_errors=%d replays=%d decrypt_errors=%d\n", | ||
419 | ccmp->key_idx, ccmp->key_set, | ||
420 | MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn), | ||
421 | ccmp->dot11RSNAStatsCCMPFormatErrors, | ||
422 | ccmp->dot11RSNAStatsCCMPReplays, | ||
423 | ccmp->dot11RSNAStatsCCMPDecryptErrors); | ||
424 | |||
425 | return p; | ||
426 | } | ||
427 | |||
428 | static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = { | ||
429 | .name = "CCMP", | ||
430 | .init = ieee80211_ccmp_init, | ||
431 | .deinit = ieee80211_ccmp_deinit, | ||
432 | .encrypt_mpdu = ieee80211_ccmp_encrypt, | ||
433 | .decrypt_mpdu = ieee80211_ccmp_decrypt, | ||
434 | .encrypt_msdu = NULL, | ||
435 | .decrypt_msdu = NULL, | ||
436 | .set_key = ieee80211_ccmp_set_key, | ||
437 | .get_key = ieee80211_ccmp_get_key, | ||
438 | .print_stats = ieee80211_ccmp_print_stats, | ||
439 | .extra_prefix_len = CCMP_HDR_LEN, | ||
440 | .extra_postfix_len = CCMP_MIC_LEN, | ||
441 | .owner = THIS_MODULE, | ||
442 | }; | ||
443 | |||
444 | static int __init ieee80211_crypto_ccmp_init(void) | ||
445 | { | ||
446 | return ieee80211_register_crypto_ops(&ieee80211_crypt_ccmp); | ||
447 | } | ||
448 | |||
449 | static void __exit ieee80211_crypto_ccmp_exit(void) | ||
450 | { | ||
451 | ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp); | ||
452 | } | ||
453 | |||
454 | module_init(ieee80211_crypto_ccmp_init); | ||
455 | module_exit(ieee80211_crypto_ccmp_exit); | ||
diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c new file mode 100644 index 000000000000..d4f9164be1a1 --- /dev/null +++ b/net/ieee80211/ieee80211_crypt_tkip.c | |||
@@ -0,0 +1,683 @@ | |||
1 | /* | ||
2 | * Host AP crypt: host-based TKIP encryption implementation for Host AP driver | ||
3 | * | ||
4 | * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi> | ||
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 version 2 as | ||
8 | * published by the Free Software Foundation. See README and COPYING for | ||
9 | * more details. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/version.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/random.h> | ||
18 | #include <linux/skbuff.h> | ||
19 | #include <linux/netdevice.h> | ||
20 | #include <linux/if_ether.h> | ||
21 | #include <linux/if_arp.h> | ||
22 | #include <asm/string.h> | ||
23 | |||
24 | #include <net/ieee80211.h> | ||
25 | |||
26 | #include <linux/crypto.h> | ||
27 | #include <asm/scatterlist.h> | ||
28 | #include <linux/crc32.h> | ||
29 | |||
30 | MODULE_AUTHOR("Jouni Malinen"); | ||
31 | MODULE_DESCRIPTION("Host AP crypt: TKIP"); | ||
32 | MODULE_LICENSE("GPL"); | ||
33 | |||
34 | struct ieee80211_tkip_data { | ||
35 | #define TKIP_KEY_LEN 32 | ||
36 | u8 key[TKIP_KEY_LEN]; | ||
37 | int key_set; | ||
38 | |||
39 | u32 tx_iv32; | ||
40 | u16 tx_iv16; | ||
41 | u16 tx_ttak[5]; | ||
42 | int tx_phase1_done; | ||
43 | |||
44 | u32 rx_iv32; | ||
45 | u16 rx_iv16; | ||
46 | u16 rx_ttak[5]; | ||
47 | int rx_phase1_done; | ||
48 | u32 rx_iv32_new; | ||
49 | u16 rx_iv16_new; | ||
50 | |||
51 | u32 dot11RSNAStatsTKIPReplays; | ||
52 | u32 dot11RSNAStatsTKIPICVErrors; | ||
53 | u32 dot11RSNAStatsTKIPLocalMICFailures; | ||
54 | |||
55 | int key_idx; | ||
56 | |||
57 | struct crypto_tfm *tfm_arc4; | ||
58 | struct crypto_tfm *tfm_michael; | ||
59 | |||
60 | /* scratch buffers for virt_to_page() (crypto API) */ | ||
61 | u8 rx_hdr[16], tx_hdr[16]; | ||
62 | }; | ||
63 | |||
64 | static void *ieee80211_tkip_init(int key_idx) | ||
65 | { | ||
66 | struct ieee80211_tkip_data *priv; | ||
67 | |||
68 | priv = kmalloc(sizeof(*priv), GFP_ATOMIC); | ||
69 | if (priv == NULL) | ||
70 | goto fail; | ||
71 | memset(priv, 0, sizeof(*priv)); | ||
72 | priv->key_idx = key_idx; | ||
73 | |||
74 | priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0); | ||
75 | if (priv->tfm_arc4 == NULL) { | ||
76 | printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " | ||
77 | "crypto API arc4\n"); | ||
78 | goto fail; | ||
79 | } | ||
80 | |||
81 | priv->tfm_michael = crypto_alloc_tfm("michael_mic", 0); | ||
82 | if (priv->tfm_michael == NULL) { | ||
83 | printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " | ||
84 | "crypto API michael_mic\n"); | ||
85 | goto fail; | ||
86 | } | ||
87 | |||
88 | return priv; | ||
89 | |||
90 | fail: | ||
91 | if (priv) { | ||
92 | if (priv->tfm_michael) | ||
93 | crypto_free_tfm(priv->tfm_michael); | ||
94 | if (priv->tfm_arc4) | ||
95 | crypto_free_tfm(priv->tfm_arc4); | ||
96 | kfree(priv); | ||
97 | } | ||
98 | |||
99 | return NULL; | ||
100 | } | ||
101 | |||
102 | static void ieee80211_tkip_deinit(void *priv) | ||
103 | { | ||
104 | struct ieee80211_tkip_data *_priv = priv; | ||
105 | if (_priv && _priv->tfm_michael) | ||
106 | crypto_free_tfm(_priv->tfm_michael); | ||
107 | if (_priv && _priv->tfm_arc4) | ||
108 | crypto_free_tfm(_priv->tfm_arc4); | ||
109 | kfree(priv); | ||
110 | } | ||
111 | |||
112 | static inline u16 RotR1(u16 val) | ||
113 | { | ||
114 | return (val >> 1) | (val << 15); | ||
115 | } | ||
116 | |||
117 | static inline u8 Lo8(u16 val) | ||
118 | { | ||
119 | return val & 0xff; | ||
120 | } | ||
121 | |||
122 | static inline u8 Hi8(u16 val) | ||
123 | { | ||
124 | return val >> 8; | ||
125 | } | ||
126 | |||
127 | static inline u16 Lo16(u32 val) | ||
128 | { | ||
129 | return val & 0xffff; | ||
130 | } | ||
131 | |||
132 | static inline u16 Hi16(u32 val) | ||
133 | { | ||
134 | return val >> 16; | ||
135 | } | ||
136 | |||
137 | static inline u16 Mk16(u8 hi, u8 lo) | ||
138 | { | ||
139 | return lo | (((u16) hi) << 8); | ||
140 | } | ||
141 | |||
142 | static inline u16 Mk16_le(u16 * v) | ||
143 | { | ||
144 | return le16_to_cpu(*v); | ||
145 | } | ||
146 | |||
147 | static const u16 Sbox[256] = { | ||
148 | 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, | ||
149 | 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, | ||
150 | 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, | ||
151 | 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, | ||
152 | 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, | ||
153 | 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, | ||
154 | 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, | ||
155 | 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, | ||
156 | 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, | ||
157 | 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, | ||
158 | 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, | ||
159 | 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, | ||
160 | 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, | ||
161 | 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, | ||
162 | 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, | ||
163 | 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, | ||
164 | 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, | ||
165 | 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, | ||
166 | 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, | ||
167 | 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, | ||
168 | 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, | ||
169 | 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, | ||
170 | 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, | ||
171 | 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, | ||
172 | 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, | ||
173 | 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, | ||
174 | 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, | ||
175 | 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, | ||
176 | 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, | ||
177 | 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, | ||
178 | 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, | ||
179 | 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, | ||
180 | }; | ||
181 | |||
182 | static inline u16 _S_(u16 v) | ||
183 | { | ||
184 | u16 t = Sbox[Hi8(v)]; | ||
185 | return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); | ||
186 | } | ||
187 | |||
188 | #define PHASE1_LOOP_COUNT 8 | ||
189 | |||
190 | static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA, | ||
191 | u32 IV32) | ||
192 | { | ||
193 | int i, j; | ||
194 | |||
195 | /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ | ||
196 | TTAK[0] = Lo16(IV32); | ||
197 | TTAK[1] = Hi16(IV32); | ||
198 | TTAK[2] = Mk16(TA[1], TA[0]); | ||
199 | TTAK[3] = Mk16(TA[3], TA[2]); | ||
200 | TTAK[4] = Mk16(TA[5], TA[4]); | ||
201 | |||
202 | for (i = 0; i < PHASE1_LOOP_COUNT; i++) { | ||
203 | j = 2 * (i & 1); | ||
204 | TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); | ||
205 | TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); | ||
206 | TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); | ||
207 | TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); | ||
208 | TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK, | ||
213 | u16 IV16) | ||
214 | { | ||
215 | /* Make temporary area overlap WEP seed so that the final copy can be | ||
216 | * avoided on little endian hosts. */ | ||
217 | u16 *PPK = (u16 *) & WEPSeed[4]; | ||
218 | |||
219 | /* Step 1 - make copy of TTAK and bring in TSC */ | ||
220 | PPK[0] = TTAK[0]; | ||
221 | PPK[1] = TTAK[1]; | ||
222 | PPK[2] = TTAK[2]; | ||
223 | PPK[3] = TTAK[3]; | ||
224 | PPK[4] = TTAK[4]; | ||
225 | PPK[5] = TTAK[4] + IV16; | ||
226 | |||
227 | /* Step 2 - 96-bit bijective mixing using S-box */ | ||
228 | PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) & TK[0])); | ||
229 | PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) & TK[2])); | ||
230 | PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) & TK[4])); | ||
231 | PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) & TK[6])); | ||
232 | PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) & TK[8])); | ||
233 | PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) & TK[10])); | ||
234 | |||
235 | PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) & TK[12])); | ||
236 | PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) & TK[14])); | ||
237 | PPK[2] += RotR1(PPK[1]); | ||
238 | PPK[3] += RotR1(PPK[2]); | ||
239 | PPK[4] += RotR1(PPK[3]); | ||
240 | PPK[5] += RotR1(PPK[4]); | ||
241 | |||
242 | /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value | ||
243 | * WEPSeed[0..2] is transmitted as WEP IV */ | ||
244 | WEPSeed[0] = Hi8(IV16); | ||
245 | WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; | ||
246 | WEPSeed[2] = Lo8(IV16); | ||
247 | WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) & TK[0])) >> 1); | ||
248 | |||
249 | #ifdef __BIG_ENDIAN | ||
250 | { | ||
251 | int i; | ||
252 | for (i = 0; i < 6; i++) | ||
253 | PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); | ||
254 | } | ||
255 | #endif | ||
256 | } | ||
257 | |||
258 | static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | ||
259 | { | ||
260 | struct ieee80211_tkip_data *tkey = priv; | ||
261 | int len; | ||
262 | u8 rc4key[16], *pos, *icv; | ||
263 | struct ieee80211_hdr *hdr; | ||
264 | u32 crc; | ||
265 | struct scatterlist sg; | ||
266 | |||
267 | if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 || | ||
268 | skb->len < hdr_len) | ||
269 | return -1; | ||
270 | |||
271 | hdr = (struct ieee80211_hdr *)skb->data; | ||
272 | if (!tkey->tx_phase1_done) { | ||
273 | tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, | ||
274 | tkey->tx_iv32); | ||
275 | tkey->tx_phase1_done = 1; | ||
276 | } | ||
277 | tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); | ||
278 | |||
279 | len = skb->len - hdr_len; | ||
280 | pos = skb_push(skb, 8); | ||
281 | memmove(pos, pos + 8, hdr_len); | ||
282 | pos += hdr_len; | ||
283 | icv = skb_put(skb, 4); | ||
284 | |||
285 | *pos++ = rc4key[0]; | ||
286 | *pos++ = rc4key[1]; | ||
287 | *pos++ = rc4key[2]; | ||
288 | *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ; | ||
289 | *pos++ = tkey->tx_iv32 & 0xff; | ||
290 | *pos++ = (tkey->tx_iv32 >> 8) & 0xff; | ||
291 | *pos++ = (tkey->tx_iv32 >> 16) & 0xff; | ||
292 | *pos++ = (tkey->tx_iv32 >> 24) & 0xff; | ||
293 | |||
294 | crc = ~crc32_le(~0, pos, len); | ||
295 | icv[0] = crc; | ||
296 | icv[1] = crc >> 8; | ||
297 | icv[2] = crc >> 16; | ||
298 | icv[3] = crc >> 24; | ||
299 | |||
300 | crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); | ||
301 | sg.page = virt_to_page(pos); | ||
302 | sg.offset = offset_in_page(pos); | ||
303 | sg.length = len + 4; | ||
304 | crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4); | ||
305 | |||
306 | tkey->tx_iv16++; | ||
307 | if (tkey->tx_iv16 == 0) { | ||
308 | tkey->tx_phase1_done = 0; | ||
309 | tkey->tx_iv32++; | ||
310 | } | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) | ||
316 | { | ||
317 | struct ieee80211_tkip_data *tkey = priv; | ||
318 | u8 rc4key[16]; | ||
319 | u8 keyidx, *pos; | ||
320 | u32 iv32; | ||
321 | u16 iv16; | ||
322 | struct ieee80211_hdr *hdr; | ||
323 | u8 icv[4]; | ||
324 | u32 crc; | ||
325 | struct scatterlist sg; | ||
326 | int plen; | ||
327 | |||
328 | if (skb->len < hdr_len + 8 + 4) | ||
329 | return -1; | ||
330 | |||
331 | hdr = (struct ieee80211_hdr *)skb->data; | ||
332 | pos = skb->data + hdr_len; | ||
333 | keyidx = pos[3]; | ||
334 | if (!(keyidx & (1 << 5))) { | ||
335 | if (net_ratelimit()) { | ||
336 | printk(KERN_DEBUG "TKIP: received packet without ExtIV" | ||
337 | " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); | ||
338 | } | ||
339 | return -2; | ||
340 | } | ||
341 | keyidx >>= 6; | ||
342 | if (tkey->key_idx != keyidx) { | ||
343 | printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame " | ||
344 | "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv); | ||
345 | return -6; | ||
346 | } | ||
347 | if (!tkey->key_set) { | ||
348 | if (net_ratelimit()) { | ||
349 | printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT | ||
350 | " with keyid=%d that does not have a configured" | ||
351 | " key\n", MAC_ARG(hdr->addr2), keyidx); | ||
352 | } | ||
353 | return -3; | ||
354 | } | ||
355 | iv16 = (pos[0] << 8) | pos[2]; | ||
356 | iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); | ||
357 | pos += 8; | ||
358 | |||
359 | if (iv32 < tkey->rx_iv32 || | ||
360 | (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) { | ||
361 | if (net_ratelimit()) { | ||
362 | printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT | ||
363 | " previous TSC %08x%04x received TSC " | ||
364 | "%08x%04x\n", MAC_ARG(hdr->addr2), | ||
365 | tkey->rx_iv32, tkey->rx_iv16, iv32, iv16); | ||
366 | } | ||
367 | tkey->dot11RSNAStatsTKIPReplays++; | ||
368 | return -4; | ||
369 | } | ||
370 | |||
371 | if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) { | ||
372 | tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32); | ||
373 | tkey->rx_phase1_done = 1; | ||
374 | } | ||
375 | tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16); | ||
376 | |||
377 | plen = skb->len - hdr_len - 12; | ||
378 | |||
379 | crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); | ||
380 | sg.page = virt_to_page(pos); | ||
381 | sg.offset = offset_in_page(pos); | ||
382 | sg.length = plen + 4; | ||
383 | crypto_cipher_decrypt(tkey->tfm_arc4, &sg, &sg, plen + 4); | ||
384 | |||
385 | crc = ~crc32_le(~0, pos, plen); | ||
386 | icv[0] = crc; | ||
387 | icv[1] = crc >> 8; | ||
388 | icv[2] = crc >> 16; | ||
389 | icv[3] = crc >> 24; | ||
390 | if (memcmp(icv, pos + plen, 4) != 0) { | ||
391 | if (iv32 != tkey->rx_iv32) { | ||
392 | /* Previously cached Phase1 result was already lost, so | ||
393 | * it needs to be recalculated for the next packet. */ | ||
394 | tkey->rx_phase1_done = 0; | ||
395 | } | ||
396 | if (net_ratelimit()) { | ||
397 | printk(KERN_DEBUG "TKIP: ICV error detected: STA=" | ||
398 | MAC_FMT "\n", MAC_ARG(hdr->addr2)); | ||
399 | } | ||
400 | tkey->dot11RSNAStatsTKIPICVErrors++; | ||
401 | return -5; | ||
402 | } | ||
403 | |||
404 | /* Update real counters only after Michael MIC verification has | ||
405 | * completed */ | ||
406 | tkey->rx_iv32_new = iv32; | ||
407 | tkey->rx_iv16_new = iv16; | ||
408 | |||
409 | /* Remove IV and ICV */ | ||
410 | memmove(skb->data + 8, skb->data, hdr_len); | ||
411 | skb_pull(skb, 8); | ||
412 | skb_trim(skb, skb->len - 4); | ||
413 | |||
414 | return keyidx; | ||
415 | } | ||
416 | |||
417 | static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr, | ||
418 | u8 * data, size_t data_len, u8 * mic) | ||
419 | { | ||
420 | struct scatterlist sg[2]; | ||
421 | |||
422 | if (tkey->tfm_michael == NULL) { | ||
423 | printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); | ||
424 | return -1; | ||
425 | } | ||
426 | sg[0].page = virt_to_page(hdr); | ||
427 | sg[0].offset = offset_in_page(hdr); | ||
428 | sg[0].length = 16; | ||
429 | |||
430 | sg[1].page = virt_to_page(data); | ||
431 | sg[1].offset = offset_in_page(data); | ||
432 | sg[1].length = data_len; | ||
433 | |||
434 | crypto_digest_init(tkey->tfm_michael); | ||
435 | crypto_digest_setkey(tkey->tfm_michael, key, 8); | ||
436 | crypto_digest_update(tkey->tfm_michael, sg, 2); | ||
437 | crypto_digest_final(tkey->tfm_michael, mic); | ||
438 | |||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) | ||
443 | { | ||
444 | struct ieee80211_hdr *hdr11; | ||
445 | |||
446 | hdr11 = (struct ieee80211_hdr *)skb->data; | ||
447 | switch (le16_to_cpu(hdr11->frame_ctl) & | ||
448 | (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { | ||
449 | case IEEE80211_FCTL_TODS: | ||
450 | memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ | ||
451 | memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ | ||
452 | break; | ||
453 | case IEEE80211_FCTL_FROMDS: | ||
454 | memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ | ||
455 | memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */ | ||
456 | break; | ||
457 | case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: | ||
458 | memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ | ||
459 | memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */ | ||
460 | break; | ||
461 | case 0: | ||
462 | memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ | ||
463 | memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ | ||
464 | break; | ||
465 | } | ||
466 | |||
467 | hdr[12] = 0; /* priority */ | ||
468 | hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ | ||
469 | } | ||
470 | |||
471 | static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, | ||
472 | void *priv) | ||
473 | { | ||
474 | struct ieee80211_tkip_data *tkey = priv; | ||
475 | u8 *pos; | ||
476 | |||
477 | if (skb_tailroom(skb) < 8 || skb->len < hdr_len) { | ||
478 | printk(KERN_DEBUG "Invalid packet for Michael MIC add " | ||
479 | "(tailroom=%d hdr_len=%d skb->len=%d)\n", | ||
480 | skb_tailroom(skb), hdr_len, skb->len); | ||
481 | return -1; | ||
482 | } | ||
483 | |||
484 | michael_mic_hdr(skb, tkey->tx_hdr); | ||
485 | pos = skb_put(skb, 8); | ||
486 | if (michael_mic(tkey, &tkey->key[16], tkey->tx_hdr, | ||
487 | skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) | ||
488 | return -1; | ||
489 | |||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | #if WIRELESS_EXT >= 18 | ||
494 | static void ieee80211_michael_mic_failure(struct net_device *dev, | ||
495 | struct ieee80211_hdr *hdr, int keyidx) | ||
496 | { | ||
497 | union iwreq_data wrqu; | ||
498 | struct iw_michaelmicfailure ev; | ||
499 | |||
500 | /* TODO: needed parameters: count, keyid, key type, TSC */ | ||
501 | memset(&ev, 0, sizeof(ev)); | ||
502 | ev.flags = keyidx & IW_MICFAILURE_KEY_ID; | ||
503 | if (hdr->addr1[0] & 0x01) | ||
504 | ev.flags |= IW_MICFAILURE_GROUP; | ||
505 | else | ||
506 | ev.flags |= IW_MICFAILURE_PAIRWISE; | ||
507 | ev.src_addr.sa_family = ARPHRD_ETHER; | ||
508 | memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN); | ||
509 | memset(&wrqu, 0, sizeof(wrqu)); | ||
510 | wrqu.data.length = sizeof(ev); | ||
511 | wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev); | ||
512 | } | ||
513 | #elif WIRELESS_EXT >= 15 | ||
514 | static void ieee80211_michael_mic_failure(struct net_device *dev, | ||
515 | struct ieee80211_hdr *hdr, int keyidx) | ||
516 | { | ||
517 | union iwreq_data wrqu; | ||
518 | char buf[128]; | ||
519 | |||
520 | /* TODO: needed parameters: count, keyid, key type, TSC */ | ||
521 | sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=" | ||
522 | MAC_FMT ")", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", | ||
523 | MAC_ARG(hdr->addr2)); | ||
524 | memset(&wrqu, 0, sizeof(wrqu)); | ||
525 | wrqu.data.length = strlen(buf); | ||
526 | wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); | ||
527 | } | ||
528 | #else /* WIRELESS_EXT >= 15 */ | ||
529 | static inline void ieee80211_michael_mic_failure(struct net_device *dev, | ||
530 | struct ieee80211_hdr *hdr, | ||
531 | int keyidx) | ||
532 | { | ||
533 | } | ||
534 | #endif /* WIRELESS_EXT >= 15 */ | ||
535 | |||
536 | static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, | ||
537 | int hdr_len, void *priv) | ||
538 | { | ||
539 | struct ieee80211_tkip_data *tkey = priv; | ||
540 | u8 mic[8]; | ||
541 | |||
542 | if (!tkey->key_set) | ||
543 | return -1; | ||
544 | |||
545 | michael_mic_hdr(skb, tkey->rx_hdr); | ||
546 | if (michael_mic(tkey, &tkey->key[24], tkey->rx_hdr, | ||
547 | skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) | ||
548 | return -1; | ||
549 | if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { | ||
550 | struct ieee80211_hdr *hdr; | ||
551 | hdr = (struct ieee80211_hdr *)skb->data; | ||
552 | printk(KERN_DEBUG "%s: Michael MIC verification failed for " | ||
553 | "MSDU from " MAC_FMT " keyidx=%d\n", | ||
554 | skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2), | ||
555 | keyidx); | ||
556 | if (skb->dev) | ||
557 | ieee80211_michael_mic_failure(skb->dev, hdr, keyidx); | ||
558 | tkey->dot11RSNAStatsTKIPLocalMICFailures++; | ||
559 | return -1; | ||
560 | } | ||
561 | |||
562 | /* Update TSC counters for RX now that the packet verification has | ||
563 | * completed. */ | ||
564 | tkey->rx_iv32 = tkey->rx_iv32_new; | ||
565 | tkey->rx_iv16 = tkey->rx_iv16_new; | ||
566 | |||
567 | skb_trim(skb, skb->len - 8); | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | static int ieee80211_tkip_set_key(void *key, int len, u8 * seq, void *priv) | ||
573 | { | ||
574 | struct ieee80211_tkip_data *tkey = priv; | ||
575 | int keyidx; | ||
576 | struct crypto_tfm *tfm = tkey->tfm_michael; | ||
577 | struct crypto_tfm *tfm2 = tkey->tfm_arc4; | ||
578 | |||
579 | keyidx = tkey->key_idx; | ||
580 | memset(tkey, 0, sizeof(*tkey)); | ||
581 | tkey->key_idx = keyidx; | ||
582 | tkey->tfm_michael = tfm; | ||
583 | tkey->tfm_arc4 = tfm2; | ||
584 | if (len == TKIP_KEY_LEN) { | ||
585 | memcpy(tkey->key, key, TKIP_KEY_LEN); | ||
586 | tkey->key_set = 1; | ||
587 | tkey->tx_iv16 = 1; /* TSC is initialized to 1 */ | ||
588 | if (seq) { | ||
589 | tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) | | ||
590 | (seq[3] << 8) | seq[2]; | ||
591 | tkey->rx_iv16 = (seq[1] << 8) | seq[0]; | ||
592 | } | ||
593 | } else if (len == 0) | ||
594 | tkey->key_set = 0; | ||
595 | else | ||
596 | return -1; | ||
597 | |||
598 | return 0; | ||
599 | } | ||
600 | |||
601 | static int ieee80211_tkip_get_key(void *key, int len, u8 * seq, void *priv) | ||
602 | { | ||
603 | struct ieee80211_tkip_data *tkey = priv; | ||
604 | |||
605 | if (len < TKIP_KEY_LEN) | ||
606 | return -1; | ||
607 | |||
608 | if (!tkey->key_set) | ||
609 | return 0; | ||
610 | memcpy(key, tkey->key, TKIP_KEY_LEN); | ||
611 | |||
612 | if (seq) { | ||
613 | /* Return the sequence number of the last transmitted frame. */ | ||
614 | u16 iv16 = tkey->tx_iv16; | ||
615 | u32 iv32 = tkey->tx_iv32; | ||
616 | if (iv16 == 0) | ||
617 | iv32--; | ||
618 | iv16--; | ||
619 | seq[0] = tkey->tx_iv16; | ||
620 | seq[1] = tkey->tx_iv16 >> 8; | ||
621 | seq[2] = tkey->tx_iv32; | ||
622 | seq[3] = tkey->tx_iv32 >> 8; | ||
623 | seq[4] = tkey->tx_iv32 >> 16; | ||
624 | seq[5] = tkey->tx_iv32 >> 24; | ||
625 | } | ||
626 | |||
627 | return TKIP_KEY_LEN; | ||
628 | } | ||
629 | |||
630 | static char *ieee80211_tkip_print_stats(char *p, void *priv) | ||
631 | { | ||
632 | struct ieee80211_tkip_data *tkip = priv; | ||
633 | p += sprintf(p, "key[%d] alg=TKIP key_set=%d " | ||
634 | "tx_pn=%02x%02x%02x%02x%02x%02x " | ||
635 | "rx_pn=%02x%02x%02x%02x%02x%02x " | ||
636 | "replays=%d icv_errors=%d local_mic_failures=%d\n", | ||
637 | tkip->key_idx, tkip->key_set, | ||
638 | (tkip->tx_iv32 >> 24) & 0xff, | ||
639 | (tkip->tx_iv32 >> 16) & 0xff, | ||
640 | (tkip->tx_iv32 >> 8) & 0xff, | ||
641 | tkip->tx_iv32 & 0xff, | ||
642 | (tkip->tx_iv16 >> 8) & 0xff, | ||
643 | tkip->tx_iv16 & 0xff, | ||
644 | (tkip->rx_iv32 >> 24) & 0xff, | ||
645 | (tkip->rx_iv32 >> 16) & 0xff, | ||
646 | (tkip->rx_iv32 >> 8) & 0xff, | ||
647 | tkip->rx_iv32 & 0xff, | ||
648 | (tkip->rx_iv16 >> 8) & 0xff, | ||
649 | tkip->rx_iv16 & 0xff, | ||
650 | tkip->dot11RSNAStatsTKIPReplays, | ||
651 | tkip->dot11RSNAStatsTKIPICVErrors, | ||
652 | tkip->dot11RSNAStatsTKIPLocalMICFailures); | ||
653 | return p; | ||
654 | } | ||
655 | |||
656 | static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { | ||
657 | .name = "TKIP", | ||
658 | .init = ieee80211_tkip_init, | ||
659 | .deinit = ieee80211_tkip_deinit, | ||
660 | .encrypt_mpdu = ieee80211_tkip_encrypt, | ||
661 | .decrypt_mpdu = ieee80211_tkip_decrypt, | ||
662 | .encrypt_msdu = ieee80211_michael_mic_add, | ||
663 | .decrypt_msdu = ieee80211_michael_mic_verify, | ||
664 | .set_key = ieee80211_tkip_set_key, | ||
665 | .get_key = ieee80211_tkip_get_key, | ||
666 | .print_stats = ieee80211_tkip_print_stats, | ||
667 | .extra_prefix_len = 4 + 4, /* IV + ExtIV */ | ||
668 | .extra_postfix_len = 8 + 4, /* MIC + ICV */ | ||
669 | .owner = THIS_MODULE, | ||
670 | }; | ||
671 | |||
672 | static int __init ieee80211_crypto_tkip_init(void) | ||
673 | { | ||
674 | return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip); | ||
675 | } | ||
676 | |||
677 | static void __exit ieee80211_crypto_tkip_exit(void) | ||
678 | { | ||
679 | ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip); | ||
680 | } | ||
681 | |||
682 | module_init(ieee80211_crypto_tkip_init); | ||
683 | module_exit(ieee80211_crypto_tkip_exit); | ||
diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c new file mode 100644 index 000000000000..b4d2514a0902 --- /dev/null +++ b/net/ieee80211/ieee80211_crypt_wep.c | |||
@@ -0,0 +1,258 @@ | |||
1 | /* | ||
2 | * Host AP crypt: host-based WEP encryption implementation for Host AP driver | ||
3 | * | ||
4 | * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi> | ||
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 version 2 as | ||
8 | * published by the Free Software Foundation. See README and COPYING for | ||
9 | * more details. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/version.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/random.h> | ||
18 | #include <linux/skbuff.h> | ||
19 | #include <asm/string.h> | ||
20 | |||
21 | #include <net/ieee80211.h> | ||
22 | |||
23 | #include <linux/crypto.h> | ||
24 | #include <asm/scatterlist.h> | ||
25 | #include <linux/crc32.h> | ||
26 | |||
27 | MODULE_AUTHOR("Jouni Malinen"); | ||
28 | MODULE_DESCRIPTION("Host AP crypt: WEP"); | ||
29 | MODULE_LICENSE("GPL"); | ||
30 | |||
31 | struct prism2_wep_data { | ||
32 | u32 iv; | ||
33 | #define WEP_KEY_LEN 13 | ||
34 | u8 key[WEP_KEY_LEN + 1]; | ||
35 | u8 key_len; | ||
36 | u8 key_idx; | ||
37 | struct crypto_tfm *tfm; | ||
38 | }; | ||
39 | |||
40 | static void *prism2_wep_init(int keyidx) | ||
41 | { | ||
42 | struct prism2_wep_data *priv; | ||
43 | |||
44 | priv = kmalloc(sizeof(*priv), GFP_ATOMIC); | ||
45 | if (priv == NULL) | ||
46 | goto fail; | ||
47 | memset(priv, 0, sizeof(*priv)); | ||
48 | priv->key_idx = keyidx; | ||
49 | |||
50 | priv->tfm = crypto_alloc_tfm("arc4", 0); | ||
51 | if (priv->tfm == NULL) { | ||
52 | printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " | ||
53 | "crypto API arc4\n"); | ||
54 | goto fail; | ||
55 | } | ||
56 | |||
57 | /* start WEP IV from a random value */ | ||
58 | get_random_bytes(&priv->iv, 4); | ||
59 | |||
60 | return priv; | ||
61 | |||
62 | fail: | ||
63 | if (priv) { | ||
64 | if (priv->tfm) | ||
65 | crypto_free_tfm(priv->tfm); | ||
66 | kfree(priv); | ||
67 | } | ||
68 | return NULL; | ||
69 | } | ||
70 | |||
71 | static void prism2_wep_deinit(void *priv) | ||
72 | { | ||
73 | struct prism2_wep_data *_priv = priv; | ||
74 | if (_priv && _priv->tfm) | ||
75 | crypto_free_tfm(_priv->tfm); | ||
76 | kfree(priv); | ||
77 | } | ||
78 | |||
79 | /* Perform WEP encryption on given skb that has at least 4 bytes of headroom | ||
80 | * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, | ||
81 | * so the payload length increases with 8 bytes. | ||
82 | * | ||
83 | * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) | ||
84 | */ | ||
85 | static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | ||
86 | { | ||
87 | struct prism2_wep_data *wep = priv; | ||
88 | u32 crc, klen, len; | ||
89 | u8 key[WEP_KEY_LEN + 3]; | ||
90 | u8 *pos, *icv; | ||
91 | struct scatterlist sg; | ||
92 | |||
93 | if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || | ||
94 | skb->len < hdr_len) | ||
95 | return -1; | ||
96 | |||
97 | len = skb->len - hdr_len; | ||
98 | pos = skb_push(skb, 4); | ||
99 | memmove(pos, pos + 4, hdr_len); | ||
100 | pos += hdr_len; | ||
101 | |||
102 | klen = 3 + wep->key_len; | ||
103 | |||
104 | wep->iv++; | ||
105 | |||
106 | /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key | ||
107 | * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) | ||
108 | * can be used to speedup attacks, so avoid using them. */ | ||
109 | if ((wep->iv & 0xff00) == 0xff00) { | ||
110 | u8 B = (wep->iv >> 16) & 0xff; | ||
111 | if (B >= 3 && B < klen) | ||
112 | wep->iv += 0x0100; | ||
113 | } | ||
114 | |||
115 | /* Prepend 24-bit IV to RC4 key and TX frame */ | ||
116 | *pos++ = key[0] = (wep->iv >> 16) & 0xff; | ||
117 | *pos++ = key[1] = (wep->iv >> 8) & 0xff; | ||
118 | *pos++ = key[2] = wep->iv & 0xff; | ||
119 | *pos++ = wep->key_idx << 6; | ||
120 | |||
121 | /* Copy rest of the WEP key (the secret part) */ | ||
122 | memcpy(key + 3, wep->key, wep->key_len); | ||
123 | |||
124 | /* Append little-endian CRC32 and encrypt it to produce ICV */ | ||
125 | crc = ~crc32_le(~0, pos, len); | ||
126 | icv = skb_put(skb, 4); | ||
127 | icv[0] = crc; | ||
128 | icv[1] = crc >> 8; | ||
129 | icv[2] = crc >> 16; | ||
130 | icv[3] = crc >> 24; | ||
131 | |||
132 | crypto_cipher_setkey(wep->tfm, key, klen); | ||
133 | sg.page = virt_to_page(pos); | ||
134 | sg.offset = offset_in_page(pos); | ||
135 | sg.length = len + 4; | ||
136 | crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4); | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | /* Perform WEP decryption on given buffer. Buffer includes whole WEP part of | ||
142 | * the frame: IV (4 bytes), encrypted payload (including SNAP header), | ||
143 | * ICV (4 bytes). len includes both IV and ICV. | ||
144 | * | ||
145 | * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on | ||
146 | * failure. If frame is OK, IV and ICV will be removed. | ||
147 | */ | ||
148 | static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) | ||
149 | { | ||
150 | struct prism2_wep_data *wep = priv; | ||
151 | u32 crc, klen, plen; | ||
152 | u8 key[WEP_KEY_LEN + 3]; | ||
153 | u8 keyidx, *pos, icv[4]; | ||
154 | struct scatterlist sg; | ||
155 | |||
156 | if (skb->len < hdr_len + 8) | ||
157 | return -1; | ||
158 | |||
159 | pos = skb->data + hdr_len; | ||
160 | key[0] = *pos++; | ||
161 | key[1] = *pos++; | ||
162 | key[2] = *pos++; | ||
163 | keyidx = *pos++ >> 6; | ||
164 | if (keyidx != wep->key_idx) | ||
165 | return -1; | ||
166 | |||
167 | klen = 3 + wep->key_len; | ||
168 | |||
169 | /* Copy rest of the WEP key (the secret part) */ | ||
170 | memcpy(key + 3, wep->key, wep->key_len); | ||
171 | |||
172 | /* Apply RC4 to data and compute CRC32 over decrypted data */ | ||
173 | plen = skb->len - hdr_len - 8; | ||
174 | |||
175 | crypto_cipher_setkey(wep->tfm, key, klen); | ||
176 | sg.page = virt_to_page(pos); | ||
177 | sg.offset = offset_in_page(pos); | ||
178 | sg.length = plen + 4; | ||
179 | crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4); | ||
180 | |||
181 | crc = ~crc32_le(~0, pos, plen); | ||
182 | icv[0] = crc; | ||
183 | icv[1] = crc >> 8; | ||
184 | icv[2] = crc >> 16; | ||
185 | icv[3] = crc >> 24; | ||
186 | if (memcmp(icv, pos + plen, 4) != 0) { | ||
187 | /* ICV mismatch - drop frame */ | ||
188 | return -2; | ||
189 | } | ||
190 | |||
191 | /* Remove IV and ICV */ | ||
192 | memmove(skb->data + 4, skb->data, hdr_len); | ||
193 | skb_pull(skb, 4); | ||
194 | skb_trim(skb, skb->len - 4); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static int prism2_wep_set_key(void *key, int len, u8 * seq, void *priv) | ||
200 | { | ||
201 | struct prism2_wep_data *wep = priv; | ||
202 | |||
203 | if (len < 0 || len > WEP_KEY_LEN) | ||
204 | return -1; | ||
205 | |||
206 | memcpy(wep->key, key, len); | ||
207 | wep->key_len = len; | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static int prism2_wep_get_key(void *key, int len, u8 * seq, void *priv) | ||
213 | { | ||
214 | struct prism2_wep_data *wep = priv; | ||
215 | |||
216 | if (len < wep->key_len) | ||
217 | return -1; | ||
218 | |||
219 | memcpy(key, wep->key, wep->key_len); | ||
220 | |||
221 | return wep->key_len; | ||
222 | } | ||
223 | |||
224 | static char *prism2_wep_print_stats(char *p, void *priv) | ||
225 | { | ||
226 | struct prism2_wep_data *wep = priv; | ||
227 | p += sprintf(p, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len); | ||
228 | return p; | ||
229 | } | ||
230 | |||
231 | static struct ieee80211_crypto_ops ieee80211_crypt_wep = { | ||
232 | .name = "WEP", | ||
233 | .init = prism2_wep_init, | ||
234 | .deinit = prism2_wep_deinit, | ||
235 | .encrypt_mpdu = prism2_wep_encrypt, | ||
236 | .decrypt_mpdu = prism2_wep_decrypt, | ||
237 | .encrypt_msdu = NULL, | ||
238 | .decrypt_msdu = NULL, | ||
239 | .set_key = prism2_wep_set_key, | ||
240 | .get_key = prism2_wep_get_key, | ||
241 | .print_stats = prism2_wep_print_stats, | ||
242 | .extra_prefix_len = 4, /* IV */ | ||
243 | .extra_postfix_len = 4, /* ICV */ | ||
244 | .owner = THIS_MODULE, | ||
245 | }; | ||
246 | |||
247 | static int __init ieee80211_crypto_wep_init(void) | ||
248 | { | ||
249 | return ieee80211_register_crypto_ops(&ieee80211_crypt_wep); | ||
250 | } | ||
251 | |||
252 | static void __exit ieee80211_crypto_wep_exit(void) | ||
253 | { | ||
254 | ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep); | ||
255 | } | ||
256 | |||
257 | module_init(ieee80211_crypto_wep_init); | ||
258 | module_exit(ieee80211_crypto_wep_exit); | ||
diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c new file mode 100644 index 000000000000..03a47343ddc7 --- /dev/null +++ b/net/ieee80211/ieee80211_module.c | |||
@@ -0,0 +1,297 @@ | |||
1 | /******************************************************************************* | ||
2 | |||
3 | Copyright(c) 2004 Intel Corporation. All rights reserved. | ||
4 | |||
5 | Portions of this file are based on the WEP enablement code provided by the | ||
6 | Host AP project hostap-drivers v0.1.3 | ||
7 | Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | ||
8 | <jkmaline@cc.hut.fi> | ||
9 | Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> | ||
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 along with | ||
21 | this program; if not, write to the Free Software Foundation, Inc., 59 | ||
22 | Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
23 | |||
24 | The full GNU General Public License is included in this distribution in the | ||
25 | file called LICENSE. | ||
26 | |||
27 | Contact Information: | ||
28 | James P. Ketrenos <ipw2100-admin@linux.intel.com> | ||
29 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | |||
31 | *******************************************************************************/ | ||
32 | |||
33 | #include <linux/compiler.h> | ||
34 | #include <linux/config.h> | ||
35 | #include <linux/errno.h> | ||
36 | #include <linux/if_arp.h> | ||
37 | #include <linux/in6.h> | ||
38 | #include <linux/in.h> | ||
39 | #include <linux/ip.h> | ||
40 | #include <linux/kernel.h> | ||
41 | #include <linux/module.h> | ||
42 | #include <linux/netdevice.h> | ||
43 | #include <linux/proc_fs.h> | ||
44 | #include <linux/skbuff.h> | ||
45 | #include <linux/slab.h> | ||
46 | #include <linux/tcp.h> | ||
47 | #include <linux/types.h> | ||
48 | #include <linux/version.h> | ||
49 | #include <linux/wireless.h> | ||
50 | #include <linux/etherdevice.h> | ||
51 | #include <asm/uaccess.h> | ||
52 | #include <net/arp.h> | ||
53 | |||
54 | #include <net/ieee80211.h> | ||
55 | |||
56 | MODULE_DESCRIPTION("802.11 data/management/control stack"); | ||
57 | MODULE_AUTHOR | ||
58 | ("Copyright (C) 2004 Intel Corporation <jketreno@linux.intel.com>"); | ||
59 | MODULE_LICENSE("GPL"); | ||
60 | |||
61 | #define DRV_NAME "ieee80211" | ||
62 | |||
63 | static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee) | ||
64 | { | ||
65 | if (ieee->networks) | ||
66 | return 0; | ||
67 | |||
68 | ieee->networks = | ||
69 | kmalloc(MAX_NETWORK_COUNT * sizeof(struct ieee80211_network), | ||
70 | GFP_KERNEL); | ||
71 | if (!ieee->networks) { | ||
72 | printk(KERN_WARNING "%s: Out of memory allocating beacons\n", | ||
73 | ieee->dev->name); | ||
74 | return -ENOMEM; | ||
75 | } | ||
76 | |||
77 | memset(ieee->networks, 0, | ||
78 | MAX_NETWORK_COUNT * sizeof(struct ieee80211_network)); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static inline void ieee80211_networks_free(struct ieee80211_device *ieee) | ||
84 | { | ||
85 | if (!ieee->networks) | ||
86 | return; | ||
87 | kfree(ieee->networks); | ||
88 | ieee->networks = NULL; | ||
89 | } | ||
90 | |||
91 | static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee) | ||
92 | { | ||
93 | int i; | ||
94 | |||
95 | INIT_LIST_HEAD(&ieee->network_free_list); | ||
96 | INIT_LIST_HEAD(&ieee->network_list); | ||
97 | for (i = 0; i < MAX_NETWORK_COUNT; i++) | ||
98 | list_add_tail(&ieee->networks[i].list, | ||
99 | &ieee->network_free_list); | ||
100 | } | ||
101 | |||
102 | struct net_device *alloc_ieee80211(int sizeof_priv) | ||
103 | { | ||
104 | struct ieee80211_device *ieee; | ||
105 | struct net_device *dev; | ||
106 | int err; | ||
107 | |||
108 | IEEE80211_DEBUG_INFO("Initializing...\n"); | ||
109 | |||
110 | dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv); | ||
111 | if (!dev) { | ||
112 | IEEE80211_ERROR("Unable to network device.\n"); | ||
113 | goto failed; | ||
114 | } | ||
115 | ieee = netdev_priv(dev); | ||
116 | dev->hard_start_xmit = ieee80211_xmit; | ||
117 | |||
118 | ieee->dev = dev; | ||
119 | |||
120 | err = ieee80211_networks_allocate(ieee); | ||
121 | if (err) { | ||
122 | IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", err); | ||
123 | goto failed; | ||
124 | } | ||
125 | ieee80211_networks_initialize(ieee); | ||
126 | |||
127 | /* Default fragmentation threshold is maximum payload size */ | ||
128 | ieee->fts = DEFAULT_FTS; | ||
129 | ieee->scan_age = DEFAULT_MAX_SCAN_AGE; | ||
130 | ieee->open_wep = 1; | ||
131 | |||
132 | /* Default to enabling full open WEP with host based encrypt/decrypt */ | ||
133 | ieee->host_encrypt = 1; | ||
134 | ieee->host_decrypt = 1; | ||
135 | ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ | ||
136 | |||
137 | INIT_LIST_HEAD(&ieee->crypt_deinit_list); | ||
138 | init_timer(&ieee->crypt_deinit_timer); | ||
139 | ieee->crypt_deinit_timer.data = (unsigned long)ieee; | ||
140 | ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler; | ||
141 | |||
142 | spin_lock_init(&ieee->lock); | ||
143 | |||
144 | ieee->wpa_enabled = 0; | ||
145 | ieee->tkip_countermeasures = 0; | ||
146 | ieee->drop_unencrypted = 0; | ||
147 | ieee->privacy_invoked = 0; | ||
148 | ieee->ieee802_1x = 1; | ||
149 | |||
150 | return dev; | ||
151 | |||
152 | failed: | ||
153 | if (dev) | ||
154 | free_netdev(dev); | ||
155 | return NULL; | ||
156 | } | ||
157 | |||
158 | void free_ieee80211(struct net_device *dev) | ||
159 | { | ||
160 | struct ieee80211_device *ieee = netdev_priv(dev); | ||
161 | |||
162 | int i; | ||
163 | |||
164 | del_timer_sync(&ieee->crypt_deinit_timer); | ||
165 | ieee80211_crypt_deinit_entries(ieee, 1); | ||
166 | |||
167 | for (i = 0; i < WEP_KEYS; i++) { | ||
168 | struct ieee80211_crypt_data *crypt = ieee->crypt[i]; | ||
169 | if (crypt) { | ||
170 | if (crypt->ops) { | ||
171 | crypt->ops->deinit(crypt->priv); | ||
172 | module_put(crypt->ops->owner); | ||
173 | } | ||
174 | kfree(crypt); | ||
175 | ieee->crypt[i] = NULL; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | ieee80211_networks_free(ieee); | ||
180 | free_netdev(dev); | ||
181 | } | ||
182 | |||
183 | #ifdef CONFIG_IEEE80211_DEBUG | ||
184 | |||
185 | static int debug = 0; | ||
186 | u32 ieee80211_debug_level = 0; | ||
187 | struct proc_dir_entry *ieee80211_proc = NULL; | ||
188 | |||
189 | static int show_debug_level(char *page, char **start, off_t offset, | ||
190 | int count, int *eof, void *data) | ||
191 | { | ||
192 | return snprintf(page, count, "0x%08X\n", ieee80211_debug_level); | ||
193 | } | ||
194 | |||
195 | static int store_debug_level(struct file *file, const char __user * buffer, | ||
196 | unsigned long count, void *data) | ||
197 | { | ||
198 | char buf[] = "0x00000000"; | ||
199 | char *p = (char *)buf; | ||
200 | unsigned long val; | ||
201 | |||
202 | if (count > sizeof(buf) - 1) | ||
203 | count = sizeof(buf) - 1; | ||
204 | |||
205 | if (copy_from_user(buf, buffer, count)) | ||
206 | return count; | ||
207 | buf[count] = 0; | ||
208 | /* | ||
209 | * what a FPOS... What, sscanf(buf, "%i", &val) would be too | ||
210 | * scary? | ||
211 | */ | ||
212 | if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { | ||
213 | p++; | ||
214 | if (p[0] == 'x' || p[0] == 'X') | ||
215 | p++; | ||
216 | val = simple_strtoul(p, &p, 16); | ||
217 | } else | ||
218 | val = simple_strtoul(p, &p, 10); | ||
219 | if (p == buf) | ||
220 | printk(KERN_INFO DRV_NAME | ||
221 | ": %s is not in hex or decimal form.\n", buf); | ||
222 | else | ||
223 | ieee80211_debug_level = val; | ||
224 | |||
225 | return strlen(buf); | ||
226 | } | ||
227 | |||
228 | static int __init ieee80211_init(void) | ||
229 | { | ||
230 | struct proc_dir_entry *e; | ||
231 | |||
232 | ieee80211_debug_level = debug; | ||
233 | ieee80211_proc = create_proc_entry(DRV_NAME, S_IFDIR, proc_net); | ||
234 | if (ieee80211_proc == NULL) { | ||
235 | IEEE80211_ERROR("Unable to create " DRV_NAME | ||
236 | " proc directory\n"); | ||
237 | return -EIO; | ||
238 | } | ||
239 | e = create_proc_entry("debug_level", S_IFREG | S_IRUGO | S_IWUSR, | ||
240 | ieee80211_proc); | ||
241 | if (!e) { | ||
242 | remove_proc_entry(DRV_NAME, proc_net); | ||
243 | ieee80211_proc = NULL; | ||
244 | return -EIO; | ||
245 | } | ||
246 | e->read_proc = show_debug_level; | ||
247 | e->write_proc = store_debug_level; | ||
248 | e->data = NULL; | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static void __exit ieee80211_exit(void) | ||
254 | { | ||
255 | if (ieee80211_proc) { | ||
256 | remove_proc_entry("debug_level", ieee80211_proc); | ||
257 | remove_proc_entry(DRV_NAME, proc_net); | ||
258 | ieee80211_proc = NULL; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | #include <linux/moduleparam.h> | ||
263 | module_param(debug, int, 0444); | ||
264 | MODULE_PARM_DESC(debug, "debug output mask"); | ||
265 | |||
266 | module_exit(ieee80211_exit); | ||
267 | module_init(ieee80211_init); | ||
268 | #endif | ||
269 | |||
270 | const char *escape_essid(const char *essid, u8 essid_len) | ||
271 | { | ||
272 | static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; | ||
273 | const char *s = essid; | ||
274 | char *d = escaped; | ||
275 | |||
276 | if (ieee80211_is_empty_essid(essid, essid_len)) { | ||
277 | memcpy(escaped, "<hidden>", sizeof("<hidden>")); | ||
278 | return escaped; | ||
279 | } | ||
280 | |||
281 | essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); | ||
282 | while (essid_len--) { | ||
283 | if (*s == '\0') { | ||
284 | *d++ = '\\'; | ||
285 | *d++ = '0'; | ||
286 | s++; | ||
287 | } else { | ||
288 | *d++ = *s++; | ||
289 | } | ||
290 | } | ||
291 | *d = '\0'; | ||
292 | return escaped; | ||
293 | } | ||
294 | |||
295 | EXPORT_SYMBOL(alloc_ieee80211); | ||
296 | EXPORT_SYMBOL(free_ieee80211); | ||
297 | EXPORT_SYMBOL(escape_essid); | ||
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c new file mode 100644 index 000000000000..f7dcd854139e --- /dev/null +++ b/net/ieee80211/ieee80211_rx.c | |||
@@ -0,0 +1,1193 @@ | |||
1 | /* | ||
2 | * Original code based Host AP (software wireless LAN access point) driver | ||
3 | * for Intersil Prism2/2.5/3 - hostap.o module, common routines | ||
4 | * | ||
5 | * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | ||
6 | * <jkmaline@cc.hut.fi> | ||
7 | * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> | ||
8 | * Copyright (c) 2004, Intel Corporation | ||
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 version 2 as | ||
12 | * published by the Free Software Foundation. See README and COPYING for | ||
13 | * more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/compiler.h> | ||
17 | #include <linux/config.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/if_arp.h> | ||
20 | #include <linux/in6.h> | ||
21 | #include <linux/in.h> | ||
22 | #include <linux/ip.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/proc_fs.h> | ||
27 | #include <linux/skbuff.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/tcp.h> | ||
30 | #include <linux/types.h> | ||
31 | #include <linux/version.h> | ||
32 | #include <linux/wireless.h> | ||
33 | #include <linux/etherdevice.h> | ||
34 | #include <asm/uaccess.h> | ||
35 | #include <linux/ctype.h> | ||
36 | |||
37 | #include <net/ieee80211.h> | ||
38 | |||
39 | static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee, | ||
40 | struct sk_buff *skb, | ||
41 | struct ieee80211_rx_stats *rx_stats) | ||
42 | { | ||
43 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
44 | u16 fc = le16_to_cpu(hdr->frame_ctl); | ||
45 | |||
46 | skb->dev = ieee->dev; | ||
47 | skb->mac.raw = skb->data; | ||
48 | skb_pull(skb, ieee80211_get_hdrlen(fc)); | ||
49 | skb->pkt_type = PACKET_OTHERHOST; | ||
50 | skb->protocol = __constant_htons(ETH_P_80211_RAW); | ||
51 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
52 | netif_rx(skb); | ||
53 | } | ||
54 | |||
55 | /* Called only as a tasklet (software IRQ) */ | ||
56 | static struct ieee80211_frag_entry *ieee80211_frag_cache_find(struct | ||
57 | ieee80211_device | ||
58 | *ieee, | ||
59 | unsigned int seq, | ||
60 | unsigned int frag, | ||
61 | u8 * src, | ||
62 | u8 * dst) | ||
63 | { | ||
64 | struct ieee80211_frag_entry *entry; | ||
65 | int i; | ||
66 | |||
67 | for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) { | ||
68 | entry = &ieee->frag_cache[i]; | ||
69 | if (entry->skb != NULL && | ||
70 | time_after(jiffies, entry->first_frag_time + 2 * HZ)) { | ||
71 | IEEE80211_DEBUG_FRAG("expiring fragment cache entry " | ||
72 | "seq=%u last_frag=%u\n", | ||
73 | entry->seq, entry->last_frag); | ||
74 | dev_kfree_skb_any(entry->skb); | ||
75 | entry->skb = NULL; | ||
76 | } | ||
77 | |||
78 | if (entry->skb != NULL && entry->seq == seq && | ||
79 | (entry->last_frag + 1 == frag || frag == -1) && | ||
80 | memcmp(entry->src_addr, src, ETH_ALEN) == 0 && | ||
81 | memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) | ||
82 | return entry; | ||
83 | } | ||
84 | |||
85 | return NULL; | ||
86 | } | ||
87 | |||
88 | /* Called only as a tasklet (software IRQ) */ | ||
89 | static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, | ||
90 | struct ieee80211_hdr *hdr) | ||
91 | { | ||
92 | struct sk_buff *skb = NULL; | ||
93 | u16 sc; | ||
94 | unsigned int frag, seq; | ||
95 | struct ieee80211_frag_entry *entry; | ||
96 | |||
97 | sc = le16_to_cpu(hdr->seq_ctl); | ||
98 | frag = WLAN_GET_SEQ_FRAG(sc); | ||
99 | seq = WLAN_GET_SEQ_SEQ(sc); | ||
100 | |||
101 | if (frag == 0) { | ||
102 | /* Reserve enough space to fit maximum frame length */ | ||
103 | skb = dev_alloc_skb(ieee->dev->mtu + | ||
104 | sizeof(struct ieee80211_hdr) + | ||
105 | 8 /* LLC */ + | ||
106 | 2 /* alignment */ + | ||
107 | 8 /* WEP */ + ETH_ALEN /* WDS */ ); | ||
108 | if (skb == NULL) | ||
109 | return NULL; | ||
110 | |||
111 | entry = &ieee->frag_cache[ieee->frag_next_idx]; | ||
112 | ieee->frag_next_idx++; | ||
113 | if (ieee->frag_next_idx >= IEEE80211_FRAG_CACHE_LEN) | ||
114 | ieee->frag_next_idx = 0; | ||
115 | |||
116 | if (entry->skb != NULL) | ||
117 | dev_kfree_skb_any(entry->skb); | ||
118 | |||
119 | entry->first_frag_time = jiffies; | ||
120 | entry->seq = seq; | ||
121 | entry->last_frag = frag; | ||
122 | entry->skb = skb; | ||
123 | memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); | ||
124 | memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); | ||
125 | } else { | ||
126 | /* received a fragment of a frame for which the head fragment | ||
127 | * should have already been received */ | ||
128 | entry = ieee80211_frag_cache_find(ieee, seq, frag, hdr->addr2, | ||
129 | hdr->addr1); | ||
130 | if (entry != NULL) { | ||
131 | entry->last_frag = frag; | ||
132 | skb = entry->skb; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | return skb; | ||
137 | } | ||
138 | |||
139 | /* Called only as a tasklet (software IRQ) */ | ||
140 | static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee, | ||
141 | struct ieee80211_hdr *hdr) | ||
142 | { | ||
143 | u16 sc; | ||
144 | unsigned int seq; | ||
145 | struct ieee80211_frag_entry *entry; | ||
146 | |||
147 | sc = le16_to_cpu(hdr->seq_ctl); | ||
148 | seq = WLAN_GET_SEQ_SEQ(sc); | ||
149 | |||
150 | entry = ieee80211_frag_cache_find(ieee, seq, -1, hdr->addr2, | ||
151 | hdr->addr1); | ||
152 | |||
153 | if (entry == NULL) { | ||
154 | IEEE80211_DEBUG_FRAG("could not invalidate fragment cache " | ||
155 | "entry (seq=%u)\n", seq); | ||
156 | return -1; | ||
157 | } | ||
158 | |||
159 | entry->skb = NULL; | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | #ifdef NOT_YET | ||
164 | /* ieee80211_rx_frame_mgtmt | ||
165 | * | ||
166 | * Responsible for handling management control frames | ||
167 | * | ||
168 | * Called by ieee80211_rx */ | ||
169 | static inline int | ||
170 | ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, | ||
171 | struct ieee80211_rx_stats *rx_stats, u16 type, | ||
172 | u16 stype) | ||
173 | { | ||
174 | if (ieee->iw_mode == IW_MODE_MASTER) { | ||
175 | printk(KERN_DEBUG "%s: Master mode not yet suppported.\n", | ||
176 | ieee->dev->name); | ||
177 | return 0; | ||
178 | /* | ||
179 | hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr *) | ||
180 | skb->data);*/ | ||
181 | } | ||
182 | |||
183 | if (ieee->hostapd && type == WLAN_FC_TYPE_MGMT) { | ||
184 | if (stype == WLAN_FC_STYPE_BEACON && | ||
185 | ieee->iw_mode == IW_MODE_MASTER) { | ||
186 | struct sk_buff *skb2; | ||
187 | /* Process beacon frames also in kernel driver to | ||
188 | * update STA(AP) table statistics */ | ||
189 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
190 | if (skb2) | ||
191 | hostap_rx(skb2->dev, skb2, rx_stats); | ||
192 | } | ||
193 | |||
194 | /* send management frames to the user space daemon for | ||
195 | * processing */ | ||
196 | ieee->apdevstats.rx_packets++; | ||
197 | ieee->apdevstats.rx_bytes += skb->len; | ||
198 | prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT); | ||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | if (ieee->iw_mode == IW_MODE_MASTER) { | ||
203 | if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) { | ||
204 | printk(KERN_DEBUG "%s: unknown management frame " | ||
205 | "(type=0x%02x, stype=0x%02x) dropped\n", | ||
206 | skb->dev->name, type, stype); | ||
207 | return -1; | ||
208 | } | ||
209 | |||
210 | hostap_rx(skb->dev, skb, rx_stats); | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame " | ||
215 | "received in non-Host AP mode\n", skb->dev->name); | ||
216 | return -1; | ||
217 | } | ||
218 | #endif | ||
219 | |||
220 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | ||
221 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | ||
222 | static unsigned char rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | ||
223 | |||
224 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ | ||
225 | static unsigned char bridge_tunnel_header[] = | ||
226 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | ||
227 | /* No encapsulation header if EtherType < 0x600 (=length) */ | ||
228 | |||
229 | /* Called by ieee80211_rx_frame_decrypt */ | ||
230 | static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, | ||
231 | struct sk_buff *skb) | ||
232 | { | ||
233 | struct net_device *dev = ieee->dev; | ||
234 | u16 fc, ethertype; | ||
235 | struct ieee80211_hdr *hdr; | ||
236 | u8 *pos; | ||
237 | |||
238 | if (skb->len < 24) | ||
239 | return 0; | ||
240 | |||
241 | hdr = (struct ieee80211_hdr *)skb->data; | ||
242 | fc = le16_to_cpu(hdr->frame_ctl); | ||
243 | |||
244 | /* check that the frame is unicast frame to us */ | ||
245 | if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | ||
246 | IEEE80211_FCTL_TODS && | ||
247 | memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && | ||
248 | memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { | ||
249 | /* ToDS frame with own addr BSSID and DA */ | ||
250 | } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | ||
251 | IEEE80211_FCTL_FROMDS && | ||
252 | memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { | ||
253 | /* FromDS frame with own addr as DA */ | ||
254 | } else | ||
255 | return 0; | ||
256 | |||
257 | if (skb->len < 24 + 8) | ||
258 | return 0; | ||
259 | |||
260 | /* check for port access entity Ethernet type */ | ||
261 | pos = skb->data + 24; | ||
262 | ethertype = (pos[6] << 8) | pos[7]; | ||
263 | if (ethertype == ETH_P_PAE) | ||
264 | return 1; | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | /* Called only as a tasklet (software IRQ), by ieee80211_rx */ | ||
270 | static inline int | ||
271 | ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, | ||
272 | struct ieee80211_crypt_data *crypt) | ||
273 | { | ||
274 | struct ieee80211_hdr *hdr; | ||
275 | int res, hdrlen; | ||
276 | |||
277 | if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) | ||
278 | return 0; | ||
279 | |||
280 | hdr = (struct ieee80211_hdr *)skb->data; | ||
281 | hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); | ||
282 | |||
283 | #ifdef CONFIG_IEEE80211_CRYPT_TKIP | ||
284 | if (ieee->tkip_countermeasures && strcmp(crypt->ops->name, "TKIP") == 0) { | ||
285 | if (net_ratelimit()) { | ||
286 | printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " | ||
287 | "received packet from " MAC_FMT "\n", | ||
288 | ieee->dev->name, MAC_ARG(hdr->addr2)); | ||
289 | } | ||
290 | return -1; | ||
291 | } | ||
292 | #endif | ||
293 | |||
294 | atomic_inc(&crypt->refcnt); | ||
295 | res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); | ||
296 | atomic_dec(&crypt->refcnt); | ||
297 | if (res < 0) { | ||
298 | IEEE80211_DEBUG_DROP("decryption failed (SA=" MAC_FMT | ||
299 | ") res=%d\n", MAC_ARG(hdr->addr2), res); | ||
300 | if (res == -2) | ||
301 | IEEE80211_DEBUG_DROP("Decryption failed ICV " | ||
302 | "mismatch (key %d)\n", | ||
303 | skb->data[hdrlen + 3] >> 6); | ||
304 | ieee->ieee_stats.rx_discards_undecryptable++; | ||
305 | return -1; | ||
306 | } | ||
307 | |||
308 | return res; | ||
309 | } | ||
310 | |||
311 | /* Called only as a tasklet (software IRQ), by ieee80211_rx */ | ||
312 | static inline int | ||
313 | ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, | ||
314 | struct sk_buff *skb, int keyidx, | ||
315 | struct ieee80211_crypt_data *crypt) | ||
316 | { | ||
317 | struct ieee80211_hdr *hdr; | ||
318 | int res, hdrlen; | ||
319 | |||
320 | if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) | ||
321 | return 0; | ||
322 | |||
323 | hdr = (struct ieee80211_hdr *)skb->data; | ||
324 | hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); | ||
325 | |||
326 | atomic_inc(&crypt->refcnt); | ||
327 | res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); | ||
328 | atomic_dec(&crypt->refcnt); | ||
329 | if (res < 0) { | ||
330 | printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" | ||
331 | " (SA=" MAC_FMT " keyidx=%d)\n", | ||
332 | ieee->dev->name, MAC_ARG(hdr->addr2), keyidx); | ||
333 | return -1; | ||
334 | } | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | /* All received frames are sent to this function. @skb contains the frame in | ||
340 | * IEEE 802.11 format, i.e., in the format it was sent over air. | ||
341 | * This function is called only as a tasklet (software IRQ). */ | ||
342 | int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, | ||
343 | struct ieee80211_rx_stats *rx_stats) | ||
344 | { | ||
345 | struct net_device *dev = ieee->dev; | ||
346 | struct ieee80211_hdr *hdr; | ||
347 | size_t hdrlen; | ||
348 | u16 fc, type, stype, sc; | ||
349 | struct net_device_stats *stats; | ||
350 | unsigned int frag; | ||
351 | u8 *payload; | ||
352 | u16 ethertype; | ||
353 | #ifdef NOT_YET | ||
354 | struct net_device *wds = NULL; | ||
355 | struct sk_buff *skb2 = NULL; | ||
356 | struct net_device *wds = NULL; | ||
357 | int frame_authorized = 0; | ||
358 | int from_assoc_ap = 0; | ||
359 | void *sta = NULL; | ||
360 | #endif | ||
361 | u8 dst[ETH_ALEN]; | ||
362 | u8 src[ETH_ALEN]; | ||
363 | struct ieee80211_crypt_data *crypt = NULL; | ||
364 | int keyidx = 0; | ||
365 | |||
366 | hdr = (struct ieee80211_hdr *)skb->data; | ||
367 | stats = &ieee->stats; | ||
368 | |||
369 | if (skb->len < 10) { | ||
370 | printk(KERN_INFO "%s: SKB length < 10\n", dev->name); | ||
371 | goto rx_dropped; | ||
372 | } | ||
373 | |||
374 | fc = le16_to_cpu(hdr->frame_ctl); | ||
375 | type = WLAN_FC_GET_TYPE(fc); | ||
376 | stype = WLAN_FC_GET_STYPE(fc); | ||
377 | sc = le16_to_cpu(hdr->seq_ctl); | ||
378 | frag = WLAN_GET_SEQ_FRAG(sc); | ||
379 | hdrlen = ieee80211_get_hdrlen(fc); | ||
380 | |||
381 | #ifdef NOT_YET | ||
382 | #if WIRELESS_EXT > 15 | ||
383 | /* Put this code here so that we avoid duplicating it in all | ||
384 | * Rx paths. - Jean II */ | ||
385 | #ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ | ||
386 | /* If spy monitoring on */ | ||
387 | if (iface->spy_data.spy_number > 0) { | ||
388 | struct iw_quality wstats; | ||
389 | wstats.level = rx_stats->signal; | ||
390 | wstats.noise = rx_stats->noise; | ||
391 | wstats.updated = 6; /* No qual value */ | ||
392 | /* Update spy records */ | ||
393 | wireless_spy_update(dev, hdr->addr2, &wstats); | ||
394 | } | ||
395 | #endif /* IW_WIRELESS_SPY */ | ||
396 | #endif /* WIRELESS_EXT > 15 */ | ||
397 | hostap_update_rx_stats(local->ap, hdr, rx_stats); | ||
398 | #endif | ||
399 | |||
400 | #if WIRELESS_EXT > 15 | ||
401 | if (ieee->iw_mode == IW_MODE_MONITOR) { | ||
402 | ieee80211_monitor_rx(ieee, skb, rx_stats); | ||
403 | stats->rx_packets++; | ||
404 | stats->rx_bytes += skb->len; | ||
405 | return 1; | ||
406 | } | ||
407 | #endif | ||
408 | |||
409 | if (ieee->host_decrypt) { | ||
410 | int idx = 0; | ||
411 | if (skb->len >= hdrlen + 3) | ||
412 | idx = skb->data[hdrlen + 3] >> 6; | ||
413 | crypt = ieee->crypt[idx]; | ||
414 | #ifdef NOT_YET | ||
415 | sta = NULL; | ||
416 | |||
417 | /* Use station specific key to override default keys if the | ||
418 | * receiver address is a unicast address ("individual RA"). If | ||
419 | * bcrx_sta_key parameter is set, station specific key is used | ||
420 | * even with broad/multicast targets (this is against IEEE | ||
421 | * 802.11, but makes it easier to use different keys with | ||
422 | * stations that do not support WEP key mapping). */ | ||
423 | |||
424 | if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) | ||
425 | (void)hostap_handle_sta_crypto(local, hdr, &crypt, | ||
426 | &sta); | ||
427 | #endif | ||
428 | |||
429 | /* allow NULL decrypt to indicate an station specific override | ||
430 | * for default encryption */ | ||
431 | if (crypt && (crypt->ops == NULL || | ||
432 | crypt->ops->decrypt_mpdu == NULL)) | ||
433 | crypt = NULL; | ||
434 | |||
435 | if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) { | ||
436 | /* This seems to be triggered by some (multicast?) | ||
437 | * frames from other than current BSS, so just drop the | ||
438 | * frames silently instead of filling system log with | ||
439 | * these reports. */ | ||
440 | IEEE80211_DEBUG_DROP("Decryption failed (not set)" | ||
441 | " (SA=" MAC_FMT ")\n", | ||
442 | MAC_ARG(hdr->addr2)); | ||
443 | ieee->ieee_stats.rx_discards_undecryptable++; | ||
444 | goto rx_dropped; | ||
445 | } | ||
446 | } | ||
447 | #ifdef NOT_YET | ||
448 | if (type != WLAN_FC_TYPE_DATA) { | ||
449 | if (type == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_AUTH && | ||
450 | fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt && | ||
451 | (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) { | ||
452 | printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " | ||
453 | "from " MAC_FMT "\n", dev->name, | ||
454 | MAC_ARG(hdr->addr2)); | ||
455 | /* TODO: could inform hostapd about this so that it | ||
456 | * could send auth failure report */ | ||
457 | goto rx_dropped; | ||
458 | } | ||
459 | |||
460 | if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype)) | ||
461 | goto rx_dropped; | ||
462 | else | ||
463 | goto rx_exit; | ||
464 | } | ||
465 | #endif | ||
466 | |||
467 | /* Data frame - extract src/dst addresses */ | ||
468 | if (skb->len < IEEE80211_3ADDR_LEN) | ||
469 | goto rx_dropped; | ||
470 | |||
471 | switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { | ||
472 | case IEEE80211_FCTL_FROMDS: | ||
473 | memcpy(dst, hdr->addr1, ETH_ALEN); | ||
474 | memcpy(src, hdr->addr3, ETH_ALEN); | ||
475 | break; | ||
476 | case IEEE80211_FCTL_TODS: | ||
477 | memcpy(dst, hdr->addr3, ETH_ALEN); | ||
478 | memcpy(src, hdr->addr2, ETH_ALEN); | ||
479 | break; | ||
480 | case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: | ||
481 | if (skb->len < IEEE80211_4ADDR_LEN) | ||
482 | goto rx_dropped; | ||
483 | memcpy(dst, hdr->addr3, ETH_ALEN); | ||
484 | memcpy(src, hdr->addr4, ETH_ALEN); | ||
485 | break; | ||
486 | case 0: | ||
487 | memcpy(dst, hdr->addr1, ETH_ALEN); | ||
488 | memcpy(src, hdr->addr2, ETH_ALEN); | ||
489 | break; | ||
490 | } | ||
491 | |||
492 | #ifdef NOT_YET | ||
493 | if (hostap_rx_frame_wds(ieee, hdr, fc, &wds)) | ||
494 | goto rx_dropped; | ||
495 | if (wds) { | ||
496 | skb->dev = dev = wds; | ||
497 | stats = hostap_get_stats(dev); | ||
498 | } | ||
499 | |||
500 | if (ieee->iw_mode == IW_MODE_MASTER && !wds && | ||
501 | (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | ||
502 | IEEE80211_FCTL_FROMDS && ieee->stadev | ||
503 | && memcmp(hdr->addr2, ieee->assoc_ap_addr, ETH_ALEN) == 0) { | ||
504 | /* Frame from BSSID of the AP for which we are a client */ | ||
505 | skb->dev = dev = ieee->stadev; | ||
506 | stats = hostap_get_stats(dev); | ||
507 | from_assoc_ap = 1; | ||
508 | } | ||
509 | #endif | ||
510 | |||
511 | dev->last_rx = jiffies; | ||
512 | |||
513 | #ifdef NOT_YET | ||
514 | if ((ieee->iw_mode == IW_MODE_MASTER || | ||
515 | ieee->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) { | ||
516 | switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats, | ||
517 | wds != NULL)) { | ||
518 | case AP_RX_CONTINUE_NOT_AUTHORIZED: | ||
519 | frame_authorized = 0; | ||
520 | break; | ||
521 | case AP_RX_CONTINUE: | ||
522 | frame_authorized = 1; | ||
523 | break; | ||
524 | case AP_RX_DROP: | ||
525 | goto rx_dropped; | ||
526 | case AP_RX_EXIT: | ||
527 | goto rx_exit; | ||
528 | } | ||
529 | } | ||
530 | #endif | ||
531 | |||
532 | /* Nullfunc frames may have PS-bit set, so they must be passed to | ||
533 | * hostap_handle_sta_rx() before being dropped here. */ | ||
534 | if (stype != IEEE80211_STYPE_DATA && | ||
535 | stype != IEEE80211_STYPE_DATA_CFACK && | ||
536 | stype != IEEE80211_STYPE_DATA_CFPOLL && | ||
537 | stype != IEEE80211_STYPE_DATA_CFACKPOLL) { | ||
538 | if (stype != IEEE80211_STYPE_NULLFUNC) | ||
539 | IEEE80211_DEBUG_DROP("RX: dropped data frame " | ||
540 | "with no data (type=0x%02x, " | ||
541 | "subtype=0x%02x, len=%d)\n", | ||
542 | type, stype, skb->len); | ||
543 | goto rx_dropped; | ||
544 | } | ||
545 | |||
546 | /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ | ||
547 | |||
548 | if (ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && | ||
549 | (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0) | ||
550 | goto rx_dropped; | ||
551 | |||
552 | hdr = (struct ieee80211_hdr *)skb->data; | ||
553 | |||
554 | /* skb: hdr + (possibly fragmented) plaintext payload */ | ||
555 | // PR: FIXME: hostap has additional conditions in the "if" below: | ||
556 | // ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && | ||
557 | if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) { | ||
558 | int flen; | ||
559 | struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr); | ||
560 | IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag); | ||
561 | |||
562 | if (!frag_skb) { | ||
563 | IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG, | ||
564 | "Rx cannot get skb from fragment " | ||
565 | "cache (morefrag=%d seq=%u frag=%u)\n", | ||
566 | (fc & IEEE80211_FCTL_MOREFRAGS) != 0, | ||
567 | WLAN_GET_SEQ_SEQ(sc), frag); | ||
568 | goto rx_dropped; | ||
569 | } | ||
570 | |||
571 | flen = skb->len; | ||
572 | if (frag != 0) | ||
573 | flen -= hdrlen; | ||
574 | |||
575 | if (frag_skb->tail + flen > frag_skb->end) { | ||
576 | printk(KERN_WARNING "%s: host decrypted and " | ||
577 | "reassembled frame did not fit skb\n", | ||
578 | dev->name); | ||
579 | ieee80211_frag_cache_invalidate(ieee, hdr); | ||
580 | goto rx_dropped; | ||
581 | } | ||
582 | |||
583 | if (frag == 0) { | ||
584 | /* copy first fragment (including full headers) into | ||
585 | * beginning of the fragment cache skb */ | ||
586 | memcpy(skb_put(frag_skb, flen), skb->data, flen); | ||
587 | } else { | ||
588 | /* append frame payload to the end of the fragment | ||
589 | * cache skb */ | ||
590 | memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, | ||
591 | flen); | ||
592 | } | ||
593 | dev_kfree_skb_any(skb); | ||
594 | skb = NULL; | ||
595 | |||
596 | if (fc & IEEE80211_FCTL_MOREFRAGS) { | ||
597 | /* more fragments expected - leave the skb in fragment | ||
598 | * cache for now; it will be delivered to upper layers | ||
599 | * after all fragments have been received */ | ||
600 | goto rx_exit; | ||
601 | } | ||
602 | |||
603 | /* this was the last fragment and the frame will be | ||
604 | * delivered, so remove skb from fragment cache */ | ||
605 | skb = frag_skb; | ||
606 | hdr = (struct ieee80211_hdr *)skb->data; | ||
607 | ieee80211_frag_cache_invalidate(ieee, hdr); | ||
608 | } | ||
609 | |||
610 | /* skb: hdr + (possible reassembled) full MSDU payload; possibly still | ||
611 | * encrypted/authenticated */ | ||
612 | if (ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && | ||
613 | ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) | ||
614 | goto rx_dropped; | ||
615 | |||
616 | hdr = (struct ieee80211_hdr *)skb->data; | ||
617 | if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) { | ||
618 | if ( /*ieee->ieee802_1x && */ | ||
619 | ieee80211_is_eapol_frame(ieee, skb)) { | ||
620 | /* pass unencrypted EAPOL frames even if encryption is | ||
621 | * configured */ | ||
622 | } else { | ||
623 | IEEE80211_DEBUG_DROP("encryption configured, but RX " | ||
624 | "frame not encrypted (SA=" MAC_FMT | ||
625 | ")\n", MAC_ARG(hdr->addr2)); | ||
626 | goto rx_dropped; | ||
627 | } | ||
628 | } | ||
629 | |||
630 | if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep && | ||
631 | !ieee80211_is_eapol_frame(ieee, skb)) { | ||
632 | IEEE80211_DEBUG_DROP("dropped unencrypted RX data " | ||
633 | "frame from " MAC_FMT | ||
634 | " (drop_unencrypted=1)\n", | ||
635 | MAC_ARG(hdr->addr2)); | ||
636 | goto rx_dropped; | ||
637 | } | ||
638 | |||
639 | /* skb: hdr + (possible reassembled) full plaintext payload */ | ||
640 | |||
641 | payload = skb->data + hdrlen; | ||
642 | ethertype = (payload[6] << 8) | payload[7]; | ||
643 | |||
644 | #ifdef NOT_YET | ||
645 | /* If IEEE 802.1X is used, check whether the port is authorized to send | ||
646 | * the received frame. */ | ||
647 | if (ieee->ieee802_1x && ieee->iw_mode == IW_MODE_MASTER) { | ||
648 | if (ethertype == ETH_P_PAE) { | ||
649 | printk(KERN_DEBUG "%s: RX: IEEE 802.1X frame\n", | ||
650 | dev->name); | ||
651 | if (ieee->hostapd && ieee->apdev) { | ||
652 | /* Send IEEE 802.1X frames to the user | ||
653 | * space daemon for processing */ | ||
654 | prism2_rx_80211(ieee->apdev, skb, rx_stats, | ||
655 | PRISM2_RX_MGMT); | ||
656 | ieee->apdevstats.rx_packets++; | ||
657 | ieee->apdevstats.rx_bytes += skb->len; | ||
658 | goto rx_exit; | ||
659 | } | ||
660 | } else if (!frame_authorized) { | ||
661 | printk(KERN_DEBUG "%s: dropped frame from " | ||
662 | "unauthorized port (IEEE 802.1X): " | ||
663 | "ethertype=0x%04x\n", dev->name, ethertype); | ||
664 | goto rx_dropped; | ||
665 | } | ||
666 | } | ||
667 | #endif | ||
668 | |||
669 | /* convert hdr + possible LLC headers into Ethernet header */ | ||
670 | if (skb->len - hdrlen >= 8 && | ||
671 | ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 && | ||
672 | ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || | ||
673 | memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) { | ||
674 | /* remove RFC1042 or Bridge-Tunnel encapsulation and | ||
675 | * replace EtherType */ | ||
676 | skb_pull(skb, hdrlen + SNAP_SIZE); | ||
677 | memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); | ||
678 | memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); | ||
679 | } else { | ||
680 | u16 len; | ||
681 | /* Leave Ethernet header part of hdr and full payload */ | ||
682 | skb_pull(skb, hdrlen); | ||
683 | len = htons(skb->len); | ||
684 | memcpy(skb_push(skb, 2), &len, 2); | ||
685 | memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); | ||
686 | memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); | ||
687 | } | ||
688 | |||
689 | #ifdef NOT_YET | ||
690 | if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | ||
691 | IEEE80211_FCTL_TODS) && skb->len >= ETH_HLEN + ETH_ALEN) { | ||
692 | /* Non-standard frame: get addr4 from its bogus location after | ||
693 | * the payload */ | ||
694 | memcpy(skb->data + ETH_ALEN, | ||
695 | skb->data + skb->len - ETH_ALEN, ETH_ALEN); | ||
696 | skb_trim(skb, skb->len - ETH_ALEN); | ||
697 | } | ||
698 | #endif | ||
699 | |||
700 | stats->rx_packets++; | ||
701 | stats->rx_bytes += skb->len; | ||
702 | |||
703 | #ifdef NOT_YET | ||
704 | if (ieee->iw_mode == IW_MODE_MASTER && !wds && ieee->ap->bridge_packets) { | ||
705 | if (dst[0] & 0x01) { | ||
706 | /* copy multicast frame both to the higher layers and | ||
707 | * to the wireless media */ | ||
708 | ieee->ap->bridged_multicast++; | ||
709 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
710 | if (skb2 == NULL) | ||
711 | printk(KERN_DEBUG "%s: skb_clone failed for " | ||
712 | "multicast frame\n", dev->name); | ||
713 | } else if (hostap_is_sta_assoc(ieee->ap, dst)) { | ||
714 | /* send frame directly to the associated STA using | ||
715 | * wireless media and not passing to higher layers */ | ||
716 | ieee->ap->bridged_unicast++; | ||
717 | skb2 = skb; | ||
718 | skb = NULL; | ||
719 | } | ||
720 | } | ||
721 | |||
722 | if (skb2 != NULL) { | ||
723 | /* send to wireless media */ | ||
724 | skb2->protocol = __constant_htons(ETH_P_802_3); | ||
725 | skb2->mac.raw = skb2->nh.raw = skb2->data; | ||
726 | /* skb2->nh.raw = skb2->data + ETH_HLEN; */ | ||
727 | skb2->dev = dev; | ||
728 | dev_queue_xmit(skb2); | ||
729 | } | ||
730 | #endif | ||
731 | |||
732 | if (skb) { | ||
733 | skb->protocol = eth_type_trans(skb, dev); | ||
734 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
735 | skb->dev = dev; | ||
736 | skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */ | ||
737 | netif_rx(skb); | ||
738 | } | ||
739 | |||
740 | rx_exit: | ||
741 | #ifdef NOT_YET | ||
742 | if (sta) | ||
743 | hostap_handle_sta_release(sta); | ||
744 | #endif | ||
745 | return 1; | ||
746 | |||
747 | rx_dropped: | ||
748 | stats->rx_dropped++; | ||
749 | |||
750 | /* Returning 0 indicates to caller that we have not handled the SKB-- | ||
751 | * so it is still allocated and can be used again by underlying | ||
752 | * hardware as a DMA target */ | ||
753 | return 0; | ||
754 | } | ||
755 | |||
756 | #define MGMT_FRAME_FIXED_PART_LENGTH 0x24 | ||
757 | |||
758 | static inline int ieee80211_is_ofdm_rate(u8 rate) | ||
759 | { | ||
760 | switch (rate & ~IEEE80211_BASIC_RATE_MASK) { | ||
761 | case IEEE80211_OFDM_RATE_6MB: | ||
762 | case IEEE80211_OFDM_RATE_9MB: | ||
763 | case IEEE80211_OFDM_RATE_12MB: | ||
764 | case IEEE80211_OFDM_RATE_18MB: | ||
765 | case IEEE80211_OFDM_RATE_24MB: | ||
766 | case IEEE80211_OFDM_RATE_36MB: | ||
767 | case IEEE80211_OFDM_RATE_48MB: | ||
768 | case IEEE80211_OFDM_RATE_54MB: | ||
769 | return 1; | ||
770 | } | ||
771 | return 0; | ||
772 | } | ||
773 | |||
774 | static inline int ieee80211_network_init(struct ieee80211_device *ieee, | ||
775 | struct ieee80211_probe_response | ||
776 | *beacon, | ||
777 | struct ieee80211_network *network, | ||
778 | struct ieee80211_rx_stats *stats) | ||
779 | { | ||
780 | #ifdef CONFIG_IEEE80211_DEBUG | ||
781 | char rates_str[64]; | ||
782 | char *p; | ||
783 | #endif | ||
784 | struct ieee80211_info_element *info_element; | ||
785 | u16 left; | ||
786 | u8 i; | ||
787 | |||
788 | /* Pull out fixed field data */ | ||
789 | memcpy(network->bssid, beacon->header.addr3, ETH_ALEN); | ||
790 | network->capability = beacon->capability; | ||
791 | network->last_scanned = jiffies; | ||
792 | network->time_stamp[0] = beacon->time_stamp[0]; | ||
793 | network->time_stamp[1] = beacon->time_stamp[1]; | ||
794 | network->beacon_interval = beacon->beacon_interval; | ||
795 | /* Where to pull this? beacon->listen_interval; */ | ||
796 | network->listen_interval = 0x0A; | ||
797 | network->rates_len = network->rates_ex_len = 0; | ||
798 | network->last_associate = 0; | ||
799 | network->ssid_len = 0; | ||
800 | network->flags = 0; | ||
801 | network->atim_window = 0; | ||
802 | |||
803 | if (stats->freq == IEEE80211_52GHZ_BAND) { | ||
804 | /* for A band (No DS info) */ | ||
805 | network->channel = stats->received_channel; | ||
806 | } else | ||
807 | network->flags |= NETWORK_HAS_CCK; | ||
808 | |||
809 | network->wpa_ie_len = 0; | ||
810 | network->rsn_ie_len = 0; | ||
811 | |||
812 | info_element = &beacon->info_element; | ||
813 | left = stats->len - ((void *)info_element - (void *)beacon); | ||
814 | while (left >= sizeof(struct ieee80211_info_element_hdr)) { | ||
815 | if (sizeof(struct ieee80211_info_element_hdr) + | ||
816 | info_element->len > left) { | ||
817 | IEEE80211_DEBUG_SCAN | ||
818 | ("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%Zd left=%d.\n", | ||
819 | info_element->len + | ||
820 | sizeof(struct ieee80211_info_element), left); | ||
821 | return 1; | ||
822 | } | ||
823 | |||
824 | switch (info_element->id) { | ||
825 | case MFIE_TYPE_SSID: | ||
826 | if (ieee80211_is_empty_essid(info_element->data, | ||
827 | info_element->len)) { | ||
828 | network->flags |= NETWORK_EMPTY_ESSID; | ||
829 | break; | ||
830 | } | ||
831 | |||
832 | network->ssid_len = min(info_element->len, | ||
833 | (u8) IW_ESSID_MAX_SIZE); | ||
834 | memcpy(network->ssid, info_element->data, | ||
835 | network->ssid_len); | ||
836 | if (network->ssid_len < IW_ESSID_MAX_SIZE) | ||
837 | memset(network->ssid + network->ssid_len, 0, | ||
838 | IW_ESSID_MAX_SIZE - network->ssid_len); | ||
839 | |||
840 | IEEE80211_DEBUG_SCAN("MFIE_TYPE_SSID: '%s' len=%d.\n", | ||
841 | network->ssid, network->ssid_len); | ||
842 | break; | ||
843 | |||
844 | case MFIE_TYPE_RATES: | ||
845 | #ifdef CONFIG_IEEE80211_DEBUG | ||
846 | p = rates_str; | ||
847 | #endif | ||
848 | network->rates_len = | ||
849 | min(info_element->len, MAX_RATES_LENGTH); | ||
850 | for (i = 0; i < network->rates_len; i++) { | ||
851 | network->rates[i] = info_element->data[i]; | ||
852 | #ifdef CONFIG_IEEE80211_DEBUG | ||
853 | p += snprintf(p, | ||
854 | sizeof(rates_str) - (p - | ||
855 | rates_str), | ||
856 | "%02X ", network->rates[i]); | ||
857 | #endif | ||
858 | if (ieee80211_is_ofdm_rate | ||
859 | (info_element->data[i])) { | ||
860 | network->flags |= NETWORK_HAS_OFDM; | ||
861 | if (info_element->data[i] & | ||
862 | IEEE80211_BASIC_RATE_MASK) | ||
863 | network->flags &= | ||
864 | ~NETWORK_HAS_CCK; | ||
865 | } | ||
866 | } | ||
867 | |||
868 | IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES: '%s' (%d)\n", | ||
869 | rates_str, network->rates_len); | ||
870 | break; | ||
871 | |||
872 | case MFIE_TYPE_RATES_EX: | ||
873 | #ifdef CONFIG_IEEE80211_DEBUG | ||
874 | p = rates_str; | ||
875 | #endif | ||
876 | network->rates_ex_len = | ||
877 | min(info_element->len, MAX_RATES_EX_LENGTH); | ||
878 | for (i = 0; i < network->rates_ex_len; i++) { | ||
879 | network->rates_ex[i] = info_element->data[i]; | ||
880 | #ifdef CONFIG_IEEE80211_DEBUG | ||
881 | p += snprintf(p, | ||
882 | sizeof(rates_str) - (p - | ||
883 | rates_str), | ||
884 | "%02X ", network->rates[i]); | ||
885 | #endif | ||
886 | if (ieee80211_is_ofdm_rate | ||
887 | (info_element->data[i])) { | ||
888 | network->flags |= NETWORK_HAS_OFDM; | ||
889 | if (info_element->data[i] & | ||
890 | IEEE80211_BASIC_RATE_MASK) | ||
891 | network->flags &= | ||
892 | ~NETWORK_HAS_CCK; | ||
893 | } | ||
894 | } | ||
895 | |||
896 | IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES_EX: '%s' (%d)\n", | ||
897 | rates_str, network->rates_ex_len); | ||
898 | break; | ||
899 | |||
900 | case MFIE_TYPE_DS_SET: | ||
901 | IEEE80211_DEBUG_SCAN("MFIE_TYPE_DS_SET: %d\n", | ||
902 | info_element->data[0]); | ||
903 | if (stats->freq == IEEE80211_24GHZ_BAND) | ||
904 | network->channel = info_element->data[0]; | ||
905 | break; | ||
906 | |||
907 | case MFIE_TYPE_FH_SET: | ||
908 | IEEE80211_DEBUG_SCAN("MFIE_TYPE_FH_SET: ignored\n"); | ||
909 | break; | ||
910 | |||
911 | case MFIE_TYPE_CF_SET: | ||
912 | IEEE80211_DEBUG_SCAN("MFIE_TYPE_CF_SET: ignored\n"); | ||
913 | break; | ||
914 | |||
915 | case MFIE_TYPE_TIM: | ||
916 | IEEE80211_DEBUG_SCAN("MFIE_TYPE_TIM: ignored\n"); | ||
917 | break; | ||
918 | |||
919 | case MFIE_TYPE_IBSS_SET: | ||
920 | IEEE80211_DEBUG_SCAN("MFIE_TYPE_IBSS_SET: ignored\n"); | ||
921 | break; | ||
922 | |||
923 | case MFIE_TYPE_CHALLENGE: | ||
924 | IEEE80211_DEBUG_SCAN("MFIE_TYPE_CHALLENGE: ignored\n"); | ||
925 | break; | ||
926 | |||
927 | case MFIE_TYPE_GENERIC: | ||
928 | IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", | ||
929 | info_element->len); | ||
930 | if (info_element->len >= 4 && | ||
931 | info_element->data[0] == 0x00 && | ||
932 | info_element->data[1] == 0x50 && | ||
933 | info_element->data[2] == 0xf2 && | ||
934 | info_element->data[3] == 0x01) { | ||
935 | network->wpa_ie_len = min(info_element->len + 2, | ||
936 | MAX_WPA_IE_LEN); | ||
937 | memcpy(network->wpa_ie, info_element, | ||
938 | network->wpa_ie_len); | ||
939 | } | ||
940 | break; | ||
941 | |||
942 | case MFIE_TYPE_RSN: | ||
943 | IEEE80211_DEBUG_SCAN("MFIE_TYPE_RSN: %d bytes\n", | ||
944 | info_element->len); | ||
945 | network->rsn_ie_len = min(info_element->len + 2, | ||
946 | MAX_WPA_IE_LEN); | ||
947 | memcpy(network->rsn_ie, info_element, | ||
948 | network->rsn_ie_len); | ||
949 | break; | ||
950 | |||
951 | default: | ||
952 | IEEE80211_DEBUG_SCAN("unsupported IE %d\n", | ||
953 | info_element->id); | ||
954 | break; | ||
955 | } | ||
956 | |||
957 | left -= sizeof(struct ieee80211_info_element_hdr) + | ||
958 | info_element->len; | ||
959 | info_element = (struct ieee80211_info_element *) | ||
960 | &info_element->data[info_element->len]; | ||
961 | } | ||
962 | |||
963 | network->mode = 0; | ||
964 | if (stats->freq == IEEE80211_52GHZ_BAND) | ||
965 | network->mode = IEEE_A; | ||
966 | else { | ||
967 | if (network->flags & NETWORK_HAS_OFDM) | ||
968 | network->mode |= IEEE_G; | ||
969 | if (network->flags & NETWORK_HAS_CCK) | ||
970 | network->mode |= IEEE_B; | ||
971 | } | ||
972 | |||
973 | if (network->mode == 0) { | ||
974 | IEEE80211_DEBUG_SCAN("Filtered out '%s (" MAC_FMT ")' " | ||
975 | "network.\n", | ||
976 | escape_essid(network->ssid, | ||
977 | network->ssid_len), | ||
978 | MAC_ARG(network->bssid)); | ||
979 | return 1; | ||
980 | } | ||
981 | |||
982 | if (ieee80211_is_empty_essid(network->ssid, network->ssid_len)) | ||
983 | network->flags |= NETWORK_EMPTY_ESSID; | ||
984 | |||
985 | memcpy(&network->stats, stats, sizeof(network->stats)); | ||
986 | |||
987 | return 0; | ||
988 | } | ||
989 | |||
990 | static inline int is_same_network(struct ieee80211_network *src, | ||
991 | struct ieee80211_network *dst) | ||
992 | { | ||
993 | /* A network is only a duplicate if the channel, BSSID, and ESSID | ||
994 | * all match. We treat all <hidden> with the same BSSID and channel | ||
995 | * as one network */ | ||
996 | return ((src->ssid_len == dst->ssid_len) && | ||
997 | (src->channel == dst->channel) && | ||
998 | !memcmp(src->bssid, dst->bssid, ETH_ALEN) && | ||
999 | !memcmp(src->ssid, dst->ssid, src->ssid_len)); | ||
1000 | } | ||
1001 | |||
1002 | static inline void update_network(struct ieee80211_network *dst, | ||
1003 | struct ieee80211_network *src) | ||
1004 | { | ||
1005 | memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); | ||
1006 | dst->capability = src->capability; | ||
1007 | memcpy(dst->rates, src->rates, src->rates_len); | ||
1008 | dst->rates_len = src->rates_len; | ||
1009 | memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len); | ||
1010 | dst->rates_ex_len = src->rates_ex_len; | ||
1011 | |||
1012 | dst->mode = src->mode; | ||
1013 | dst->flags = src->flags; | ||
1014 | dst->time_stamp[0] = src->time_stamp[0]; | ||
1015 | dst->time_stamp[1] = src->time_stamp[1]; | ||
1016 | |||
1017 | dst->beacon_interval = src->beacon_interval; | ||
1018 | dst->listen_interval = src->listen_interval; | ||
1019 | dst->atim_window = src->atim_window; | ||
1020 | |||
1021 | memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len); | ||
1022 | dst->wpa_ie_len = src->wpa_ie_len; | ||
1023 | memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len); | ||
1024 | dst->rsn_ie_len = src->rsn_ie_len; | ||
1025 | |||
1026 | dst->last_scanned = jiffies; | ||
1027 | /* dst->last_associate is not overwritten */ | ||
1028 | } | ||
1029 | |||
1030 | static inline void ieee80211_process_probe_response(struct ieee80211_device | ||
1031 | *ieee, | ||
1032 | struct | ||
1033 | ieee80211_probe_response | ||
1034 | *beacon, | ||
1035 | struct ieee80211_rx_stats | ||
1036 | *stats) | ||
1037 | { | ||
1038 | struct ieee80211_network network; | ||
1039 | struct ieee80211_network *target; | ||
1040 | struct ieee80211_network *oldest = NULL; | ||
1041 | #ifdef CONFIG_IEEE80211_DEBUG | ||
1042 | struct ieee80211_info_element *info_element = &beacon->info_element; | ||
1043 | #endif | ||
1044 | unsigned long flags; | ||
1045 | |||
1046 | IEEE80211_DEBUG_SCAN("'%s' (" MAC_FMT | ||
1047 | "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", | ||
1048 | escape_essid(info_element->data, | ||
1049 | info_element->len), | ||
1050 | MAC_ARG(beacon->header.addr3), | ||
1051 | (beacon->capability & (1 << 0xf)) ? '1' : '0', | ||
1052 | (beacon->capability & (1 << 0xe)) ? '1' : '0', | ||
1053 | (beacon->capability & (1 << 0xd)) ? '1' : '0', | ||
1054 | (beacon->capability & (1 << 0xc)) ? '1' : '0', | ||
1055 | (beacon->capability & (1 << 0xb)) ? '1' : '0', | ||
1056 | (beacon->capability & (1 << 0xa)) ? '1' : '0', | ||
1057 | (beacon->capability & (1 << 0x9)) ? '1' : '0', | ||
1058 | (beacon->capability & (1 << 0x8)) ? '1' : '0', | ||
1059 | (beacon->capability & (1 << 0x7)) ? '1' : '0', | ||
1060 | (beacon->capability & (1 << 0x6)) ? '1' : '0', | ||
1061 | (beacon->capability & (1 << 0x5)) ? '1' : '0', | ||
1062 | (beacon->capability & (1 << 0x4)) ? '1' : '0', | ||
1063 | (beacon->capability & (1 << 0x3)) ? '1' : '0', | ||
1064 | (beacon->capability & (1 << 0x2)) ? '1' : '0', | ||
1065 | (beacon->capability & (1 << 0x1)) ? '1' : '0', | ||
1066 | (beacon->capability & (1 << 0x0)) ? '1' : '0'); | ||
1067 | |||
1068 | if (ieee80211_network_init(ieee, beacon, &network, stats)) { | ||
1069 | IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n", | ||
1070 | escape_essid(info_element->data, | ||
1071 | info_element->len), | ||
1072 | MAC_ARG(beacon->header.addr3), | ||
1073 | WLAN_FC_GET_STYPE(beacon->header. | ||
1074 | frame_ctl) == | ||
1075 | IEEE80211_STYPE_PROBE_RESP ? | ||
1076 | "PROBE RESPONSE" : "BEACON"); | ||
1077 | return; | ||
1078 | } | ||
1079 | |||
1080 | /* The network parsed correctly -- so now we scan our known networks | ||
1081 | * to see if we can find it in our list. | ||
1082 | * | ||
1083 | * NOTE: This search is definitely not optimized. Once its doing | ||
1084 | * the "right thing" we'll optimize it for efficiency if | ||
1085 | * necessary */ | ||
1086 | |||
1087 | /* Search for this entry in the list and update it if it is | ||
1088 | * already there. */ | ||
1089 | |||
1090 | spin_lock_irqsave(&ieee->lock, flags); | ||
1091 | |||
1092 | list_for_each_entry(target, &ieee->network_list, list) { | ||
1093 | if (is_same_network(target, &network)) | ||
1094 | break; | ||
1095 | |||
1096 | if ((oldest == NULL) || | ||
1097 | (target->last_scanned < oldest->last_scanned)) | ||
1098 | oldest = target; | ||
1099 | } | ||
1100 | |||
1101 | /* If we didn't find a match, then get a new network slot to initialize | ||
1102 | * with this beacon's information */ | ||
1103 | if (&target->list == &ieee->network_list) { | ||
1104 | if (list_empty(&ieee->network_free_list)) { | ||
1105 | /* If there are no more slots, expire the oldest */ | ||
1106 | list_del(&oldest->list); | ||
1107 | target = oldest; | ||
1108 | IEEE80211_DEBUG_SCAN("Expired '%s' (" MAC_FMT ") from " | ||
1109 | "network list.\n", | ||
1110 | escape_essid(target->ssid, | ||
1111 | target->ssid_len), | ||
1112 | MAC_ARG(target->bssid)); | ||
1113 | } else { | ||
1114 | /* Otherwise just pull from the free list */ | ||
1115 | target = list_entry(ieee->network_free_list.next, | ||
1116 | struct ieee80211_network, list); | ||
1117 | list_del(ieee->network_free_list.next); | ||
1118 | } | ||
1119 | |||
1120 | #ifdef CONFIG_IEEE80211_DEBUG | ||
1121 | IEEE80211_DEBUG_SCAN("Adding '%s' (" MAC_FMT ") via %s.\n", | ||
1122 | escape_essid(network.ssid, | ||
1123 | network.ssid_len), | ||
1124 | MAC_ARG(network.bssid), | ||
1125 | WLAN_FC_GET_STYPE(beacon->header. | ||
1126 | frame_ctl) == | ||
1127 | IEEE80211_STYPE_PROBE_RESP ? | ||
1128 | "PROBE RESPONSE" : "BEACON"); | ||
1129 | #endif | ||
1130 | memcpy(target, &network, sizeof(*target)); | ||
1131 | list_add_tail(&target->list, &ieee->network_list); | ||
1132 | } else { | ||
1133 | IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n", | ||
1134 | escape_essid(target->ssid, | ||
1135 | target->ssid_len), | ||
1136 | MAC_ARG(target->bssid), | ||
1137 | WLAN_FC_GET_STYPE(beacon->header. | ||
1138 | frame_ctl) == | ||
1139 | IEEE80211_STYPE_PROBE_RESP ? | ||
1140 | "PROBE RESPONSE" : "BEACON"); | ||
1141 | update_network(target, &network); | ||
1142 | } | ||
1143 | |||
1144 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
1145 | } | ||
1146 | |||
1147 | void ieee80211_rx_mgt(struct ieee80211_device *ieee, | ||
1148 | struct ieee80211_hdr *header, | ||
1149 | struct ieee80211_rx_stats *stats) | ||
1150 | { | ||
1151 | switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { | ||
1152 | case IEEE80211_STYPE_ASSOC_RESP: | ||
1153 | IEEE80211_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n", | ||
1154 | WLAN_FC_GET_STYPE(header->frame_ctl)); | ||
1155 | break; | ||
1156 | |||
1157 | case IEEE80211_STYPE_REASSOC_RESP: | ||
1158 | IEEE80211_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n", | ||
1159 | WLAN_FC_GET_STYPE(header->frame_ctl)); | ||
1160 | break; | ||
1161 | |||
1162 | case IEEE80211_STYPE_PROBE_RESP: | ||
1163 | IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", | ||
1164 | WLAN_FC_GET_STYPE(header->frame_ctl)); | ||
1165 | IEEE80211_DEBUG_SCAN("Probe response\n"); | ||
1166 | ieee80211_process_probe_response(ieee, | ||
1167 | (struct | ||
1168 | ieee80211_probe_response *) | ||
1169 | header, stats); | ||
1170 | break; | ||
1171 | |||
1172 | case IEEE80211_STYPE_BEACON: | ||
1173 | IEEE80211_DEBUG_MGMT("received BEACON (%d)\n", | ||
1174 | WLAN_FC_GET_STYPE(header->frame_ctl)); | ||
1175 | IEEE80211_DEBUG_SCAN("Beacon\n"); | ||
1176 | ieee80211_process_probe_response(ieee, | ||
1177 | (struct | ||
1178 | ieee80211_probe_response *) | ||
1179 | header, stats); | ||
1180 | break; | ||
1181 | |||
1182 | default: | ||
1183 | IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n", | ||
1184 | WLAN_FC_GET_STYPE(header->frame_ctl)); | ||
1185 | IEEE80211_WARNING("%s: Unknown management packet: %d\n", | ||
1186 | ieee->dev->name, | ||
1187 | WLAN_FC_GET_STYPE(header->frame_ctl)); | ||
1188 | break; | ||
1189 | } | ||
1190 | } | ||
1191 | |||
1192 | EXPORT_SYMBOL(ieee80211_rx_mgt); | ||
1193 | EXPORT_SYMBOL(ieee80211_rx); | ||
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c new file mode 100644 index 000000000000..c9aaff3fea1e --- /dev/null +++ b/net/ieee80211/ieee80211_tx.c | |||
@@ -0,0 +1,428 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify it | ||
6 | under the terms of version 2 of the GNU General Public License as | ||
7 | published by the Free Software Foundation. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along with | ||
15 | this program; if not, write to the Free Software Foundation, Inc., 59 | ||
16 | Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | |||
18 | The full GNU General Public License is included in this distribution in the | ||
19 | file called LICENSE. | ||
20 | |||
21 | Contact Information: | ||
22 | James P. Ketrenos <ipw2100-admin@linux.intel.com> | ||
23 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
24 | |||
25 | ******************************************************************************/ | ||
26 | #include <linux/compiler.h> | ||
27 | #include <linux/config.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/if_arp.h> | ||
30 | #include <linux/in6.h> | ||
31 | #include <linux/in.h> | ||
32 | #include <linux/ip.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/netdevice.h> | ||
36 | #include <linux/proc_fs.h> | ||
37 | #include <linux/skbuff.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/tcp.h> | ||
40 | #include <linux/types.h> | ||
41 | #include <linux/version.h> | ||
42 | #include <linux/wireless.h> | ||
43 | #include <linux/etherdevice.h> | ||
44 | #include <asm/uaccess.h> | ||
45 | |||
46 | #include <net/ieee80211.h> | ||
47 | |||
48 | /* | ||
49 | |||
50 | 802.11 Data Frame | ||
51 | |||
52 | ,-------------------------------------------------------------------. | ||
53 | Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | | ||
54 | |------|------|---------|---------|---------|------|---------|------| | ||
55 | Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs | | ||
56 | | | tion | (BSSID) | | | ence | data | | | ||
57 | `--------------------------------------------------| |------' | ||
58 | Total: 28 non-data bytes `----.----' | ||
59 | | | ||
60 | .- 'Frame data' expands to <---------------------------' | ||
61 | | | ||
62 | V | ||
63 | ,---------------------------------------------------. | ||
64 | Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 | | ||
65 | |------|------|---------|----------|------|---------| | ||
66 | Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP | | ||
67 | | DSAP | SSAP | | | | Packet | | ||
68 | | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | | | ||
69 | `-----------------------------------------| | | ||
70 | Total: 8 non-data bytes `----.----' | ||
71 | | | ||
72 | .- 'IP Packet' expands, if WEP enabled, to <--' | ||
73 | | | ||
74 | V | ||
75 | ,-----------------------. | ||
76 | Bytes | 4 | 0-2296 | 4 | | ||
77 | |-----|-----------|-----| | ||
78 | Desc. | IV | Encrypted | ICV | | ||
79 | | | IP Packet | | | ||
80 | `-----------------------' | ||
81 | Total: 8 non-data bytes | ||
82 | |||
83 | 802.3 Ethernet Data Frame | ||
84 | |||
85 | ,-----------------------------------------. | ||
86 | Bytes | 6 | 6 | 2 | Variable | 4 | | ||
87 | |-------|-------|------|-----------|------| | ||
88 | Desc. | Dest. | Source| Type | IP Packet | fcs | | ||
89 | | MAC | MAC | | | | | ||
90 | `-----------------------------------------' | ||
91 | Total: 18 non-data bytes | ||
92 | |||
93 | In the event that fragmentation is required, the incoming payload is split into | ||
94 | N parts of size ieee->fts. The first fragment contains the SNAP header and the | ||
95 | remaining packets are just data. | ||
96 | |||
97 | If encryption is enabled, each fragment payload size is reduced by enough space | ||
98 | to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP) | ||
99 | So if you have 1500 bytes of payload with ieee->fts set to 500 without | ||
100 | encryption it will take 3 frames. With WEP it will take 4 frames as the | ||
101 | payload of each frame is reduced to 492 bytes. | ||
102 | |||
103 | * SKB visualization | ||
104 | * | ||
105 | * ,- skb->data | ||
106 | * | | ||
107 | * | ETHERNET HEADER ,-<-- PAYLOAD | ||
108 | * | | 14 bytes from skb->data | ||
109 | * | 2 bytes for Type --> ,T. | (sizeof ethhdr) | ||
110 | * | | | | | ||
111 | * |,-Dest.--. ,--Src.---. | | | | ||
112 | * | 6 bytes| | 6 bytes | | | | | ||
113 | * v | | | | | | | ||
114 | * 0 | v 1 | v | v 2 | ||
115 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 | ||
116 | * ^ | ^ | ^ | | ||
117 | * | | | | | | | ||
118 | * | | | | `T' <---- 2 bytes for Type | ||
119 | * | | | | | ||
120 | * | | '---SNAP--' <-------- 6 bytes for SNAP | ||
121 | * | | | ||
122 | * `-IV--' <-------------------- 4 bytes for IV (WEP) | ||
123 | * | ||
124 | * SNAP HEADER | ||
125 | * | ||
126 | */ | ||
127 | |||
128 | static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; | ||
129 | static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; | ||
130 | |||
131 | static inline int ieee80211_put_snap(u8 * data, u16 h_proto) | ||
132 | { | ||
133 | struct ieee80211_snap_hdr *snap; | ||
134 | u8 *oui; | ||
135 | |||
136 | snap = (struct ieee80211_snap_hdr *)data; | ||
137 | snap->dsap = 0xaa; | ||
138 | snap->ssap = 0xaa; | ||
139 | snap->ctrl = 0x03; | ||
140 | |||
141 | if (h_proto == 0x8137 || h_proto == 0x80f3) | ||
142 | oui = P802_1H_OUI; | ||
143 | else | ||
144 | oui = RFC1042_OUI; | ||
145 | snap->oui[0] = oui[0]; | ||
146 | snap->oui[1] = oui[1]; | ||
147 | snap->oui[2] = oui[2]; | ||
148 | |||
149 | *(u16 *) (data + SNAP_SIZE) = htons(h_proto); | ||
150 | |||
151 | return SNAP_SIZE + sizeof(u16); | ||
152 | } | ||
153 | |||
154 | static inline int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, | ||
155 | struct sk_buff *frag, int hdr_len) | ||
156 | { | ||
157 | struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx]; | ||
158 | int res; | ||
159 | |||
160 | #ifdef CONFIG_IEEE80211_CRYPT_TKIP | ||
161 | struct ieee80211_hdr *header; | ||
162 | |||
163 | if (ieee->tkip_countermeasures && | ||
164 | crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { | ||
165 | header = (struct ieee80211_hdr *)frag->data; | ||
166 | if (net_ratelimit()) { | ||
167 | printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " | ||
168 | "TX packet to " MAC_FMT "\n", | ||
169 | ieee->dev->name, MAC_ARG(header->addr1)); | ||
170 | } | ||
171 | return -1; | ||
172 | } | ||
173 | #endif | ||
174 | /* To encrypt, frame format is: | ||
175 | * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */ | ||
176 | |||
177 | // PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU encryption. | ||
178 | /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so | ||
179 | * call both MSDU and MPDU encryption functions from here. */ | ||
180 | atomic_inc(&crypt->refcnt); | ||
181 | res = 0; | ||
182 | if (crypt->ops->encrypt_msdu) | ||
183 | res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv); | ||
184 | if (res == 0 && crypt->ops->encrypt_mpdu) | ||
185 | res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv); | ||
186 | |||
187 | atomic_dec(&crypt->refcnt); | ||
188 | if (res < 0) { | ||
189 | printk(KERN_INFO "%s: Encryption failed: len=%d.\n", | ||
190 | ieee->dev->name, frag->len); | ||
191 | ieee->ieee_stats.tx_discards++; | ||
192 | return -1; | ||
193 | } | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | void ieee80211_txb_free(struct ieee80211_txb *txb) | ||
199 | { | ||
200 | int i; | ||
201 | if (unlikely(!txb)) | ||
202 | return; | ||
203 | for (i = 0; i < txb->nr_frags; i++) | ||
204 | if (txb->fragments[i]) | ||
205 | dev_kfree_skb_any(txb->fragments[i]); | ||
206 | kfree(txb); | ||
207 | } | ||
208 | |||
209 | static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, | ||
210 | int gfp_mask) | ||
211 | { | ||
212 | struct ieee80211_txb *txb; | ||
213 | int i; | ||
214 | txb = kmalloc(sizeof(struct ieee80211_txb) + (sizeof(u8 *) * nr_frags), | ||
215 | gfp_mask); | ||
216 | if (!txb) | ||
217 | return NULL; | ||
218 | |||
219 | memset(txb, 0, sizeof(struct ieee80211_txb)); | ||
220 | txb->nr_frags = nr_frags; | ||
221 | txb->frag_size = txb_size; | ||
222 | |||
223 | for (i = 0; i < nr_frags; i++) { | ||
224 | txb->fragments[i] = dev_alloc_skb(txb_size); | ||
225 | if (unlikely(!txb->fragments[i])) { | ||
226 | i--; | ||
227 | break; | ||
228 | } | ||
229 | } | ||
230 | if (unlikely(i != nr_frags)) { | ||
231 | while (i >= 0) | ||
232 | dev_kfree_skb_any(txb->fragments[i--]); | ||
233 | kfree(txb); | ||
234 | return NULL; | ||
235 | } | ||
236 | return txb; | ||
237 | } | ||
238 | |||
239 | /* SKBs are added to the ieee->tx_queue. */ | ||
240 | int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | ||
241 | { | ||
242 | struct ieee80211_device *ieee = netdev_priv(dev); | ||
243 | struct ieee80211_txb *txb = NULL; | ||
244 | struct ieee80211_hdr *frag_hdr; | ||
245 | int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; | ||
246 | unsigned long flags; | ||
247 | struct net_device_stats *stats = &ieee->stats; | ||
248 | int ether_type, encrypt; | ||
249 | int bytes, fc, hdr_len; | ||
250 | struct sk_buff *skb_frag; | ||
251 | struct ieee80211_hdr header = { /* Ensure zero initialized */ | ||
252 | .duration_id = 0, | ||
253 | .seq_ctl = 0 | ||
254 | }; | ||
255 | u8 dest[ETH_ALEN], src[ETH_ALEN]; | ||
256 | |||
257 | struct ieee80211_crypt_data *crypt; | ||
258 | |||
259 | spin_lock_irqsave(&ieee->lock, flags); | ||
260 | |||
261 | /* If there is no driver handler to take the TXB, dont' bother | ||
262 | * creating it... */ | ||
263 | if (!ieee->hard_start_xmit) { | ||
264 | printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name); | ||
265 | goto success; | ||
266 | } | ||
267 | |||
268 | if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) { | ||
269 | printk(KERN_WARNING "%s: skb too small (%d).\n", | ||
270 | ieee->dev->name, skb->len); | ||
271 | goto success; | ||
272 | } | ||
273 | |||
274 | ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); | ||
275 | |||
276 | crypt = ieee->crypt[ieee->tx_keyidx]; | ||
277 | |||
278 | encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && | ||
279 | ieee->host_encrypt && crypt && crypt->ops; | ||
280 | |||
281 | if (!encrypt && ieee->ieee802_1x && | ||
282 | ieee->drop_unencrypted && ether_type != ETH_P_PAE) { | ||
283 | stats->tx_dropped++; | ||
284 | goto success; | ||
285 | } | ||
286 | |||
287 | /* Save source and destination addresses */ | ||
288 | memcpy(&dest, skb->data, ETH_ALEN); | ||
289 | memcpy(&src, skb->data + ETH_ALEN, ETH_ALEN); | ||
290 | |||
291 | /* Advance the SKB to the start of the payload */ | ||
292 | skb_pull(skb, sizeof(struct ethhdr)); | ||
293 | |||
294 | /* Determine total amount of storage required for TXB packets */ | ||
295 | bytes = skb->len + SNAP_SIZE + sizeof(u16); | ||
296 | |||
297 | if (encrypt) | ||
298 | fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | | ||
299 | IEEE80211_FCTL_PROTECTED; | ||
300 | else | ||
301 | fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; | ||
302 | |||
303 | if (ieee->iw_mode == IW_MODE_INFRA) { | ||
304 | fc |= IEEE80211_FCTL_TODS; | ||
305 | /* To DS: Addr1 = BSSID, Addr2 = SA, | ||
306 | Addr3 = DA */ | ||
307 | memcpy(&header.addr1, ieee->bssid, ETH_ALEN); | ||
308 | memcpy(&header.addr2, &src, ETH_ALEN); | ||
309 | memcpy(&header.addr3, &dest, ETH_ALEN); | ||
310 | } else if (ieee->iw_mode == IW_MODE_ADHOC) { | ||
311 | /* not From/To DS: Addr1 = DA, Addr2 = SA, | ||
312 | Addr3 = BSSID */ | ||
313 | memcpy(&header.addr1, dest, ETH_ALEN); | ||
314 | memcpy(&header.addr2, src, ETH_ALEN); | ||
315 | memcpy(&header.addr3, ieee->bssid, ETH_ALEN); | ||
316 | } | ||
317 | header.frame_ctl = cpu_to_le16(fc); | ||
318 | hdr_len = IEEE80211_3ADDR_LEN; | ||
319 | |||
320 | /* Determine fragmentation size based on destination (multicast | ||
321 | * and broadcast are not fragmented) */ | ||
322 | if (is_multicast_ether_addr(dest) || is_broadcast_ether_addr(dest)) | ||
323 | frag_size = MAX_FRAG_THRESHOLD; | ||
324 | else | ||
325 | frag_size = ieee->fts; | ||
326 | |||
327 | /* Determine amount of payload per fragment. Regardless of if | ||
328 | * this stack is providing the full 802.11 header, one will | ||
329 | * eventually be affixed to this fragment -- so we must account for | ||
330 | * it when determining the amount of payload space. */ | ||
331 | bytes_per_frag = frag_size - IEEE80211_3ADDR_LEN; | ||
332 | if (ieee->config & | ||
333 | (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) | ||
334 | bytes_per_frag -= IEEE80211_FCS_LEN; | ||
335 | |||
336 | /* Each fragment may need to have room for encryptiong pre/postfix */ | ||
337 | if (encrypt) | ||
338 | bytes_per_frag -= crypt->ops->extra_prefix_len + | ||
339 | crypt->ops->extra_postfix_len; | ||
340 | |||
341 | /* Number of fragments is the total bytes_per_frag / | ||
342 | * payload_per_fragment */ | ||
343 | nr_frags = bytes / bytes_per_frag; | ||
344 | bytes_last_frag = bytes % bytes_per_frag; | ||
345 | if (bytes_last_frag) | ||
346 | nr_frags++; | ||
347 | else | ||
348 | bytes_last_frag = bytes_per_frag; | ||
349 | |||
350 | /* When we allocate the TXB we allocate enough space for the reserve | ||
351 | * and full fragment bytes (bytes_per_frag doesn't include prefix, | ||
352 | * postfix, header, FCS, etc.) */ | ||
353 | txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC); | ||
354 | if (unlikely(!txb)) { | ||
355 | printk(KERN_WARNING "%s: Could not allocate TXB\n", | ||
356 | ieee->dev->name); | ||
357 | goto failed; | ||
358 | } | ||
359 | txb->encrypted = encrypt; | ||
360 | txb->payload_size = bytes; | ||
361 | |||
362 | for (i = 0; i < nr_frags; i++) { | ||
363 | skb_frag = txb->fragments[i]; | ||
364 | |||
365 | if (encrypt) | ||
366 | skb_reserve(skb_frag, crypt->ops->extra_prefix_len); | ||
367 | |||
368 | frag_hdr = (struct ieee80211_hdr *)skb_put(skb_frag, hdr_len); | ||
369 | memcpy(frag_hdr, &header, hdr_len); | ||
370 | |||
371 | /* If this is not the last fragment, then add the MOREFRAGS | ||
372 | * bit to the frame control */ | ||
373 | if (i != nr_frags - 1) { | ||
374 | frag_hdr->frame_ctl = | ||
375 | cpu_to_le16(fc | IEEE80211_FCTL_MOREFRAGS); | ||
376 | bytes = bytes_per_frag; | ||
377 | } else { | ||
378 | /* The last fragment takes the remaining length */ | ||
379 | bytes = bytes_last_frag; | ||
380 | } | ||
381 | |||
382 | /* Put a SNAP header on the first fragment */ | ||
383 | if (i == 0) { | ||
384 | ieee80211_put_snap(skb_put | ||
385 | (skb_frag, SNAP_SIZE + sizeof(u16)), | ||
386 | ether_type); | ||
387 | bytes -= SNAP_SIZE + sizeof(u16); | ||
388 | } | ||
389 | |||
390 | memcpy(skb_put(skb_frag, bytes), skb->data, bytes); | ||
391 | |||
392 | /* Advance the SKB... */ | ||
393 | skb_pull(skb, bytes); | ||
394 | |||
395 | /* Encryption routine will move the header forward in order | ||
396 | * to insert the IV between the header and the payload */ | ||
397 | if (encrypt) | ||
398 | ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); | ||
399 | if (ieee->config & | ||
400 | (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) | ||
401 | skb_put(skb_frag, 4); | ||
402 | } | ||
403 | |||
404 | success: | ||
405 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
406 | |||
407 | dev_kfree_skb_any(skb); | ||
408 | |||
409 | if (txb) { | ||
410 | if ((*ieee->hard_start_xmit) (txb, dev) == 0) { | ||
411 | stats->tx_packets++; | ||
412 | stats->tx_bytes += txb->payload_size; | ||
413 | return 0; | ||
414 | } | ||
415 | ieee80211_txb_free(txb); | ||
416 | } | ||
417 | |||
418 | return 0; | ||
419 | |||
420 | failed: | ||
421 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
422 | netif_stop_queue(dev); | ||
423 | stats->tx_errors++; | ||
424 | return 1; | ||
425 | |||
426 | } | ||
427 | |||
428 | EXPORT_SYMBOL(ieee80211_txb_free); | ||
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c new file mode 100644 index 000000000000..94882f39b072 --- /dev/null +++ b/net/ieee80211/ieee80211_wx.c | |||
@@ -0,0 +1,468 @@ | |||
1 | /****************************************************************************** | ||
2 | |||
3 | Copyright(c) 2004 Intel Corporation. All rights reserved. | ||
4 | |||
5 | Portions of this file are based on the WEP enablement code provided by the | ||
6 | Host AP project hostap-drivers v0.1.3 | ||
7 | Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | ||
8 | <jkmaline@cc.hut.fi> | ||
9 | Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> | ||
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 along with | ||
21 | this program; if not, write to the Free Software Foundation, Inc., 59 | ||
22 | Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
23 | |||
24 | The full GNU General Public License is included in this distribution in the | ||
25 | file called LICENSE. | ||
26 | |||
27 | Contact Information: | ||
28 | James P. Ketrenos <ipw2100-admin@linux.intel.com> | ||
29 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
30 | |||
31 | ******************************************************************************/ | ||
32 | |||
33 | #include <linux/kmod.h> | ||
34 | #include <linux/module.h> | ||
35 | |||
36 | #include <net/ieee80211.h> | ||
37 | #include <linux/wireless.h> | ||
38 | |||
39 | static const char *ieee80211_modes[] = { | ||
40 | "?", "a", "b", "ab", "g", "ag", "bg", "abg" | ||
41 | }; | ||
42 | |||
43 | #define MAX_CUSTOM_LEN 64 | ||
44 | static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee, | ||
45 | char *start, char *stop, | ||
46 | struct ieee80211_network *network) | ||
47 | { | ||
48 | char custom[MAX_CUSTOM_LEN]; | ||
49 | char *p; | ||
50 | struct iw_event iwe; | ||
51 | int i, j; | ||
52 | u8 max_rate, rate; | ||
53 | |||
54 | /* First entry *MUST* be the AP MAC address */ | ||
55 | iwe.cmd = SIOCGIWAP; | ||
56 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
57 | memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); | ||
58 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN); | ||
59 | |||
60 | /* Remaining entries will be displayed in the order we provide them */ | ||
61 | |||
62 | /* Add the ESSID */ | ||
63 | iwe.cmd = SIOCGIWESSID; | ||
64 | iwe.u.data.flags = 1; | ||
65 | if (network->flags & NETWORK_EMPTY_ESSID) { | ||
66 | iwe.u.data.length = sizeof("<hidden>"); | ||
67 | start = iwe_stream_add_point(start, stop, &iwe, "<hidden>"); | ||
68 | } else { | ||
69 | iwe.u.data.length = min(network->ssid_len, (u8) 32); | ||
70 | start = iwe_stream_add_point(start, stop, &iwe, network->ssid); | ||
71 | } | ||
72 | |||
73 | /* Add the protocol name */ | ||
74 | iwe.cmd = SIOCGIWNAME; | ||
75 | snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", | ||
76 | ieee80211_modes[network->mode]); | ||
77 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN); | ||
78 | |||
79 | /* Add mode */ | ||
80 | iwe.cmd = SIOCGIWMODE; | ||
81 | if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { | ||
82 | if (network->capability & WLAN_CAPABILITY_ESS) | ||
83 | iwe.u.mode = IW_MODE_MASTER; | ||
84 | else | ||
85 | iwe.u.mode = IW_MODE_ADHOC; | ||
86 | |||
87 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN); | ||
88 | } | ||
89 | |||
90 | /* Add frequency/channel */ | ||
91 | iwe.cmd = SIOCGIWFREQ; | ||
92 | /* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode); | ||
93 | iwe.u.freq.e = 3; */ | ||
94 | iwe.u.freq.m = network->channel; | ||
95 | iwe.u.freq.e = 0; | ||
96 | iwe.u.freq.i = 0; | ||
97 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN); | ||
98 | |||
99 | /* Add encryption capability */ | ||
100 | iwe.cmd = SIOCGIWENCODE; | ||
101 | if (network->capability & WLAN_CAPABILITY_PRIVACY) | ||
102 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
103 | else | ||
104 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
105 | iwe.u.data.length = 0; | ||
106 | start = iwe_stream_add_point(start, stop, &iwe, network->ssid); | ||
107 | |||
108 | /* Add basic and extended rates */ | ||
109 | max_rate = 0; | ||
110 | p = custom; | ||
111 | p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); | ||
112 | for (i = 0, j = 0; i < network->rates_len;) { | ||
113 | if (j < network->rates_ex_len && | ||
114 | ((network->rates_ex[j] & 0x7F) < | ||
115 | (network->rates[i] & 0x7F))) | ||
116 | rate = network->rates_ex[j++] & 0x7F; | ||
117 | else | ||
118 | rate = network->rates[i++] & 0x7F; | ||
119 | if (rate > max_rate) | ||
120 | max_rate = rate; | ||
121 | p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), | ||
122 | "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); | ||
123 | } | ||
124 | for (; j < network->rates_ex_len; j++) { | ||
125 | rate = network->rates_ex[j] & 0x7F; | ||
126 | p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), | ||
127 | "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); | ||
128 | if (rate > max_rate) | ||
129 | max_rate = rate; | ||
130 | } | ||
131 | |||
132 | iwe.cmd = SIOCGIWRATE; | ||
133 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | ||
134 | iwe.u.bitrate.value = max_rate * 500000; | ||
135 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_PARAM_LEN); | ||
136 | |||
137 | iwe.cmd = IWEVCUSTOM; | ||
138 | iwe.u.data.length = p - custom; | ||
139 | if (iwe.u.data.length) | ||
140 | start = iwe_stream_add_point(start, stop, &iwe, custom); | ||
141 | |||
142 | /* Add quality statistics */ | ||
143 | /* TODO: Fix these values... */ | ||
144 | iwe.cmd = IWEVQUAL; | ||
145 | iwe.u.qual.qual = network->stats.signal; | ||
146 | iwe.u.qual.level = network->stats.rssi; | ||
147 | iwe.u.qual.noise = network->stats.noise; | ||
148 | iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK; | ||
149 | if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) | ||
150 | iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; | ||
151 | if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) | ||
152 | iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; | ||
153 | if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) | ||
154 | iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID; | ||
155 | |||
156 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); | ||
157 | |||
158 | iwe.cmd = IWEVCUSTOM; | ||
159 | p = custom; | ||
160 | |||
161 | iwe.u.data.length = p - custom; | ||
162 | if (iwe.u.data.length) | ||
163 | start = iwe_stream_add_point(start, stop, &iwe, custom); | ||
164 | |||
165 | if (ieee->wpa_enabled && network->wpa_ie_len) { | ||
166 | char buf[MAX_WPA_IE_LEN * 2 + 30]; | ||
167 | |||
168 | u8 *p = buf; | ||
169 | p += sprintf(p, "wpa_ie="); | ||
170 | for (i = 0; i < network->wpa_ie_len; i++) { | ||
171 | p += sprintf(p, "%02x", network->wpa_ie[i]); | ||
172 | } | ||
173 | |||
174 | memset(&iwe, 0, sizeof(iwe)); | ||
175 | iwe.cmd = IWEVCUSTOM; | ||
176 | iwe.u.data.length = strlen(buf); | ||
177 | start = iwe_stream_add_point(start, stop, &iwe, buf); | ||
178 | } | ||
179 | |||
180 | if (ieee->wpa_enabled && network->rsn_ie_len) { | ||
181 | char buf[MAX_WPA_IE_LEN * 2 + 30]; | ||
182 | |||
183 | u8 *p = buf; | ||
184 | p += sprintf(p, "rsn_ie="); | ||
185 | for (i = 0; i < network->rsn_ie_len; i++) { | ||
186 | p += sprintf(p, "%02x", network->rsn_ie[i]); | ||
187 | } | ||
188 | |||
189 | memset(&iwe, 0, sizeof(iwe)); | ||
190 | iwe.cmd = IWEVCUSTOM; | ||
191 | iwe.u.data.length = strlen(buf); | ||
192 | start = iwe_stream_add_point(start, stop, &iwe, buf); | ||
193 | } | ||
194 | |||
195 | /* Add EXTRA: Age to display seconds since last beacon/probe response | ||
196 | * for given network. */ | ||
197 | iwe.cmd = IWEVCUSTOM; | ||
198 | p = custom; | ||
199 | p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), | ||
200 | " Last beacon: %lums ago", | ||
201 | (jiffies - network->last_scanned) / (HZ / 100)); | ||
202 | iwe.u.data.length = p - custom; | ||
203 | if (iwe.u.data.length) | ||
204 | start = iwe_stream_add_point(start, stop, &iwe, custom); | ||
205 | |||
206 | return start; | ||
207 | } | ||
208 | |||
209 | int ieee80211_wx_get_scan(struct ieee80211_device *ieee, | ||
210 | struct iw_request_info *info, | ||
211 | union iwreq_data *wrqu, char *extra) | ||
212 | { | ||
213 | struct ieee80211_network *network; | ||
214 | unsigned long flags; | ||
215 | |||
216 | char *ev = extra; | ||
217 | char *stop = ev + IW_SCAN_MAX_DATA; | ||
218 | int i = 0; | ||
219 | |||
220 | IEEE80211_DEBUG_WX("Getting scan\n"); | ||
221 | |||
222 | spin_lock_irqsave(&ieee->lock, flags); | ||
223 | |||
224 | list_for_each_entry(network, &ieee->network_list, list) { | ||
225 | i++; | ||
226 | if (ieee->scan_age == 0 || | ||
227 | time_after(network->last_scanned + ieee->scan_age, jiffies)) | ||
228 | ev = ipw2100_translate_scan(ieee, ev, stop, network); | ||
229 | else | ||
230 | IEEE80211_DEBUG_SCAN("Not showing network '%s (" | ||
231 | MAC_FMT ")' due to age (%lums).\n", | ||
232 | escape_essid(network->ssid, | ||
233 | network->ssid_len), | ||
234 | MAC_ARG(network->bssid), | ||
235 | (jiffies - | ||
236 | network->last_scanned) / (HZ / | ||
237 | 100)); | ||
238 | } | ||
239 | |||
240 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
241 | |||
242 | wrqu->data.length = ev - extra; | ||
243 | wrqu->data.flags = 0; | ||
244 | |||
245 | IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i); | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | int ieee80211_wx_set_encode(struct ieee80211_device *ieee, | ||
251 | struct iw_request_info *info, | ||
252 | union iwreq_data *wrqu, char *keybuf) | ||
253 | { | ||
254 | struct iw_point *erq = &(wrqu->encoding); | ||
255 | struct net_device *dev = ieee->dev; | ||
256 | struct ieee80211_security sec = { | ||
257 | .flags = 0 | ||
258 | }; | ||
259 | int i, key, key_provided, len; | ||
260 | struct ieee80211_crypt_data **crypt; | ||
261 | |||
262 | IEEE80211_DEBUG_WX("SET_ENCODE\n"); | ||
263 | |||
264 | key = erq->flags & IW_ENCODE_INDEX; | ||
265 | if (key) { | ||
266 | if (key > WEP_KEYS) | ||
267 | return -EINVAL; | ||
268 | key--; | ||
269 | key_provided = 1; | ||
270 | } else { | ||
271 | key_provided = 0; | ||
272 | key = ieee->tx_keyidx; | ||
273 | } | ||
274 | |||
275 | IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? | ||
276 | "provided" : "default"); | ||
277 | |||
278 | crypt = &ieee->crypt[key]; | ||
279 | |||
280 | if (erq->flags & IW_ENCODE_DISABLED) { | ||
281 | if (key_provided && *crypt) { | ||
282 | IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n", | ||
283 | key); | ||
284 | ieee80211_crypt_delayed_deinit(ieee, crypt); | ||
285 | } else | ||
286 | IEEE80211_DEBUG_WX("Disabling encryption.\n"); | ||
287 | |||
288 | /* Check all the keys to see if any are still configured, | ||
289 | * and if no key index was provided, de-init them all */ | ||
290 | for (i = 0; i < WEP_KEYS; i++) { | ||
291 | if (ieee->crypt[i] != NULL) { | ||
292 | if (key_provided) | ||
293 | break; | ||
294 | ieee80211_crypt_delayed_deinit(ieee, | ||
295 | &ieee->crypt[i]); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | if (i == WEP_KEYS) { | ||
300 | sec.enabled = 0; | ||
301 | sec.level = SEC_LEVEL_0; | ||
302 | sec.flags |= SEC_ENABLED | SEC_LEVEL; | ||
303 | } | ||
304 | |||
305 | goto done; | ||
306 | } | ||
307 | |||
308 | sec.enabled = 1; | ||
309 | sec.flags |= SEC_ENABLED; | ||
310 | |||
311 | if (*crypt != NULL && (*crypt)->ops != NULL && | ||
312 | strcmp((*crypt)->ops->name, "WEP") != 0) { | ||
313 | /* changing to use WEP; deinit previously used algorithm | ||
314 | * on this key */ | ||
315 | ieee80211_crypt_delayed_deinit(ieee, crypt); | ||
316 | } | ||
317 | |||
318 | if (*crypt == NULL) { | ||
319 | struct ieee80211_crypt_data *new_crypt; | ||
320 | |||
321 | /* take WEP into use */ | ||
322 | new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data), | ||
323 | GFP_KERNEL); | ||
324 | if (new_crypt == NULL) | ||
325 | return -ENOMEM; | ||
326 | memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); | ||
327 | new_crypt->ops = ieee80211_get_crypto_ops("WEP"); | ||
328 | if (!new_crypt->ops) { | ||
329 | request_module("ieee80211_crypt_wep"); | ||
330 | new_crypt->ops = ieee80211_get_crypto_ops("WEP"); | ||
331 | } | ||
332 | |||
333 | if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) | ||
334 | new_crypt->priv = new_crypt->ops->init(key); | ||
335 | |||
336 | if (!new_crypt->ops || !new_crypt->priv) { | ||
337 | kfree(new_crypt); | ||
338 | new_crypt = NULL; | ||
339 | |||
340 | printk(KERN_WARNING "%s: could not initialize WEP: " | ||
341 | "load module ieee80211_crypt_wep\n", dev->name); | ||
342 | return -EOPNOTSUPP; | ||
343 | } | ||
344 | *crypt = new_crypt; | ||
345 | } | ||
346 | |||
347 | /* If a new key was provided, set it up */ | ||
348 | if (erq->length > 0) { | ||
349 | len = erq->length <= 5 ? 5 : 13; | ||
350 | memcpy(sec.keys[key], keybuf, erq->length); | ||
351 | if (len > erq->length) | ||
352 | memset(sec.keys[key] + erq->length, 0, | ||
353 | len - erq->length); | ||
354 | IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", | ||
355 | key, escape_essid(sec.keys[key], len), | ||
356 | erq->length, len); | ||
357 | sec.key_sizes[key] = len; | ||
358 | (*crypt)->ops->set_key(sec.keys[key], len, NULL, | ||
359 | (*crypt)->priv); | ||
360 | sec.flags |= (1 << key); | ||
361 | /* This ensures a key will be activated if no key is | ||
362 | * explicitely set */ | ||
363 | if (key == sec.active_key) | ||
364 | sec.flags |= SEC_ACTIVE_KEY; | ||
365 | } else { | ||
366 | len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, | ||
367 | NULL, (*crypt)->priv); | ||
368 | if (len == 0) { | ||
369 | /* Set a default key of all 0 */ | ||
370 | IEEE80211_DEBUG_WX("Setting key %d to all zero.\n", | ||
371 | key); | ||
372 | memset(sec.keys[key], 0, 13); | ||
373 | (*crypt)->ops->set_key(sec.keys[key], 13, NULL, | ||
374 | (*crypt)->priv); | ||
375 | sec.key_sizes[key] = 13; | ||
376 | sec.flags |= (1 << key); | ||
377 | } | ||
378 | |||
379 | /* No key data - just set the default TX key index */ | ||
380 | if (key_provided) { | ||
381 | IEEE80211_DEBUG_WX | ||
382 | ("Setting key %d to default Tx key.\n", key); | ||
383 | ieee->tx_keyidx = key; | ||
384 | sec.active_key = key; | ||
385 | sec.flags |= SEC_ACTIVE_KEY; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | done: | ||
390 | ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); | ||
391 | sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; | ||
392 | sec.flags |= SEC_AUTH_MODE; | ||
393 | IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ? | ||
394 | "OPEN" : "SHARED KEY"); | ||
395 | |||
396 | /* For now we just support WEP, so only set that security level... | ||
397 | * TODO: When WPA is added this is one place that needs to change */ | ||
398 | sec.flags |= SEC_LEVEL; | ||
399 | sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ | ||
400 | |||
401 | if (ieee->set_security) | ||
402 | ieee->set_security(dev, &sec); | ||
403 | |||
404 | /* Do not reset port if card is in Managed mode since resetting will | ||
405 | * generate new IEEE 802.11 authentication which may end up in looping | ||
406 | * with IEEE 802.1X. If your hardware requires a reset after WEP | ||
407 | * configuration (for example... Prism2), implement the reset_port in | ||
408 | * the callbacks structures used to initialize the 802.11 stack. */ | ||
409 | if (ieee->reset_on_keychange && | ||
410 | ieee->iw_mode != IW_MODE_INFRA && | ||
411 | ieee->reset_port && ieee->reset_port(dev)) { | ||
412 | printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); | ||
413 | return -EINVAL; | ||
414 | } | ||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | int ieee80211_wx_get_encode(struct ieee80211_device *ieee, | ||
419 | struct iw_request_info *info, | ||
420 | union iwreq_data *wrqu, char *keybuf) | ||
421 | { | ||
422 | struct iw_point *erq = &(wrqu->encoding); | ||
423 | int len, key; | ||
424 | struct ieee80211_crypt_data *crypt; | ||
425 | |||
426 | IEEE80211_DEBUG_WX("GET_ENCODE\n"); | ||
427 | |||
428 | key = erq->flags & IW_ENCODE_INDEX; | ||
429 | if (key) { | ||
430 | if (key > WEP_KEYS) | ||
431 | return -EINVAL; | ||
432 | key--; | ||
433 | } else | ||
434 | key = ieee->tx_keyidx; | ||
435 | |||
436 | crypt = ieee->crypt[key]; | ||
437 | erq->flags = key + 1; | ||
438 | |||
439 | if (crypt == NULL || crypt->ops == NULL) { | ||
440 | erq->length = 0; | ||
441 | erq->flags |= IW_ENCODE_DISABLED; | ||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | if (strcmp(crypt->ops->name, "WEP") != 0) { | ||
446 | /* only WEP is supported with wireless extensions, so just | ||
447 | * report that encryption is used */ | ||
448 | erq->length = 0; | ||
449 | erq->flags |= IW_ENCODE_ENABLED; | ||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv); | ||
454 | erq->length = (len >= 0 ? len : 0); | ||
455 | |||
456 | erq->flags |= IW_ENCODE_ENABLED; | ||
457 | |||
458 | if (ieee->open_wep) | ||
459 | erq->flags |= IW_ENCODE_OPEN; | ||
460 | else | ||
461 | erq->flags |= IW_ENCODE_RESTRICTED; | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | EXPORT_SYMBOL(ieee80211_wx_get_scan); | ||
467 | EXPORT_SYMBOL(ieee80211_wx_set_encode); | ||
468 | EXPORT_SYMBOL(ieee80211_wx_get_encode); | ||
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 514c85b2631a..035ad2c9e1ba 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c | |||
@@ -263,10 +263,8 @@ static int ah_init_state(struct xfrm_state *x) | |||
263 | 263 | ||
264 | error: | 264 | error: |
265 | if (ahp) { | 265 | if (ahp) { |
266 | if (ahp->work_icv) | 266 | kfree(ahp->work_icv); |
267 | kfree(ahp->work_icv); | 267 | crypto_free_tfm(ahp->tfm); |
268 | if (ahp->tfm) | ||
269 | crypto_free_tfm(ahp->tfm); | ||
270 | kfree(ahp); | 268 | kfree(ahp); |
271 | } | 269 | } |
272 | return -EINVAL; | 270 | return -EINVAL; |
@@ -279,14 +277,10 @@ static void ah_destroy(struct xfrm_state *x) | |||
279 | if (!ahp) | 277 | if (!ahp) |
280 | return; | 278 | return; |
281 | 279 | ||
282 | if (ahp->work_icv) { | 280 | kfree(ahp->work_icv); |
283 | kfree(ahp->work_icv); | 281 | ahp->work_icv = NULL; |
284 | ahp->work_icv = NULL; | 282 | crypto_free_tfm(ahp->tfm); |
285 | } | 283 | ahp->tfm = NULL; |
286 | if (ahp->tfm) { | ||
287 | crypto_free_tfm(ahp->tfm); | ||
288 | ahp->tfm = NULL; | ||
289 | } | ||
290 | kfree(ahp); | 284 | kfree(ahp); |
291 | } | 285 | } |
292 | 286 | ||
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index b31ffc5053d2..1b5a09d1b90b 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c | |||
@@ -343,22 +343,14 @@ static void esp_destroy(struct xfrm_state *x) | |||
343 | if (!esp) | 343 | if (!esp) |
344 | return; | 344 | return; |
345 | 345 | ||
346 | if (esp->conf.tfm) { | 346 | crypto_free_tfm(esp->conf.tfm); |
347 | crypto_free_tfm(esp->conf.tfm); | 347 | esp->conf.tfm = NULL; |
348 | esp->conf.tfm = NULL; | 348 | kfree(esp->conf.ivec); |
349 | } | 349 | esp->conf.ivec = NULL; |
350 | if (esp->conf.ivec) { | 350 | crypto_free_tfm(esp->auth.tfm); |
351 | kfree(esp->conf.ivec); | 351 | esp->auth.tfm = NULL; |
352 | esp->conf.ivec = NULL; | 352 | kfree(esp->auth.work_icv); |
353 | } | 353 | esp->auth.work_icv = NULL; |
354 | if (esp->auth.tfm) { | ||
355 | crypto_free_tfm(esp->auth.tfm); | ||
356 | esp->auth.tfm = NULL; | ||
357 | } | ||
358 | if (esp->auth.work_icv) { | ||
359 | kfree(esp->auth.work_icv); | ||
360 | esp->auth.work_icv = NULL; | ||
361 | } | ||
362 | kfree(esp); | 354 | kfree(esp); |
363 | } | 355 | } |
364 | 356 | ||
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 9e6e683cc34d..e7d26d9943c2 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c | |||
@@ -457,7 +457,7 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb) | |||
457 | 457 | ||
458 | if (pskb_pull(skb, ihl) == NULL) | 458 | if (pskb_pull(skb, ihl) == NULL) |
459 | goto err; | 459 | goto err; |
460 | if (pskb_trim(skb, end-offset)) | 460 | if (pskb_trim_rcsum(skb, end-offset)) |
461 | goto err; | 461 | goto err; |
462 | 462 | ||
463 | /* Find out which fragments are in front and at the back of us | 463 | /* Find out which fragments are in front and at the back of us |
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index dcb7ee6c4858..fc718df17b40 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c | |||
@@ -345,8 +345,7 @@ static void ipcomp_free_tfms(struct crypto_tfm **tfms) | |||
345 | 345 | ||
346 | for_each_cpu(cpu) { | 346 | for_each_cpu(cpu) { |
347 | struct crypto_tfm *tfm = *per_cpu_ptr(tfms, cpu); | 347 | struct crypto_tfm *tfm = *per_cpu_ptr(tfms, cpu); |
348 | if (tfm) | 348 | crypto_free_tfm(tfm); |
349 | crypto_free_tfm(tfm); | ||
350 | } | 349 | } |
351 | free_percpu(tfms); | 350 | free_percpu(tfms); |
352 | } | 351 | } |
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 63e106605f28..953129d392d2 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include <linux/major.h> | 54 | #include <linux/major.h> |
55 | #include <linux/root_dev.h> | 55 | #include <linux/root_dev.h> |
56 | #include <linux/delay.h> | 56 | #include <linux/delay.h> |
57 | #include <linux/nfs_fs.h> | ||
57 | #include <net/arp.h> | 58 | #include <net/arp.h> |
58 | #include <net/ip.h> | 59 | #include <net/ip.h> |
59 | #include <net/ipconfig.h> | 60 | #include <net/ipconfig.h> |
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index e046f5521814..30aa8e2ee214 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -34,6 +34,7 @@ config IP_NF_CT_ACCT | |||
34 | 34 | ||
35 | config IP_NF_CONNTRACK_MARK | 35 | config IP_NF_CONNTRACK_MARK |
36 | bool 'Connection mark tracking support' | 36 | bool 'Connection mark tracking support' |
37 | depends on IP_NF_CONNTRACK | ||
37 | help | 38 | help |
38 | This option enables support for connection marks, used by the | 39 | This option enables support for connection marks, used by the |
39 | `CONNMARK' target and `connmark' match. Similar to the mark value | 40 | `CONNMARK' target and `connmark' match. Similar to the mark value |
@@ -85,6 +86,25 @@ config IP_NF_IRC | |||
85 | 86 | ||
86 | To compile it as a module, choose M here. If unsure, say Y. | 87 | To compile it as a module, choose M here. If unsure, say Y. |
87 | 88 | ||
89 | config IP_NF_NETBIOS_NS | ||
90 | tristate "NetBIOS name service protocol support (EXPERIMENTAL)" | ||
91 | depends on IP_NF_CONNTRACK && EXPERIMENTAL | ||
92 | help | ||
93 | NetBIOS name service requests are sent as broadcast messages from an | ||
94 | unprivileged port and responded to with unicast messages to the | ||
95 | same port. This make them hard to firewall properly because connection | ||
96 | tracking doesn't deal with broadcasts. This helper tracks locally | ||
97 | originating NetBIOS name service requests and the corresponding | ||
98 | responses. It relies on correct IP address configuration, specifically | ||
99 | netmask and broadcast address. When properly configured, the output | ||
100 | of "ip address show" should look similar to this: | ||
101 | |||
102 | $ ip -4 address show eth0 | ||
103 | 4: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000 | ||
104 | inet 172.16.2.252/24 brd 172.16.2.255 scope global eth0 | ||
105 | |||
106 | To compile it as a module, choose M here. If unsure, say N. | ||
107 | |||
88 | config IP_NF_TFTP | 108 | config IP_NF_TFTP |
89 | tristate "TFTP protocol support" | 109 | tristate "TFTP protocol support" |
90 | depends on IP_NF_CONNTRACK | 110 | depends on IP_NF_CONNTRACK |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index a7bd38f50522..1ba0db746817 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
@@ -21,6 +21,7 @@ obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o | |||
21 | obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o | 21 | obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o |
22 | obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o | 22 | obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o |
23 | obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o | 23 | obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o |
24 | obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o | ||
24 | 25 | ||
25 | # NAT helpers | 26 | # NAT helpers |
26 | obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o | 27 | obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o |
diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c index be4c9eb3243f..dc20881004bc 100644 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c +++ b/net/ipv4/netfilter/ip_conntrack_amanda.c | |||
@@ -108,6 +108,7 @@ static int help(struct sk_buff **pskb, | |||
108 | } | 108 | } |
109 | 109 | ||
110 | exp->expectfn = NULL; | 110 | exp->expectfn = NULL; |
111 | exp->flags = 0; | ||
111 | 112 | ||
112 | exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; | 113 | exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; |
113 | exp->tuple.src.u.tcp.port = 0; | 114 | exp->tuple.src.u.tcp.port = 0; |
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index a0648600190e..19cba16e6e1e 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c | |||
@@ -197,7 +197,7 @@ ip_ct_invert_tuple(struct ip_conntrack_tuple *inverse, | |||
197 | 197 | ||
198 | 198 | ||
199 | /* ip_conntrack_expect helper functions */ | 199 | /* ip_conntrack_expect helper functions */ |
200 | static void unlink_expect(struct ip_conntrack_expect *exp) | 200 | void ip_ct_unlink_expect(struct ip_conntrack_expect *exp) |
201 | { | 201 | { |
202 | ASSERT_WRITE_LOCK(&ip_conntrack_lock); | 202 | ASSERT_WRITE_LOCK(&ip_conntrack_lock); |
203 | IP_NF_ASSERT(!timer_pending(&exp->timeout)); | 203 | IP_NF_ASSERT(!timer_pending(&exp->timeout)); |
@@ -207,18 +207,12 @@ static void unlink_expect(struct ip_conntrack_expect *exp) | |||
207 | ip_conntrack_expect_put(exp); | 207 | ip_conntrack_expect_put(exp); |
208 | } | 208 | } |
209 | 209 | ||
210 | void __ip_ct_expect_unlink_destroy(struct ip_conntrack_expect *exp) | ||
211 | { | ||
212 | unlink_expect(exp); | ||
213 | ip_conntrack_expect_put(exp); | ||
214 | } | ||
215 | |||
216 | static void expectation_timed_out(unsigned long ul_expect) | 210 | static void expectation_timed_out(unsigned long ul_expect) |
217 | { | 211 | { |
218 | struct ip_conntrack_expect *exp = (void *)ul_expect; | 212 | struct ip_conntrack_expect *exp = (void *)ul_expect; |
219 | 213 | ||
220 | write_lock_bh(&ip_conntrack_lock); | 214 | write_lock_bh(&ip_conntrack_lock); |
221 | unlink_expect(exp); | 215 | ip_ct_unlink_expect(exp); |
222 | write_unlock_bh(&ip_conntrack_lock); | 216 | write_unlock_bh(&ip_conntrack_lock); |
223 | ip_conntrack_expect_put(exp); | 217 | ip_conntrack_expect_put(exp); |
224 | } | 218 | } |
@@ -264,10 +258,14 @@ find_expectation(const struct ip_conntrack_tuple *tuple) | |||
264 | master ct never got confirmed, we'd hold a reference to it | 258 | master ct never got confirmed, we'd hold a reference to it |
265 | and weird things would happen to future packets). */ | 259 | and weird things would happen to future packets). */ |
266 | if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) | 260 | if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) |
267 | && is_confirmed(i->master) | 261 | && is_confirmed(i->master)) { |
268 | && del_timer(&i->timeout)) { | 262 | if (i->flags & IP_CT_EXPECT_PERMANENT) { |
269 | unlink_expect(i); | 263 | atomic_inc(&i->use); |
270 | return i; | 264 | return i; |
265 | } else if (del_timer(&i->timeout)) { | ||
266 | ip_ct_unlink_expect(i); | ||
267 | return i; | ||
268 | } | ||
271 | } | 269 | } |
272 | } | 270 | } |
273 | return NULL; | 271 | return NULL; |
@@ -284,7 +282,7 @@ void ip_ct_remove_expectations(struct ip_conntrack *ct) | |||
284 | 282 | ||
285 | list_for_each_entry_safe(i, tmp, &ip_conntrack_expect_list, list) { | 283 | list_for_each_entry_safe(i, tmp, &ip_conntrack_expect_list, list) { |
286 | if (i->master == ct && del_timer(&i->timeout)) { | 284 | if (i->master == ct && del_timer(&i->timeout)) { |
287 | unlink_expect(i); | 285 | ip_ct_unlink_expect(i); |
288 | ip_conntrack_expect_put(i); | 286 | ip_conntrack_expect_put(i); |
289 | } | 287 | } |
290 | } | 288 | } |
@@ -925,7 +923,7 @@ void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp) | |||
925 | /* choose the the oldest expectation to evict */ | 923 | /* choose the the oldest expectation to evict */ |
926 | list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) { | 924 | list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) { |
927 | if (expect_matches(i, exp) && del_timer(&i->timeout)) { | 925 | if (expect_matches(i, exp) && del_timer(&i->timeout)) { |
928 | unlink_expect(i); | 926 | ip_ct_unlink_expect(i); |
929 | write_unlock_bh(&ip_conntrack_lock); | 927 | write_unlock_bh(&ip_conntrack_lock); |
930 | ip_conntrack_expect_put(i); | 928 | ip_conntrack_expect_put(i); |
931 | return; | 929 | return; |
@@ -934,6 +932,9 @@ void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp) | |||
934 | write_unlock_bh(&ip_conntrack_lock); | 932 | write_unlock_bh(&ip_conntrack_lock); |
935 | } | 933 | } |
936 | 934 | ||
935 | /* We don't increase the master conntrack refcount for non-fulfilled | ||
936 | * conntracks. During the conntrack destruction, the expectations are | ||
937 | * always killed before the conntrack itself */ | ||
937 | struct ip_conntrack_expect *ip_conntrack_expect_alloc(struct ip_conntrack *me) | 938 | struct ip_conntrack_expect *ip_conntrack_expect_alloc(struct ip_conntrack *me) |
938 | { | 939 | { |
939 | struct ip_conntrack_expect *new; | 940 | struct ip_conntrack_expect *new; |
@@ -944,17 +945,14 @@ struct ip_conntrack_expect *ip_conntrack_expect_alloc(struct ip_conntrack *me) | |||
944 | return NULL; | 945 | return NULL; |
945 | } | 946 | } |
946 | new->master = me; | 947 | new->master = me; |
947 | atomic_inc(&new->master->ct_general.use); | ||
948 | atomic_set(&new->use, 1); | 948 | atomic_set(&new->use, 1); |
949 | return new; | 949 | return new; |
950 | } | 950 | } |
951 | 951 | ||
952 | void ip_conntrack_expect_put(struct ip_conntrack_expect *exp) | 952 | void ip_conntrack_expect_put(struct ip_conntrack_expect *exp) |
953 | { | 953 | { |
954 | if (atomic_dec_and_test(&exp->use)) { | 954 | if (atomic_dec_and_test(&exp->use)) |
955 | ip_conntrack_put(exp->master); | ||
956 | kmem_cache_free(ip_conntrack_expect_cachep, exp); | 955 | kmem_cache_free(ip_conntrack_expect_cachep, exp); |
957 | } | ||
958 | } | 956 | } |
959 | 957 | ||
960 | static void ip_conntrack_expect_insert(struct ip_conntrack_expect *exp) | 958 | static void ip_conntrack_expect_insert(struct ip_conntrack_expect *exp) |
@@ -982,7 +980,7 @@ static void evict_oldest_expect(struct ip_conntrack *master) | |||
982 | list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) { | 980 | list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) { |
983 | if (i->master == master) { | 981 | if (i->master == master) { |
984 | if (del_timer(&i->timeout)) { | 982 | if (del_timer(&i->timeout)) { |
985 | unlink_expect(i); | 983 | ip_ct_unlink_expect(i); |
986 | ip_conntrack_expect_put(i); | 984 | ip_conntrack_expect_put(i); |
987 | } | 985 | } |
988 | break; | 986 | break; |
@@ -1099,7 +1097,7 @@ void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me) | |||
1099 | /* Get rid of expectations */ | 1097 | /* Get rid of expectations */ |
1100 | list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, list) { | 1098 | list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, list) { |
1101 | if (exp->master->helper == me && del_timer(&exp->timeout)) { | 1099 | if (exp->master->helper == me && del_timer(&exp->timeout)) { |
1102 | unlink_expect(exp); | 1100 | ip_ct_unlink_expect(exp); |
1103 | ip_conntrack_expect_put(exp); | 1101 | ip_conntrack_expect_put(exp); |
1104 | } | 1102 | } |
1105 | } | 1103 | } |
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c index 3a2627db1729..1b79ec36085f 100644 --- a/net/ipv4/netfilter/ip_conntrack_ftp.c +++ b/net/ipv4/netfilter/ip_conntrack_ftp.c | |||
@@ -421,6 +421,7 @@ static int help(struct sk_buff **pskb, | |||
421 | { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }}); | 421 | { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }}); |
422 | 422 | ||
423 | exp->expectfn = NULL; | 423 | exp->expectfn = NULL; |
424 | exp->flags = 0; | ||
424 | 425 | ||
425 | /* Now, NAT might want to mangle the packet, and register the | 426 | /* Now, NAT might want to mangle the packet, and register the |
426 | * (possibly changed) expectation itself. */ | 427 | * (possibly changed) expectation itself. */ |
diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c index 25438eec21a1..d7a8a98c05e1 100644 --- a/net/ipv4/netfilter/ip_conntrack_irc.c +++ b/net/ipv4/netfilter/ip_conntrack_irc.c | |||
@@ -221,6 +221,7 @@ static int help(struct sk_buff **pskb, | |||
221 | { { 0, { 0 } }, | 221 | { { 0, { 0 } }, |
222 | { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }}); | 222 | { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }}); |
223 | exp->expectfn = NULL; | 223 | exp->expectfn = NULL; |
224 | exp->flags = 0; | ||
224 | if (ip_nat_irc_hook) | 225 | if (ip_nat_irc_hook) |
225 | ret = ip_nat_irc_hook(pskb, ctinfo, | 226 | ret = ip_nat_irc_hook(pskb, ctinfo, |
226 | addr_beg_p - ib_ptr, | 227 | addr_beg_p - ib_ptr, |
diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c new file mode 100644 index 000000000000..2b5cf9c51309 --- /dev/null +++ b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c | |||
@@ -0,0 +1,131 @@ | |||
1 | /* | ||
2 | * NetBIOS name service broadcast connection tracking helper | ||
3 | * | ||
4 | * (c) 2005 Patrick McHardy <kaber@trash.net> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | /* | ||
12 | * This helper tracks locally originating NetBIOS name service | ||
13 | * requests by issuing permanent expectations (valid until | ||
14 | * timing out) matching all reply connections from the | ||
15 | * destination network. The only NetBIOS specific thing is | ||
16 | * actually the port number. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/skbuff.h> | ||
22 | #include <linux/netdevice.h> | ||
23 | #include <linux/inetdevice.h> | ||
24 | #include <linux/in.h> | ||
25 | #include <linux/ip.h> | ||
26 | #include <linux/udp.h> | ||
27 | #include <net/route.h> | ||
28 | |||
29 | #include <linux/netfilter.h> | ||
30 | #include <linux/netfilter_ipv4.h> | ||
31 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
32 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
33 | |||
34 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
35 | MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper"); | ||
36 | MODULE_LICENSE("GPL"); | ||
37 | |||
38 | static unsigned int timeout = 3; | ||
39 | module_param(timeout, int, 0600); | ||
40 | MODULE_PARM_DESC(timeout, "timeout for master connection/replies in seconds"); | ||
41 | |||
42 | static int help(struct sk_buff **pskb, | ||
43 | struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) | ||
44 | { | ||
45 | struct ip_conntrack_expect *exp; | ||
46 | struct iphdr *iph = (*pskb)->nh.iph; | ||
47 | struct udphdr _uh, *uh; | ||
48 | struct rtable *rt = (struct rtable *)(*pskb)->dst; | ||
49 | struct in_device *in_dev; | ||
50 | u_int32_t mask = 0; | ||
51 | |||
52 | /* we're only interested in locally generated packets */ | ||
53 | if ((*pskb)->sk == NULL) | ||
54 | goto out; | ||
55 | if (rt == NULL || !(rt->rt_flags & RTCF_BROADCAST)) | ||
56 | goto out; | ||
57 | if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) | ||
58 | goto out; | ||
59 | |||
60 | rcu_read_lock(); | ||
61 | in_dev = __in_dev_get(rt->u.dst.dev); | ||
62 | if (in_dev != NULL) { | ||
63 | for_primary_ifa(in_dev) { | ||
64 | if (ifa->ifa_broadcast == iph->daddr) { | ||
65 | mask = ifa->ifa_mask; | ||
66 | break; | ||
67 | } | ||
68 | } endfor_ifa(in_dev); | ||
69 | } | ||
70 | rcu_read_unlock(); | ||
71 | |||
72 | if (mask == 0) | ||
73 | goto out; | ||
74 | |||
75 | uh = skb_header_pointer(*pskb, iph->ihl * 4, sizeof(_uh), &_uh); | ||
76 | BUG_ON(uh == NULL); | ||
77 | |||
78 | exp = ip_conntrack_expect_alloc(ct); | ||
79 | if (exp == NULL) | ||
80 | goto out; | ||
81 | memset(&exp->tuple, 0, sizeof(exp->tuple)); | ||
82 | exp->tuple.src.ip = iph->daddr & mask; | ||
83 | exp->tuple.dst.ip = iph->saddr; | ||
84 | exp->tuple.dst.u.udp.port = uh->source; | ||
85 | exp->tuple.dst.protonum = IPPROTO_UDP; | ||
86 | |||
87 | memset(&exp->mask, 0, sizeof(exp->mask)); | ||
88 | exp->mask.src.ip = mask; | ||
89 | exp->mask.dst.ip = 0xFFFFFFFF; | ||
90 | exp->mask.dst.u.udp.port = 0xFFFF; | ||
91 | exp->mask.dst.protonum = 0xFF; | ||
92 | |||
93 | exp->expectfn = NULL; | ||
94 | exp->flags = IP_CT_EXPECT_PERMANENT; | ||
95 | |||
96 | ip_conntrack_expect_related(exp); | ||
97 | ip_conntrack_expect_put(exp); | ||
98 | |||
99 | ip_ct_refresh_acct(ct, ctinfo, NULL, timeout * HZ); | ||
100 | out: | ||
101 | return NF_ACCEPT; | ||
102 | } | ||
103 | |||
104 | static struct ip_conntrack_helper helper = { | ||
105 | .name = "netbios-ns", | ||
106 | .tuple = { | ||
107 | .src.u.udp.port = __constant_htons(137), | ||
108 | .dst.protonum = IPPROTO_UDP, | ||
109 | }, | ||
110 | .mask = { | ||
111 | .src.u.udp.port = 0xFFFF, | ||
112 | .dst.protonum = 0xFF, | ||
113 | }, | ||
114 | .max_expected = 1, | ||
115 | .me = THIS_MODULE, | ||
116 | .help = help, | ||
117 | }; | ||
118 | |||
119 | static int __init init(void) | ||
120 | { | ||
121 | helper.timeout = timeout; | ||
122 | return ip_conntrack_helper_register(&helper); | ||
123 | } | ||
124 | |||
125 | static void __exit fini(void) | ||
126 | { | ||
127 | ip_conntrack_helper_unregister(&helper); | ||
128 | } | ||
129 | |||
130 | module_init(init); | ||
131 | module_exit(fini); | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index a4e9278db4ed..15aef3564742 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c | |||
@@ -1349,8 +1349,10 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, | |||
1349 | list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, | 1349 | list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, |
1350 | list) { | 1350 | list) { |
1351 | if (exp->master->helper == h | 1351 | if (exp->master->helper == h |
1352 | && del_timer(&exp->timeout)) | 1352 | && del_timer(&exp->timeout)) { |
1353 | __ip_ct_expect_unlink_destroy(exp); | 1353 | ip_ct_unlink_expect(exp); |
1354 | ip_conntrack_expect_put(exp); | ||
1355 | } | ||
1354 | } | 1356 | } |
1355 | write_unlock(&ip_conntrack_lock); | 1357 | write_unlock(&ip_conntrack_lock); |
1356 | } else { | 1358 | } else { |
@@ -1358,8 +1360,10 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, | |||
1358 | write_lock_bh(&ip_conntrack_lock); | 1360 | write_lock_bh(&ip_conntrack_lock); |
1359 | list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, | 1361 | list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, |
1360 | list) { | 1362 | list) { |
1361 | if (del_timer(&exp->timeout)) | 1363 | if (del_timer(&exp->timeout)) { |
1362 | __ip_ct_expect_unlink_destroy(exp); | 1364 | ip_ct_unlink_expect(exp); |
1365 | ip_conntrack_expect_put(exp); | ||
1366 | } | ||
1363 | } | 1367 | } |
1364 | write_unlock_bh(&ip_conntrack_lock); | 1368 | write_unlock_bh(&ip_conntrack_lock); |
1365 | } | 1369 | } |
@@ -1413,6 +1417,7 @@ ctnetlink_create_expect(struct nfattr *cda[]) | |||
1413 | } | 1417 | } |
1414 | 1418 | ||
1415 | exp->expectfn = NULL; | 1419 | exp->expectfn = NULL; |
1420 | exp->flags = 0; | ||
1416 | exp->master = ct; | 1421 | exp->master = ct; |
1417 | memcpy(&exp->tuple, &tuple, sizeof(struct ip_conntrack_tuple)); | 1422 | memcpy(&exp->tuple, &tuple, sizeof(struct ip_conntrack_tuple)); |
1418 | memcpy(&exp->mask, &mask, sizeof(struct ip_conntrack_tuple)); | 1423 | memcpy(&exp->mask, &mask, sizeof(struct ip_conntrack_tuple)); |
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c index f23ef1f88c46..1985abc59d24 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c | |||
@@ -349,6 +349,7 @@ static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa, | |||
349 | return 0; | 349 | return 0; |
350 | 350 | ||
351 | nfattr_failure: | 351 | nfattr_failure: |
352 | read_unlock_bh(&tcp_lock); | ||
352 | return -1; | 353 | return -1; |
353 | } | 354 | } |
354 | #endif | 355 | #endif |
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index ee5895afd0c3..ae3e3e655db5 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c | |||
@@ -998,7 +998,7 @@ EXPORT_SYMBOL(ip_conntrack_expect_related); | |||
998 | EXPORT_SYMBOL(ip_conntrack_unexpect_related); | 998 | EXPORT_SYMBOL(ip_conntrack_unexpect_related); |
999 | EXPORT_SYMBOL_GPL(ip_conntrack_expect_list); | 999 | EXPORT_SYMBOL_GPL(ip_conntrack_expect_list); |
1000 | EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); | 1000 | EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); |
1001 | EXPORT_SYMBOL_GPL(__ip_ct_expect_unlink_destroy); | 1001 | EXPORT_SYMBOL_GPL(ip_ct_unlink_expect); |
1002 | 1002 | ||
1003 | EXPORT_SYMBOL(ip_conntrack_tuple_taken); | 1003 | EXPORT_SYMBOL(ip_conntrack_tuple_taken); |
1004 | EXPORT_SYMBOL(ip_ct_gather_frags); | 1004 | EXPORT_SYMBOL(ip_ct_gather_frags); |
diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c index f8ff170f390a..d2b590533452 100644 --- a/net/ipv4/netfilter/ip_conntrack_tftp.c +++ b/net/ipv4/netfilter/ip_conntrack_tftp.c | |||
@@ -75,6 +75,7 @@ static int tftp_help(struct sk_buff **pskb, | |||
75 | exp->mask.dst.u.udp.port = 0xffff; | 75 | exp->mask.dst.u.udp.port = 0xffff; |
76 | exp->mask.dst.protonum = 0xff; | 76 | exp->mask.dst.protonum = 0xff; |
77 | exp->expectfn = NULL; | 77 | exp->expectfn = NULL; |
78 | exp->flags = 0; | ||
78 | 79 | ||
79 | DEBUGP("expect: "); | 80 | DEBUGP("expect: "); |
80 | DUMP_TUPLE(&exp->tuple); | 81 | DUMP_TUPLE(&exp->tuple); |
diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c index 60d70fa41a15..cb66b8bddeb3 100644 --- a/net/ipv4/netfilter/ip_nat_rule.c +++ b/net/ipv4/netfilter/ip_nat_rule.c | |||
@@ -255,6 +255,27 @@ alloc_null_binding(struct ip_conntrack *conntrack, | |||
255 | return ip_nat_setup_info(conntrack, &range, hooknum); | 255 | return ip_nat_setup_info(conntrack, &range, hooknum); |
256 | } | 256 | } |
257 | 257 | ||
258 | unsigned int | ||
259 | alloc_null_binding_confirmed(struct ip_conntrack *conntrack, | ||
260 | struct ip_nat_info *info, | ||
261 | unsigned int hooknum) | ||
262 | { | ||
263 | u_int32_t ip | ||
264 | = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC | ||
265 | ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip | ||
266 | : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip); | ||
267 | u_int16_t all | ||
268 | = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC | ||
269 | ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all | ||
270 | : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all); | ||
271 | struct ip_nat_range range | ||
272 | = { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } }; | ||
273 | |||
274 | DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n", | ||
275 | conntrack, NIPQUAD(ip)); | ||
276 | return ip_nat_setup_info(conntrack, &range, hooknum); | ||
277 | } | ||
278 | |||
258 | int ip_nat_rule_find(struct sk_buff **pskb, | 279 | int ip_nat_rule_find(struct sk_buff **pskb, |
259 | unsigned int hooknum, | 280 | unsigned int hooknum, |
260 | const struct net_device *in, | 281 | const struct net_device *in, |
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index 89db052add81..0ff368b131f6 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c | |||
@@ -123,8 +123,12 @@ ip_nat_fn(unsigned int hooknum, | |||
123 | if (!ip_nat_initialized(ct, maniptype)) { | 123 | if (!ip_nat_initialized(ct, maniptype)) { |
124 | unsigned int ret; | 124 | unsigned int ret; |
125 | 125 | ||
126 | /* LOCAL_IN hook doesn't have a chain! */ | 126 | if (unlikely(is_confirmed(ct))) |
127 | if (hooknum == NF_IP_LOCAL_IN) | 127 | /* NAT module was loaded late */ |
128 | ret = alloc_null_binding_confirmed(ct, info, | ||
129 | hooknum); | ||
130 | else if (hooknum == NF_IP_LOCAL_IN) | ||
131 | /* LOCAL_IN hook doesn't have a chain! */ | ||
128 | ret = alloc_null_binding(ct, info, hooknum); | 132 | ret = alloc_null_binding(ct, info, hooknum); |
129 | else | 133 | else |
130 | ret = ip_nat_rule_find(pskb, hooknum, | 134 | ret = ip_nat_rule_find(pskb, hooknum, |
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 2d05cafec221..7d38913754b1 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c | |||
@@ -144,7 +144,7 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip, | |||
144 | memcpy(&c->clustermac, &i->clustermac, ETH_ALEN); | 144 | memcpy(&c->clustermac, &i->clustermac, ETH_ALEN); |
145 | c->num_total_nodes = i->num_total_nodes; | 145 | c->num_total_nodes = i->num_total_nodes; |
146 | c->num_local_nodes = i->num_local_nodes; | 146 | c->num_local_nodes = i->num_local_nodes; |
147 | memcpy(&c->local_nodes, &i->local_nodes, sizeof(&c->local_nodes)); | 147 | memcpy(&c->local_nodes, &i->local_nodes, sizeof(c->local_nodes)); |
148 | c->hash_mode = i->hash_mode; | 148 | c->hash_mode = i->hash_mode; |
149 | c->hash_initval = i->hash_initval; | 149 | c->hash_initval = i->hash_initval; |
150 | atomic_set(&c->refcount, 1); | 150 | atomic_set(&c->refcount, 1); |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 02fdda68718d..f3f0013a9580 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -552,8 +552,7 @@ new_segment: | |||
552 | tcp_mark_push(tp, skb); | 552 | tcp_mark_push(tp, skb); |
553 | goto new_segment; | 553 | goto new_segment; |
554 | } | 554 | } |
555 | if (sk->sk_forward_alloc < copy && | 555 | if (!sk_stream_wmem_schedule(sk, copy)) |
556 | !sk_stream_mem_schedule(sk, copy, 0)) | ||
557 | goto wait_for_memory; | 556 | goto wait_for_memory; |
558 | 557 | ||
559 | if (can_coalesce) { | 558 | if (can_coalesce) { |
@@ -770,19 +769,23 @@ new_segment: | |||
770 | if (off == PAGE_SIZE) { | 769 | if (off == PAGE_SIZE) { |
771 | put_page(page); | 770 | put_page(page); |
772 | TCP_PAGE(sk) = page = NULL; | 771 | TCP_PAGE(sk) = page = NULL; |
772 | off = 0; | ||
773 | } | 773 | } |
774 | } | 774 | } else |
775 | off = 0; | ||
776 | |||
777 | if (copy > PAGE_SIZE - off) | ||
778 | copy = PAGE_SIZE - off; | ||
779 | |||
780 | if (!sk_stream_wmem_schedule(sk, copy)) | ||
781 | goto wait_for_memory; | ||
775 | 782 | ||
776 | if (!page) { | 783 | if (!page) { |
777 | /* Allocate new cache page. */ | 784 | /* Allocate new cache page. */ |
778 | if (!(page = sk_stream_alloc_page(sk))) | 785 | if (!(page = sk_stream_alloc_page(sk))) |
779 | goto wait_for_memory; | 786 | goto wait_for_memory; |
780 | off = 0; | ||
781 | } | 787 | } |
782 | 788 | ||
783 | if (copy > PAGE_SIZE - off) | ||
784 | copy = PAGE_SIZE - off; | ||
785 | |||
786 | /* Time to copy data. We are close to | 789 | /* Time to copy data. We are close to |
787 | * the end! */ | 790 | * the end! */ |
788 | err = skb_copy_to_page(sk, from, skb, page, | 791 | err = skb_copy_to_page(sk, from, skb, page, |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 1afb080bdf0c..29222b964951 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -923,14 +923,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
923 | int flag = 0; | 923 | int flag = 0; |
924 | int i; | 924 | int i; |
925 | 925 | ||
926 | /* So, SACKs for already sent large segments will be lost. | ||
927 | * Not good, but alternative is to resegment the queue. */ | ||
928 | if (sk->sk_route_caps & NETIF_F_TSO) { | ||
929 | sk->sk_route_caps &= ~NETIF_F_TSO; | ||
930 | sock_set_flag(sk, SOCK_NO_LARGESEND); | ||
931 | tp->mss_cache = tp->mss_cache; | ||
932 | } | ||
933 | |||
934 | if (!tp->sacked_out) | 926 | if (!tp->sacked_out) |
935 | tp->fackets_out = 0; | 927 | tp->fackets_out = 0; |
936 | prior_fackets = tp->fackets_out; | 928 | prior_fackets = tp->fackets_out; |
@@ -978,20 +970,40 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
978 | flag |= FLAG_DATA_LOST; | 970 | flag |= FLAG_DATA_LOST; |
979 | 971 | ||
980 | sk_stream_for_retrans_queue(skb, sk) { | 972 | sk_stream_for_retrans_queue(skb, sk) { |
981 | u8 sacked = TCP_SKB_CB(skb)->sacked; | 973 | int in_sack, pcount; |
982 | int in_sack; | 974 | u8 sacked; |
983 | 975 | ||
984 | /* The retransmission queue is always in order, so | 976 | /* The retransmission queue is always in order, so |
985 | * we can short-circuit the walk early. | 977 | * we can short-circuit the walk early. |
986 | */ | 978 | */ |
987 | if(!before(TCP_SKB_CB(skb)->seq, end_seq)) | 979 | if (!before(TCP_SKB_CB(skb)->seq, end_seq)) |
988 | break; | 980 | break; |
989 | 981 | ||
990 | fack_count += tcp_skb_pcount(skb); | 982 | pcount = tcp_skb_pcount(skb); |
983 | |||
984 | if (pcount > 1 && | ||
985 | (after(start_seq, TCP_SKB_CB(skb)->seq) || | ||
986 | before(end_seq, TCP_SKB_CB(skb)->end_seq))) { | ||
987 | unsigned int pkt_len; | ||
988 | |||
989 | if (after(start_seq, TCP_SKB_CB(skb)->seq)) | ||
990 | pkt_len = (start_seq - | ||
991 | TCP_SKB_CB(skb)->seq); | ||
992 | else | ||
993 | pkt_len = (end_seq - | ||
994 | TCP_SKB_CB(skb)->seq); | ||
995 | if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->tso_size)) | ||
996 | break; | ||
997 | pcount = tcp_skb_pcount(skb); | ||
998 | } | ||
999 | |||
1000 | fack_count += pcount; | ||
991 | 1001 | ||
992 | in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && | 1002 | in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && |
993 | !before(end_seq, TCP_SKB_CB(skb)->end_seq); | 1003 | !before(end_seq, TCP_SKB_CB(skb)->end_seq); |
994 | 1004 | ||
1005 | sacked = TCP_SKB_CB(skb)->sacked; | ||
1006 | |||
995 | /* Account D-SACK for retransmitted packet. */ | 1007 | /* Account D-SACK for retransmitted packet. */ |
996 | if ((dup_sack && in_sack) && | 1008 | if ((dup_sack && in_sack) && |
997 | (sacked & TCPCB_RETRANS) && | 1009 | (sacked & TCPCB_RETRANS) && |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 75b68116682a..6094db5e11be 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -428,11 +428,11 @@ static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb, unsigned | |||
428 | * packet to the list. This won't be called frequently, I hope. | 428 | * packet to the list. This won't be called frequently, I hope. |
429 | * Remember, these are still headerless SKBs at this point. | 429 | * Remember, these are still headerless SKBs at this point. |
430 | */ | 430 | */ |
431 | static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss_now) | 431 | int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss_now) |
432 | { | 432 | { |
433 | struct tcp_sock *tp = tcp_sk(sk); | 433 | struct tcp_sock *tp = tcp_sk(sk); |
434 | struct sk_buff *buff; | 434 | struct sk_buff *buff; |
435 | int nsize; | 435 | int nsize, old_factor; |
436 | u16 flags; | 436 | u16 flags; |
437 | 437 | ||
438 | nsize = skb_headlen(skb) - len; | 438 | nsize = skb_headlen(skb) - len; |
@@ -490,18 +490,29 @@ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned | |||
490 | tp->left_out -= tcp_skb_pcount(skb); | 490 | tp->left_out -= tcp_skb_pcount(skb); |
491 | } | 491 | } |
492 | 492 | ||
493 | old_factor = tcp_skb_pcount(skb); | ||
494 | |||
493 | /* Fix up tso_factor for both original and new SKB. */ | 495 | /* Fix up tso_factor for both original and new SKB. */ |
494 | tcp_set_skb_tso_segs(sk, skb, mss_now); | 496 | tcp_set_skb_tso_segs(sk, skb, mss_now); |
495 | tcp_set_skb_tso_segs(sk, buff, mss_now); | 497 | tcp_set_skb_tso_segs(sk, buff, mss_now); |
496 | 498 | ||
497 | if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) { | 499 | /* If this packet has been sent out already, we must |
498 | tp->lost_out += tcp_skb_pcount(skb); | 500 | * adjust the various packet counters. |
499 | tp->left_out += tcp_skb_pcount(skb); | 501 | */ |
500 | } | 502 | if (after(tp->snd_nxt, TCP_SKB_CB(buff)->end_seq)) { |
503 | int diff = old_factor - tcp_skb_pcount(skb) - | ||
504 | tcp_skb_pcount(buff); | ||
501 | 505 | ||
502 | if (TCP_SKB_CB(buff)->sacked&TCPCB_LOST) { | 506 | tp->packets_out -= diff; |
503 | tp->lost_out += tcp_skb_pcount(buff); | 507 | if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) { |
504 | tp->left_out += tcp_skb_pcount(buff); | 508 | tp->lost_out -= diff; |
509 | tp->left_out -= diff; | ||
510 | } | ||
511 | if (diff > 0) { | ||
512 | tp->fackets_out -= diff; | ||
513 | if ((int)tp->fackets_out < 0) | ||
514 | tp->fackets_out = 0; | ||
515 | } | ||
505 | } | 516 | } |
506 | 517 | ||
507 | /* Link BUFF into the send queue. */ | 518 | /* Link BUFF into the send queue. */ |
@@ -1350,12 +1361,6 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) | |||
1350 | if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) { | 1361 | if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) { |
1351 | if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) | 1362 | if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) |
1352 | BUG(); | 1363 | BUG(); |
1353 | |||
1354 | if (sk->sk_route_caps & NETIF_F_TSO) { | ||
1355 | sk->sk_route_caps &= ~NETIF_F_TSO; | ||
1356 | sock_set_flag(sk, SOCK_NO_LARGESEND); | ||
1357 | } | ||
1358 | |||
1359 | if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq)) | 1364 | if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq)) |
1360 | return -ENOMEM; | 1365 | return -ENOMEM; |
1361 | } | 1366 | } |
@@ -1370,22 +1375,8 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) | |||
1370 | return -EAGAIN; | 1375 | return -EAGAIN; |
1371 | 1376 | ||
1372 | if (skb->len > cur_mss) { | 1377 | if (skb->len > cur_mss) { |
1373 | int old_factor = tcp_skb_pcount(skb); | ||
1374 | int diff; | ||
1375 | |||
1376 | if (tcp_fragment(sk, skb, cur_mss, cur_mss)) | 1378 | if (tcp_fragment(sk, skb, cur_mss, cur_mss)) |
1377 | return -ENOMEM; /* We'll try again later. */ | 1379 | return -ENOMEM; /* We'll try again later. */ |
1378 | |||
1379 | /* New SKB created, account for it. */ | ||
1380 | diff = old_factor - tcp_skb_pcount(skb) - | ||
1381 | tcp_skb_pcount(skb->next); | ||
1382 | tp->packets_out -= diff; | ||
1383 | |||
1384 | if (diff > 0) { | ||
1385 | tp->fackets_out -= diff; | ||
1386 | if ((int)tp->fackets_out < 0) | ||
1387 | tp->fackets_out = 0; | ||
1388 | } | ||
1389 | } | 1380 | } |
1390 | 1381 | ||
1391 | /* Collapse two adjacent packets if worthwhile and we can. */ | 1382 | /* Collapse two adjacent packets if worthwhile and we can. */ |
@@ -1993,12 +1984,6 @@ int tcp_write_wakeup(struct sock *sk) | |||
1993 | TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; | 1984 | TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; |
1994 | if (tcp_fragment(sk, skb, seg_size, mss)) | 1985 | if (tcp_fragment(sk, skb, seg_size, mss)) |
1995 | return -1; | 1986 | return -1; |
1996 | /* SWS override triggered forced fragmentation. | ||
1997 | * Disable TSO, the connection is too sick. */ | ||
1998 | if (sk->sk_route_caps & NETIF_F_TSO) { | ||
1999 | sock_set_flag(sk, SOCK_NO_LARGESEND); | ||
2000 | sk->sk_route_caps &= ~NETIF_F_TSO; | ||
2001 | } | ||
2002 | } else if (!tcp_skb_pcount(skb)) | 1987 | } else if (!tcp_skb_pcount(skb)) |
2003 | tcp_set_skb_tso_segs(sk, skb, mss); | 1988 | tcp_set_skb_tso_segs(sk, skb, mss); |
2004 | 1989 | ||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 937ad32db77c..6d6fb74f3b52 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -3593,10 +3593,8 @@ void __exit addrconf_cleanup(void) | |||
3593 | rtnl_unlock(); | 3593 | rtnl_unlock(); |
3594 | 3594 | ||
3595 | #ifdef CONFIG_IPV6_PRIVACY | 3595 | #ifdef CONFIG_IPV6_PRIVACY |
3596 | if (likely(md5_tfm != NULL)) { | 3596 | crypto_free_tfm(md5_tfm); |
3597 | crypto_free_tfm(md5_tfm); | 3597 | md5_tfm = NULL; |
3598 | md5_tfm = NULL; | ||
3599 | } | ||
3600 | #endif | 3598 | #endif |
3601 | 3599 | ||
3602 | #ifdef CONFIG_PROC_FS | 3600 | #ifdef CONFIG_PROC_FS |
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 0ebfad907a03..f3629730eb15 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
@@ -401,10 +401,8 @@ static int ah6_init_state(struct xfrm_state *x) | |||
401 | 401 | ||
402 | error: | 402 | error: |
403 | if (ahp) { | 403 | if (ahp) { |
404 | if (ahp->work_icv) | 404 | kfree(ahp->work_icv); |
405 | kfree(ahp->work_icv); | 405 | crypto_free_tfm(ahp->tfm); |
406 | if (ahp->tfm) | ||
407 | crypto_free_tfm(ahp->tfm); | ||
408 | kfree(ahp); | 406 | kfree(ahp); |
409 | } | 407 | } |
410 | return -EINVAL; | 408 | return -EINVAL; |
@@ -417,14 +415,10 @@ static void ah6_destroy(struct xfrm_state *x) | |||
417 | if (!ahp) | 415 | if (!ahp) |
418 | return; | 416 | return; |
419 | 417 | ||
420 | if (ahp->work_icv) { | 418 | kfree(ahp->work_icv); |
421 | kfree(ahp->work_icv); | 419 | ahp->work_icv = NULL; |
422 | ahp->work_icv = NULL; | 420 | crypto_free_tfm(ahp->tfm); |
423 | } | 421 | ahp->tfm = NULL; |
424 | if (ahp->tfm) { | ||
425 | crypto_free_tfm(ahp->tfm); | ||
426 | ahp->tfm = NULL; | ||
427 | } | ||
428 | kfree(ahp); | 422 | kfree(ahp); |
429 | } | 423 | } |
430 | 424 | ||
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index e8bff9d3d96c..9b27460f0cc7 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
@@ -276,22 +276,14 @@ static void esp6_destroy(struct xfrm_state *x) | |||
276 | if (!esp) | 276 | if (!esp) |
277 | return; | 277 | return; |
278 | 278 | ||
279 | if (esp->conf.tfm) { | 279 | crypto_free_tfm(esp->conf.tfm); |
280 | crypto_free_tfm(esp->conf.tfm); | 280 | esp->conf.tfm = NULL; |
281 | esp->conf.tfm = NULL; | 281 | kfree(esp->conf.ivec); |
282 | } | 282 | esp->conf.ivec = NULL; |
283 | if (esp->conf.ivec) { | 283 | crypto_free_tfm(esp->auth.tfm); |
284 | kfree(esp->conf.ivec); | 284 | esp->auth.tfm = NULL; |
285 | esp->conf.ivec = NULL; | 285 | kfree(esp->auth.work_icv); |
286 | } | 286 | esp->auth.work_icv = NULL; |
287 | if (esp->auth.tfm) { | ||
288 | crypto_free_tfm(esp->auth.tfm); | ||
289 | esp->auth.tfm = NULL; | ||
290 | } | ||
291 | if (esp->auth.work_icv) { | ||
292 | kfree(esp->auth.work_icv); | ||
293 | esp->auth.work_icv = NULL; | ||
294 | } | ||
295 | kfree(esp); | 287 | kfree(esp); |
296 | } | 288 | } |
297 | 289 | ||
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 5176fc655ea9..fa8f1bb0aa52 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -549,7 +549,7 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info) | |||
549 | read_lock(&raw_v6_lock); | 549 | read_lock(&raw_v6_lock); |
550 | if ((sk = sk_head(&raw_v6_htable[hash])) != NULL) { | 550 | if ((sk = sk_head(&raw_v6_htable[hash])) != NULL) { |
551 | while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, | 551 | while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, |
552 | skb->dev->ifindex))) { | 552 | IP6CB(skb)->iif))) { |
553 | rawv6_err(sk, skb, NULL, type, code, inner_offset, info); | 553 | rawv6_err(sk, skb, NULL, type, code, inner_offset, info); |
554 | sk = sk_next(sk); | 554 | sk = sk_next(sk); |
555 | } | 555 | } |
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 135383ef538f..85bfbc69b2c3 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c | |||
@@ -341,8 +341,7 @@ static void ipcomp6_free_tfms(struct crypto_tfm **tfms) | |||
341 | 341 | ||
342 | for_each_cpu(cpu) { | 342 | for_each_cpu(cpu) { |
343 | struct crypto_tfm *tfm = *per_cpu_ptr(tfms, cpu); | 343 | struct crypto_tfm *tfm = *per_cpu_ptr(tfms, cpu); |
344 | if (tfm) | 344 | crypto_free_tfm(tfm); |
345 | crypto_free_tfm(tfm); | ||
346 | } | 345 | } |
347 | free_percpu(tfms); | 346 | free_percpu(tfms); |
348 | } | 347 | } |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 7a5863298f3f..ed3a76b30fd9 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -166,7 +166,7 @@ int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | |||
166 | if (sk == NULL) | 166 | if (sk == NULL) |
167 | goto out; | 167 | goto out; |
168 | 168 | ||
169 | sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, skb->dev->ifindex); | 169 | sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); |
170 | 170 | ||
171 | while (sk) { | 171 | while (sk) { |
172 | delivered = 1; | 172 | delivered = 1; |
@@ -178,7 +178,7 @@ int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | |||
178 | rawv6_rcv(sk, clone); | 178 | rawv6_rcv(sk, clone); |
179 | } | 179 | } |
180 | sk = __raw_v6_lookup(sk_next(sk), nexthdr, daddr, saddr, | 180 | sk = __raw_v6_lookup(sk_next(sk), nexthdr, daddr, saddr, |
181 | skb->dev->ifindex); | 181 | IP6CB(skb)->iif); |
182 | } | 182 | } |
183 | out: | 183 | out: |
184 | read_unlock(&raw_v6_lock); | 184 | read_unlock(&raw_v6_lock); |
diff --git a/net/irda/irlan/irlan_filter.c b/net/irda/irlan/irlan_filter.c index 343c5d4a1a1d..ca7d358dab52 100644 --- a/net/irda/irlan/irlan_filter.c +++ b/net/irda/irlan/irlan_filter.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/seq_file.h> | 27 | #include <linux/seq_file.h> |
28 | 28 | ||
29 | #include <net/irda/irlan_common.h> | 29 | #include <net/irda/irlan_common.h> |
30 | #include <net/irda/irlan_filter.h> | ||
30 | 31 | ||
31 | /* | 32 | /* |
32 | * Function irlan_filter_request (self, skb) | 33 | * Function irlan_filter_request (self, skb) |
diff --git a/net/irda/qos.c b/net/irda/qos.c index df732d56cc57..ddfb5c502a90 100644 --- a/net/irda/qos.c +++ b/net/irda/qos.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <net/irda/parameters.h> | 37 | #include <net/irda/parameters.h> |
38 | #include <net/irda/qos.h> | 38 | #include <net/irda/qos.h> |
39 | #include <net/irda/irlap.h> | 39 | #include <net/irda/irlap.h> |
40 | #include <net/irda/irlap_frame.h> | ||
40 | 41 | ||
41 | /* | 42 | /* |
42 | * Maximum values of the baud rate we negociate with the other end. | 43 | * Maximum values of the baud rate we negociate with the other end. |
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index e089f17bb803..49a3900e3d32 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c | |||
@@ -344,14 +344,14 @@ static void nfnetlink_rcv(struct sock *sk, int len) | |||
344 | } while(nfnl && nfnl->sk_receive_queue.qlen); | 344 | } while(nfnl && nfnl->sk_receive_queue.qlen); |
345 | } | 345 | } |
346 | 346 | ||
347 | void __exit nfnetlink_exit(void) | 347 | static void __exit nfnetlink_exit(void) |
348 | { | 348 | { |
349 | printk("Removing netfilter NETLINK layer.\n"); | 349 | printk("Removing netfilter NETLINK layer.\n"); |
350 | sock_release(nfnl->sk_socket); | 350 | sock_release(nfnl->sk_socket); |
351 | return; | 351 | return; |
352 | } | 352 | } |
353 | 353 | ||
354 | int __init nfnetlink_init(void) | 354 | static int __init nfnetlink_init(void) |
355 | { | 355 | { |
356 | printk("Netfilter messages via NETLINK v%s.\n", nfversion); | 356 | printk("Netfilter messages via NETLINK v%s.\n", nfversion); |
357 | 357 | ||
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index e3a5285329af..f81fe8c52e99 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c | |||
@@ -76,17 +76,6 @@ typedef int (*nfqnl_cmpfn)(struct nfqnl_queue_entry *, unsigned long); | |||
76 | 76 | ||
77 | static DEFINE_RWLOCK(instances_lock); | 77 | static DEFINE_RWLOCK(instances_lock); |
78 | 78 | ||
79 | u_int64_t htonll(u_int64_t in) | ||
80 | { | ||
81 | u_int64_t out; | ||
82 | int i; | ||
83 | |||
84 | for (i = 0; i < sizeof(u_int64_t); i++) | ||
85 | ((u_int8_t *)&out)[sizeof(u_int64_t)-1] = ((u_int8_t *)&in)[i]; | ||
86 | |||
87 | return out; | ||
88 | } | ||
89 | |||
90 | #define INSTANCE_BUCKETS 16 | 79 | #define INSTANCE_BUCKETS 16 |
91 | static struct hlist_head instance_table[INSTANCE_BUCKETS]; | 80 | static struct hlist_head instance_table[INSTANCE_BUCKETS]; |
92 | 81 | ||
@@ -382,6 +371,12 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
382 | break; | 371 | break; |
383 | 372 | ||
384 | case NFQNL_COPY_PACKET: | 373 | case NFQNL_COPY_PACKET: |
374 | if (entry->skb->ip_summed == CHECKSUM_HW && | ||
375 | (*errp = skb_checksum_help(entry->skb, | ||
376 | entry->info->outdev == NULL))) { | ||
377 | spin_unlock_bh(&queue->lock); | ||
378 | return NULL; | ||
379 | } | ||
385 | if (queue->copy_range == 0 | 380 | if (queue->copy_range == 0 |
386 | || queue->copy_range > entry->skb->len) | 381 | || queue->copy_range > entry->skb->len) |
387 | data_len = entry->skb->len; | 382 | data_len = entry->skb->len; |
@@ -497,8 +492,8 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
497 | if (entry->skb->tstamp.off_sec) { | 492 | if (entry->skb->tstamp.off_sec) { |
498 | struct nfqnl_msg_packet_timestamp ts; | 493 | struct nfqnl_msg_packet_timestamp ts; |
499 | 494 | ||
500 | ts.sec = htonll(skb_tv_base.tv_sec + entry->skb->tstamp.off_sec); | 495 | ts.sec = cpu_to_be64(skb_tv_base.tv_sec + entry->skb->tstamp.off_sec); |
501 | ts.usec = htonll(skb_tv_base.tv_usec + entry->skb->tstamp.off_usec); | 496 | ts.usec = cpu_to_be64(skb_tv_base.tv_usec + entry->skb->tstamp.off_usec); |
502 | 497 | ||
503 | NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts); | 498 | NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts); |
504 | } | 499 | } |
@@ -647,7 +642,7 @@ nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e) | |||
647 | if (!skb_make_writable(&e->skb, data_len)) | 642 | if (!skb_make_writable(&e->skb, data_len)) |
648 | return -ENOMEM; | 643 | return -ENOMEM; |
649 | memcpy(e->skb->data, data, data_len); | 644 | memcpy(e->skb->data, data, data_len); |
650 | 645 | e->skb->ip_summed = CHECKSUM_NONE; | |
651 | return 0; | 646 | return 0; |
652 | } | 647 | } |
653 | 648 | ||
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 62435ffc6184..a64e1d5ce3ca 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -398,24 +398,13 @@ static int netlink_create(struct socket *sock, int protocol) | |||
398 | if (nl_table[protocol].registered && | 398 | if (nl_table[protocol].registered && |
399 | try_module_get(nl_table[protocol].module)) | 399 | try_module_get(nl_table[protocol].module)) |
400 | module = nl_table[protocol].module; | 400 | module = nl_table[protocol].module; |
401 | else | ||
402 | err = -EPROTONOSUPPORT; | ||
403 | groups = nl_table[protocol].groups; | 401 | groups = nl_table[protocol].groups; |
404 | netlink_unlock_table(); | 402 | netlink_unlock_table(); |
405 | 403 | ||
406 | if (err || (err = __netlink_create(sock, protocol) < 0)) | 404 | if ((err = __netlink_create(sock, protocol) < 0)) |
407 | goto out_module; | 405 | goto out_module; |
408 | 406 | ||
409 | nlk = nlk_sk(sock->sk); | 407 | nlk = nlk_sk(sock->sk); |
410 | |||
411 | nlk->groups = kmalloc(NLGRPSZ(groups), GFP_KERNEL); | ||
412 | if (nlk->groups == NULL) { | ||
413 | err = -ENOMEM; | ||
414 | goto out_module; | ||
415 | } | ||
416 | memset(nlk->groups, 0, NLGRPSZ(groups)); | ||
417 | nlk->ngroups = groups; | ||
418 | |||
419 | nlk->module = module; | 408 | nlk->module = module; |
420 | out: | 409 | out: |
421 | return err; | 410 | return err; |
@@ -534,6 +523,29 @@ netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions) | |||
534 | nlk->subscriptions = subscriptions; | 523 | nlk->subscriptions = subscriptions; |
535 | } | 524 | } |
536 | 525 | ||
526 | static int netlink_alloc_groups(struct sock *sk) | ||
527 | { | ||
528 | struct netlink_sock *nlk = nlk_sk(sk); | ||
529 | unsigned int groups; | ||
530 | int err = 0; | ||
531 | |||
532 | netlink_lock_table(); | ||
533 | groups = nl_table[sk->sk_protocol].groups; | ||
534 | if (!nl_table[sk->sk_protocol].registered) | ||
535 | err = -ENOENT; | ||
536 | netlink_unlock_table(); | ||
537 | |||
538 | if (err) | ||
539 | return err; | ||
540 | |||
541 | nlk->groups = kmalloc(NLGRPSZ(groups), GFP_KERNEL); | ||
542 | if (nlk->groups == NULL) | ||
543 | return -ENOMEM; | ||
544 | memset(nlk->groups, 0, NLGRPSZ(groups)); | ||
545 | nlk->ngroups = groups; | ||
546 | return 0; | ||
547 | } | ||
548 | |||
537 | static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | 549 | static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) |
538 | { | 550 | { |
539 | struct sock *sk = sock->sk; | 551 | struct sock *sk = sock->sk; |
@@ -545,8 +557,15 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len | |||
545 | return -EINVAL; | 557 | return -EINVAL; |
546 | 558 | ||
547 | /* Only superuser is allowed to listen multicasts */ | 559 | /* Only superuser is allowed to listen multicasts */ |
548 | if (nladdr->nl_groups && !netlink_capable(sock, NL_NONROOT_RECV)) | 560 | if (nladdr->nl_groups) { |
549 | return -EPERM; | 561 | if (!netlink_capable(sock, NL_NONROOT_RECV)) |
562 | return -EPERM; | ||
563 | if (nlk->groups == NULL) { | ||
564 | err = netlink_alloc_groups(sk); | ||
565 | if (err) | ||
566 | return err; | ||
567 | } | ||
568 | } | ||
550 | 569 | ||
551 | if (nlk->pid) { | 570 | if (nlk->pid) { |
552 | if (nladdr->nl_pid != nlk->pid) | 571 | if (nladdr->nl_pid != nlk->pid) |
@@ -559,7 +578,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len | |||
559 | return err; | 578 | return err; |
560 | } | 579 | } |
561 | 580 | ||
562 | if (!nladdr->nl_groups && !(u32)nlk->groups[0]) | 581 | if (!nladdr->nl_groups && (nlk->groups == NULL || !(u32)nlk->groups[0])) |
563 | return 0; | 582 | return 0; |
564 | 583 | ||
565 | netlink_table_grab(); | 584 | netlink_table_grab(); |
@@ -620,7 +639,7 @@ static int netlink_getname(struct socket *sock, struct sockaddr *addr, int *addr | |||
620 | nladdr->nl_groups = netlink_group_mask(nlk->dst_group); | 639 | nladdr->nl_groups = netlink_group_mask(nlk->dst_group); |
621 | } else { | 640 | } else { |
622 | nladdr->nl_pid = nlk->pid; | 641 | nladdr->nl_pid = nlk->pid; |
623 | nladdr->nl_groups = nlk->groups[0]; | 642 | nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0; |
624 | } | 643 | } |
625 | return 0; | 644 | return 0; |
626 | } | 645 | } |
@@ -976,6 +995,11 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, | |||
976 | 995 | ||
977 | if (!netlink_capable(sock, NL_NONROOT_RECV)) | 996 | if (!netlink_capable(sock, NL_NONROOT_RECV)) |
978 | return -EPERM; | 997 | return -EPERM; |
998 | if (nlk->groups == NULL) { | ||
999 | err = netlink_alloc_groups(sk); | ||
1000 | if (err) | ||
1001 | return err; | ||
1002 | } | ||
979 | if (!val || val - 1 >= nlk->ngroups) | 1003 | if (!val || val - 1 >= nlk->ngroups) |
980 | return -EINVAL; | 1004 | return -EINVAL; |
981 | netlink_table_grab(); | 1005 | netlink_table_grab(); |
@@ -1483,8 +1507,7 @@ static int netlink_seq_show(struct seq_file *seq, void *v) | |||
1483 | s, | 1507 | s, |
1484 | s->sk_protocol, | 1508 | s->sk_protocol, |
1485 | nlk->pid, | 1509 | nlk->pid, |
1486 | nlk->flags & NETLINK_KERNEL_SOCKET ? | 1510 | nlk->groups ? (u32)nlk->groups[0] : 0, |
1487 | 0 : (unsigned int)nlk->groups[0], | ||
1488 | atomic_read(&s->sk_rmem_alloc), | 1511 | atomic_read(&s->sk_rmem_alloc), |
1489 | atomic_read(&s->sk_wmem_alloc), | 1512 | atomic_read(&s->sk_wmem_alloc), |
1490 | nlk->cb, | 1513 | nlk->cb, |
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 4b53de982114..f4578c759ffc 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c | |||
@@ -1261,6 +1261,7 @@ static int nr_info_show(struct seq_file *seq, void *v) | |||
1261 | struct net_device *dev; | 1261 | struct net_device *dev; |
1262 | struct nr_sock *nr; | 1262 | struct nr_sock *nr; |
1263 | const char *devname; | 1263 | const char *devname; |
1264 | char buf[11]; | ||
1264 | 1265 | ||
1265 | if (v == SEQ_START_TOKEN) | 1266 | if (v == SEQ_START_TOKEN) |
1266 | seq_puts(seq, | 1267 | seq_puts(seq, |
@@ -1276,11 +1277,11 @@ static int nr_info_show(struct seq_file *seq, void *v) | |||
1276 | else | 1277 | else |
1277 | devname = dev->name; | 1278 | devname = dev->name; |
1278 | 1279 | ||
1279 | seq_printf(seq, "%-9s ", ax2asc(&nr->user_addr)); | 1280 | seq_printf(seq, "%-9s ", ax2asc(buf, &nr->user_addr)); |
1280 | seq_printf(seq, "%-9s ", ax2asc(&nr->dest_addr)); | 1281 | seq_printf(seq, "%-9s ", ax2asc(buf, &nr->dest_addr)); |
1281 | seq_printf(seq, | 1282 | seq_printf(seq, |
1282 | "%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d %ld\n", | 1283 | "%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d %ld\n", |
1283 | ax2asc(&nr->source_addr), | 1284 | ax2asc(buf, &nr->source_addr), |
1284 | devname, | 1285 | devname, |
1285 | nr->my_index, | 1286 | nr->my_index, |
1286 | nr->my_id, | 1287 | nr->my_id, |
diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c index 7a86b36cba50..b3b9097c87c7 100644 --- a/net/netrom/nr_route.c +++ b/net/netrom/nr_route.c | |||
@@ -881,6 +881,7 @@ static void nr_node_stop(struct seq_file *seq, void *v) | |||
881 | 881 | ||
882 | static int nr_node_show(struct seq_file *seq, void *v) | 882 | static int nr_node_show(struct seq_file *seq, void *v) |
883 | { | 883 | { |
884 | char buf[11]; | ||
884 | int i; | 885 | int i; |
885 | 886 | ||
886 | if (v == SEQ_START_TOKEN) | 887 | if (v == SEQ_START_TOKEN) |
@@ -890,7 +891,7 @@ static int nr_node_show(struct seq_file *seq, void *v) | |||
890 | struct nr_node *nr_node = v; | 891 | struct nr_node *nr_node = v; |
891 | nr_node_lock(nr_node); | 892 | nr_node_lock(nr_node); |
892 | seq_printf(seq, "%-9s %-7s %d %d", | 893 | seq_printf(seq, "%-9s %-7s %d %d", |
893 | ax2asc(&nr_node->callsign), | 894 | ax2asc(buf, &nr_node->callsign), |
894 | (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic, | 895 | (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic, |
895 | nr_node->which + 1, | 896 | nr_node->which + 1, |
896 | nr_node->count); | 897 | nr_node->count); |
@@ -964,6 +965,7 @@ static void nr_neigh_stop(struct seq_file *seq, void *v) | |||
964 | 965 | ||
965 | static int nr_neigh_show(struct seq_file *seq, void *v) | 966 | static int nr_neigh_show(struct seq_file *seq, void *v) |
966 | { | 967 | { |
968 | char buf[11]; | ||
967 | int i; | 969 | int i; |
968 | 970 | ||
969 | if (v == SEQ_START_TOKEN) | 971 | if (v == SEQ_START_TOKEN) |
@@ -973,7 +975,7 @@ static int nr_neigh_show(struct seq_file *seq, void *v) | |||
973 | 975 | ||
974 | seq_printf(seq, "%05d %-9s %-4s %3d %d %3d %3d", | 976 | seq_printf(seq, "%05d %-9s %-4s %3d %d %3d %3d", |
975 | nr_neigh->number, | 977 | nr_neigh->number, |
976 | ax2asc(&nr_neigh->callsign), | 978 | ax2asc(buf, &nr_neigh->callsign), |
977 | nr_neigh->dev ? nr_neigh->dev->name : "???", | 979 | nr_neigh->dev ? nr_neigh->dev->name : "???", |
978 | nr_neigh->quality, | 980 | nr_neigh->quality, |
979 | nr_neigh->locked, | 981 | nr_neigh->locked, |
@@ -983,7 +985,7 @@ static int nr_neigh_show(struct seq_file *seq, void *v) | |||
983 | if (nr_neigh->digipeat != NULL) { | 985 | if (nr_neigh->digipeat != NULL) { |
984 | for (i = 0; i < nr_neigh->digipeat->ndigi; i++) | 986 | for (i = 0; i < nr_neigh->digipeat->ndigi; i++) |
985 | seq_printf(seq, " %s", | 987 | seq_printf(seq, " %s", |
986 | ax2asc(&nr_neigh->digipeat->calls[i])); | 988 | ax2asc(buf, &nr_neigh->digipeat->calls[i])); |
987 | } | 989 | } |
988 | 990 | ||
989 | seq_puts(seq, "\n"); | 991 | seq_puts(seq, "\n"); |
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index ba997095f08f..8690f171c1ef 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -1535,8 +1535,7 @@ static unsigned int packet_poll(struct file * file, struct socket *sock, | |||
1535 | static void packet_mm_open(struct vm_area_struct *vma) | 1535 | static void packet_mm_open(struct vm_area_struct *vma) |
1536 | { | 1536 | { |
1537 | struct file *file = vma->vm_file; | 1537 | struct file *file = vma->vm_file; |
1538 | struct inode *inode = file->f_dentry->d_inode; | 1538 | struct socket * sock = file->private_data; |
1539 | struct socket * sock = SOCKET_I(inode); | ||
1540 | struct sock *sk = sock->sk; | 1539 | struct sock *sk = sock->sk; |
1541 | 1540 | ||
1542 | if (sk) | 1541 | if (sk) |
@@ -1546,8 +1545,7 @@ static void packet_mm_open(struct vm_area_struct *vma) | |||
1546 | static void packet_mm_close(struct vm_area_struct *vma) | 1545 | static void packet_mm_close(struct vm_area_struct *vma) |
1547 | { | 1546 | { |
1548 | struct file *file = vma->vm_file; | 1547 | struct file *file = vma->vm_file; |
1549 | struct inode *inode = file->f_dentry->d_inode; | 1548 | struct socket * sock = file->private_data; |
1550 | struct socket * sock = SOCKET_I(inode); | ||
1551 | struct sock *sk = sock->sk; | 1549 | struct sock *sk = sock->sk; |
1552 | 1550 | ||
1553 | if (sk) | 1551 | if (sk) |
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index c6e59f84c3ae..3077878ed4f0 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c | |||
@@ -1363,6 +1363,8 @@ static void rose_info_stop(struct seq_file *seq, void *v) | |||
1363 | 1363 | ||
1364 | static int rose_info_show(struct seq_file *seq, void *v) | 1364 | static int rose_info_show(struct seq_file *seq, void *v) |
1365 | { | 1365 | { |
1366 | char buf[11]; | ||
1367 | |||
1366 | if (v == SEQ_START_TOKEN) | 1368 | if (v == SEQ_START_TOKEN) |
1367 | seq_puts(seq, | 1369 | seq_puts(seq, |
1368 | "dest_addr dest_call src_addr src_call dev lci neigh st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q inode\n"); | 1370 | "dest_addr dest_call src_addr src_call dev lci neigh st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q inode\n"); |
@@ -1380,12 +1382,12 @@ static int rose_info_show(struct seq_file *seq, void *v) | |||
1380 | 1382 | ||
1381 | seq_printf(seq, "%-10s %-9s ", | 1383 | seq_printf(seq, "%-10s %-9s ", |
1382 | rose2asc(&rose->dest_addr), | 1384 | rose2asc(&rose->dest_addr), |
1383 | ax2asc(&rose->dest_call)); | 1385 | ax2asc(buf, &rose->dest_call)); |
1384 | 1386 | ||
1385 | if (ax25cmp(&rose->source_call, &null_ax25_address) == 0) | 1387 | if (ax25cmp(&rose->source_call, &null_ax25_address) == 0) |
1386 | callsign = "??????-?"; | 1388 | callsign = "??????-?"; |
1387 | else | 1389 | else |
1388 | callsign = ax2asc(&rose->source_call); | 1390 | callsign = ax2asc(buf, &rose->source_call); |
1389 | 1391 | ||
1390 | seq_printf(seq, | 1392 | seq_printf(seq, |
1391 | "%-10s %-9s %-5s %3.3X %05d %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n", | 1393 | "%-10s %-9s %-5s %3.3X %05d %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n", |
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 4510cd7613ec..e556d92c0bc4 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c | |||
@@ -851,6 +851,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) | |||
851 | unsigned char cause, diagnostic; | 851 | unsigned char cause, diagnostic; |
852 | struct net_device *dev; | 852 | struct net_device *dev; |
853 | int len, res = 0; | 853 | int len, res = 0; |
854 | char buf[11]; | ||
854 | 855 | ||
855 | #if 0 | 856 | #if 0 |
856 | if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) | 857 | if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT) |
@@ -876,7 +877,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) | |||
876 | 877 | ||
877 | if (rose_neigh == NULL) { | 878 | if (rose_neigh == NULL) { |
878 | printk("rose_route : unknown neighbour or device %s\n", | 879 | printk("rose_route : unknown neighbour or device %s\n", |
879 | ax2asc(&ax25->dest_addr)); | 880 | ax2asc(buf, &ax25->dest_addr)); |
880 | goto out; | 881 | goto out; |
881 | } | 882 | } |
882 | 883 | ||
@@ -1178,6 +1179,7 @@ static void rose_neigh_stop(struct seq_file *seq, void *v) | |||
1178 | 1179 | ||
1179 | static int rose_neigh_show(struct seq_file *seq, void *v) | 1180 | static int rose_neigh_show(struct seq_file *seq, void *v) |
1180 | { | 1181 | { |
1182 | char buf[11]; | ||
1181 | int i; | 1183 | int i; |
1182 | 1184 | ||
1183 | if (v == SEQ_START_TOKEN) | 1185 | if (v == SEQ_START_TOKEN) |
@@ -1189,7 +1191,7 @@ static int rose_neigh_show(struct seq_file *seq, void *v) | |||
1189 | /* if (!rose_neigh->loopback) { */ | 1191 | /* if (!rose_neigh->loopback) { */ |
1190 | seq_printf(seq, "%05d %-9s %-4s %3d %3d %3s %3s %3lu %3lu", | 1192 | seq_printf(seq, "%05d %-9s %-4s %3d %3d %3s %3s %3lu %3lu", |
1191 | rose_neigh->number, | 1193 | rose_neigh->number, |
1192 | (rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(&rose_neigh->callsign), | 1194 | (rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(buf, &rose_neigh->callsign), |
1193 | rose_neigh->dev ? rose_neigh->dev->name : "???", | 1195 | rose_neigh->dev ? rose_neigh->dev->name : "???", |
1194 | rose_neigh->count, | 1196 | rose_neigh->count, |
1195 | rose_neigh->use, | 1197 | rose_neigh->use, |
@@ -1200,7 +1202,7 @@ static int rose_neigh_show(struct seq_file *seq, void *v) | |||
1200 | 1202 | ||
1201 | if (rose_neigh->digipeat != NULL) { | 1203 | if (rose_neigh->digipeat != NULL) { |
1202 | for (i = 0; i < rose_neigh->digipeat->ndigi; i++) | 1204 | for (i = 0; i < rose_neigh->digipeat->ndigi; i++) |
1203 | seq_printf(seq, " %s", ax2asc(&rose_neigh->digipeat->calls[i])); | 1205 | seq_printf(seq, " %s", ax2asc(buf, &rose_neigh->digipeat->calls[i])); |
1204 | } | 1206 | } |
1205 | 1207 | ||
1206 | seq_puts(seq, "\n"); | 1208 | seq_puts(seq, "\n"); |
@@ -1260,6 +1262,8 @@ static void rose_route_stop(struct seq_file *seq, void *v) | |||
1260 | 1262 | ||
1261 | static int rose_route_show(struct seq_file *seq, void *v) | 1263 | static int rose_route_show(struct seq_file *seq, void *v) |
1262 | { | 1264 | { |
1265 | char buf[11]; | ||
1266 | |||
1263 | if (v == SEQ_START_TOKEN) | 1267 | if (v == SEQ_START_TOKEN) |
1264 | seq_puts(seq, | 1268 | seq_puts(seq, |
1265 | "lci address callsign neigh <-> lci address callsign neigh\n"); | 1269 | "lci address callsign neigh <-> lci address callsign neigh\n"); |
@@ -1271,7 +1275,7 @@ static int rose_route_show(struct seq_file *seq, void *v) | |||
1271 | "%3.3X %-10s %-9s %05d ", | 1275 | "%3.3X %-10s %-9s %05d ", |
1272 | rose_route->lci1, | 1276 | rose_route->lci1, |
1273 | rose2asc(&rose_route->src_addr), | 1277 | rose2asc(&rose_route->src_addr), |
1274 | ax2asc(&rose_route->src_call), | 1278 | ax2asc(buf, &rose_route->src_call), |
1275 | rose_route->neigh1->number); | 1279 | rose_route->neigh1->number); |
1276 | else | 1280 | else |
1277 | seq_puts(seq, | 1281 | seq_puts(seq, |
@@ -1282,7 +1286,7 @@ static int rose_route_show(struct seq_file *seq, void *v) | |||
1282 | "%3.3X %-10s %-9s %05d\n", | 1286 | "%3.3X %-10s %-9s %05d\n", |
1283 | rose_route->lci2, | 1287 | rose_route->lci2, |
1284 | rose2asc(&rose_route->dest_addr), | 1288 | rose2asc(&rose_route->dest_addr), |
1285 | ax2asc(&rose_route->dest_call), | 1289 | ax2asc(buf, &rose_route->dest_call), |
1286 | rose_route->neigh2->number); | 1290 | rose_route->neigh2->number); |
1287 | else | 1291 | else |
1288 | seq_puts(seq, | 1292 | seq_puts(seq, |
diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c index a29a3a960fd6..02891ce2db37 100644 --- a/net/rose/rose_subr.c +++ b/net/rose/rose_subr.c | |||
@@ -400,6 +400,7 @@ static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose) | |||
400 | { | 400 | { |
401 | unsigned char *p = buffer + 1; | 401 | unsigned char *p = buffer + 1; |
402 | char *callsign; | 402 | char *callsign; |
403 | char buf[11]; | ||
403 | int len, nb; | 404 | int len, nb; |
404 | 405 | ||
405 | /* National Facilities */ | 406 | /* National Facilities */ |
@@ -456,7 +457,7 @@ static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose) | |||
456 | 457 | ||
457 | *p++ = FAC_CCITT_DEST_NSAP; | 458 | *p++ = FAC_CCITT_DEST_NSAP; |
458 | 459 | ||
459 | callsign = ax2asc(&rose->dest_call); | 460 | callsign = ax2asc(buf, &rose->dest_call); |
460 | 461 | ||
461 | *p++ = strlen(callsign) + 10; | 462 | *p++ = strlen(callsign) + 10; |
462 | *p++ = (strlen(callsign) + 9) * 2; /* ??? */ | 463 | *p++ = (strlen(callsign) + 9) * 2; /* ??? */ |
@@ -471,7 +472,7 @@ static int rose_create_facilities(unsigned char *buffer, struct rose_sock *rose) | |||
471 | 472 | ||
472 | *p++ = FAC_CCITT_SRC_NSAP; | 473 | *p++ = FAC_CCITT_SRC_NSAP; |
473 | 474 | ||
474 | callsign = ax2asc(&rose->source_call); | 475 | callsign = ax2asc(buf, &rose->source_call); |
475 | 476 | ||
476 | *p++ = strlen(callsign) + 10; | 477 | *p++ = strlen(callsign) + 10; |
477 | *p++ = (strlen(callsign) + 9) * 2; /* ??? */ | 478 | *p++ = (strlen(callsign) + 9) * 2; /* ??? */ |
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index e47ac0d1a6d6..e22ccd655965 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c | |||
@@ -193,8 +193,7 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep) | |||
193 | sctp_unhash_endpoint(ep); | 193 | sctp_unhash_endpoint(ep); |
194 | 194 | ||
195 | /* Free up the HMAC transform. */ | 195 | /* Free up the HMAC transform. */ |
196 | if (sctp_sk(ep->base.sk)->hmac) | 196 | sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac); |
197 | sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac); | ||
198 | 197 | ||
199 | /* Cleanup. */ | 198 | /* Cleanup. */ |
200 | sctp_inq_free(&ep->base.inqueue); | 199 | sctp_inq_free(&ep->base.inqueue); |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 4454afe4727e..91ec8c936913 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -4194,8 +4194,7 @@ out: | |||
4194 | sctp_release_sock(sk); | 4194 | sctp_release_sock(sk); |
4195 | return err; | 4195 | return err; |
4196 | cleanup: | 4196 | cleanup: |
4197 | if (tfm) | 4197 | sctp_crypto_free_tfm(tfm); |
4198 | sctp_crypto_free_tfm(tfm); | ||
4199 | goto out; | 4198 | goto out; |
4200 | } | 4199 | } |
4201 | 4200 | ||
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index dc4893474f18..75b28dd634fe 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c | |||
@@ -42,6 +42,7 @@ | |||
42 | */ | 42 | */ |
43 | 43 | ||
44 | #include <net/sctp/structs.h> | 44 | #include <net/sctp/structs.h> |
45 | #include <net/sctp/sctp.h> | ||
45 | #include <linux/sysctl.h> | 46 | #include <linux/sysctl.h> |
46 | 47 | ||
47 | static ctl_handler sctp_sysctl_jiffies_ms; | 48 | static ctl_handler sctp_sysctl_jiffies_ms; |
diff --git a/net/socket.c b/net/socket.c index 94fe638b4d72..e1bd5d84d7bf 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -667,7 +667,7 @@ static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, | |||
667 | } | 667 | } |
668 | iocb->private = x; | 668 | iocb->private = x; |
669 | x->kiocb = iocb; | 669 | x->kiocb = iocb; |
670 | sock = SOCKET_I(iocb->ki_filp->f_dentry->d_inode); | 670 | sock = iocb->ki_filp->private_data; |
671 | 671 | ||
672 | x->async_msg.msg_name = NULL; | 672 | x->async_msg.msg_name = NULL; |
673 | x->async_msg.msg_namelen = 0; | 673 | x->async_msg.msg_namelen = 0; |
@@ -709,7 +709,7 @@ static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, | |||
709 | } | 709 | } |
710 | iocb->private = x; | 710 | iocb->private = x; |
711 | x->kiocb = iocb; | 711 | x->kiocb = iocb; |
712 | sock = SOCKET_I(iocb->ki_filp->f_dentry->d_inode); | 712 | sock = iocb->ki_filp->private_data; |
713 | 713 | ||
714 | x->async_msg.msg_name = NULL; | 714 | x->async_msg.msg_name = NULL; |
715 | x->async_msg.msg_namelen = 0; | 715 | x->async_msg.msg_namelen = 0; |
@@ -732,7 +732,7 @@ static ssize_t sock_sendpage(struct file *file, struct page *page, | |||
732 | struct socket *sock; | 732 | struct socket *sock; |
733 | int flags; | 733 | int flags; |
734 | 734 | ||
735 | sock = SOCKET_I(file->f_dentry->d_inode); | 735 | sock = file->private_data; |
736 | 736 | ||
737 | flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT; | 737 | flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT; |
738 | if (more) | 738 | if (more) |
@@ -741,14 +741,14 @@ static ssize_t sock_sendpage(struct file *file, struct page *page, | |||
741 | return sock->ops->sendpage(sock, page, offset, size, flags); | 741 | return sock->ops->sendpage(sock, page, offset, size, flags); |
742 | } | 742 | } |
743 | 743 | ||
744 | static int sock_readv_writev(int type, struct inode * inode, | 744 | static int sock_readv_writev(int type, |
745 | struct file * file, const struct iovec * iov, | 745 | struct file * file, const struct iovec * iov, |
746 | long count, size_t size) | 746 | long count, size_t size) |
747 | { | 747 | { |
748 | struct msghdr msg; | 748 | struct msghdr msg; |
749 | struct socket *sock; | 749 | struct socket *sock; |
750 | 750 | ||
751 | sock = SOCKET_I(inode); | 751 | sock = file->private_data; |
752 | 752 | ||
753 | msg.msg_name = NULL; | 753 | msg.msg_name = NULL; |
754 | msg.msg_namelen = 0; | 754 | msg.msg_namelen = 0; |
@@ -775,7 +775,7 @@ static ssize_t sock_readv(struct file *file, const struct iovec *vector, | |||
775 | int i; | 775 | int i; |
776 | for (i = 0 ; i < count ; i++) | 776 | for (i = 0 ; i < count ; i++) |
777 | tot_len += vector[i].iov_len; | 777 | tot_len += vector[i].iov_len; |
778 | return sock_readv_writev(VERIFY_WRITE, file->f_dentry->d_inode, | 778 | return sock_readv_writev(VERIFY_WRITE, |
779 | file, vector, count, tot_len); | 779 | file, vector, count, tot_len); |
780 | } | 780 | } |
781 | 781 | ||
@@ -786,7 +786,7 @@ static ssize_t sock_writev(struct file *file, const struct iovec *vector, | |||
786 | int i; | 786 | int i; |
787 | for (i = 0 ; i < count ; i++) | 787 | for (i = 0 ; i < count ; i++) |
788 | tot_len += vector[i].iov_len; | 788 | tot_len += vector[i].iov_len; |
789 | return sock_readv_writev(VERIFY_READ, file->f_dentry->d_inode, | 789 | return sock_readv_writev(VERIFY_READ, |
790 | file, vector, count, tot_len); | 790 | file, vector, count, tot_len); |
791 | } | 791 | } |
792 | 792 | ||
@@ -840,7 +840,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
840 | void __user *argp = (void __user *)arg; | 840 | void __user *argp = (void __user *)arg; |
841 | int pid, err; | 841 | int pid, err; |
842 | 842 | ||
843 | sock = SOCKET_I(file->f_dentry->d_inode); | 843 | sock = file->private_data; |
844 | if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { | 844 | if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { |
845 | err = dev_ioctl(cmd, argp); | 845 | err = dev_ioctl(cmd, argp); |
846 | } else | 846 | } else |
@@ -939,13 +939,13 @@ static unsigned int sock_poll(struct file *file, poll_table * wait) | |||
939 | /* | 939 | /* |
940 | * We can't return errors to poll, so it's either yes or no. | 940 | * We can't return errors to poll, so it's either yes or no. |
941 | */ | 941 | */ |
942 | sock = SOCKET_I(file->f_dentry->d_inode); | 942 | sock = file->private_data; |
943 | return sock->ops->poll(file, sock, wait); | 943 | return sock->ops->poll(file, sock, wait); |
944 | } | 944 | } |
945 | 945 | ||
946 | static int sock_mmap(struct file * file, struct vm_area_struct * vma) | 946 | static int sock_mmap(struct file * file, struct vm_area_struct * vma) |
947 | { | 947 | { |
948 | struct socket *sock = SOCKET_I(file->f_dentry->d_inode); | 948 | struct socket *sock = file->private_data; |
949 | 949 | ||
950 | return sock->ops->mmap(file, sock, vma); | 950 | return sock->ops->mmap(file, sock, vma); |
951 | } | 951 | } |
@@ -995,7 +995,7 @@ static int sock_fasync(int fd, struct file *filp, int on) | |||
995 | return -ENOMEM; | 995 | return -ENOMEM; |
996 | } | 996 | } |
997 | 997 | ||
998 | sock = SOCKET_I(filp->f_dentry->d_inode); | 998 | sock = filp->private_data; |
999 | 999 | ||
1000 | if ((sk=sock->sk) == NULL) { | 1000 | if ((sk=sock->sk) == NULL) { |
1001 | kfree(fna); | 1001 | kfree(fna); |
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 5a7265aeaf83..ee6ae74cd1b2 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c | |||
@@ -160,7 +160,7 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, | |||
160 | " unsupported checksum %d", cksumtype); | 160 | " unsupported checksum %d", cksumtype); |
161 | goto out; | 161 | goto out; |
162 | } | 162 | } |
163 | if (!(tfm = crypto_alloc_tfm(cksumname, 0))) | 163 | if (!(tfm = crypto_alloc_tfm(cksumname, CRYPTO_TFM_REQ_MAY_SLEEP))) |
164 | goto out; | 164 | goto out; |
165 | cksum->len = crypto_tfm_alg_digestsize(tfm); | 165 | cksum->len = crypto_tfm_alg_digestsize(tfm); |
166 | if ((cksum->data = kmalloc(cksum->len, GFP_KERNEL)) == NULL) | 166 | if ((cksum->data = kmalloc(cksum->len, GFP_KERNEL)) == NULL) |
@@ -199,8 +199,7 @@ make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body, | |||
199 | crypto_digest_final(tfm, cksum->data); | 199 | crypto_digest_final(tfm, cksum->data); |
200 | code = 0; | 200 | code = 0; |
201 | out: | 201 | out: |
202 | if (tfm) | 202 | crypto_free_tfm(tfm); |
203 | crypto_free_tfm(tfm); | ||
204 | return code; | 203 | return code; |
205 | } | 204 | } |
206 | 205 | ||
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index cf726510df8e..606a8a82cafb 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c | |||
@@ -185,12 +185,9 @@ static void | |||
185 | gss_delete_sec_context_kerberos(void *internal_ctx) { | 185 | gss_delete_sec_context_kerberos(void *internal_ctx) { |
186 | struct krb5_ctx *kctx = internal_ctx; | 186 | struct krb5_ctx *kctx = internal_ctx; |
187 | 187 | ||
188 | if (kctx->seq) | 188 | crypto_free_tfm(kctx->seq); |
189 | crypto_free_tfm(kctx->seq); | 189 | crypto_free_tfm(kctx->enc); |
190 | if (kctx->enc) | 190 | kfree(kctx->mech_used.data); |
191 | crypto_free_tfm(kctx->enc); | ||
192 | if (kctx->mech_used.data) | ||
193 | kfree(kctx->mech_used.data); | ||
194 | kfree(kctx); | 191 | kfree(kctx); |
195 | } | 192 | } |
196 | 193 | ||
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c index dad05994c3eb..6c97d61baa9b 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_mech.c +++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c | |||
@@ -214,14 +214,10 @@ static void | |||
214 | gss_delete_sec_context_spkm3(void *internal_ctx) { | 214 | gss_delete_sec_context_spkm3(void *internal_ctx) { |
215 | struct spkm3_ctx *sctx = internal_ctx; | 215 | struct spkm3_ctx *sctx = internal_ctx; |
216 | 216 | ||
217 | if(sctx->derived_integ_key) | 217 | crypto_free_tfm(sctx->derived_integ_key); |
218 | crypto_free_tfm(sctx->derived_integ_key); | 218 | crypto_free_tfm(sctx->derived_conf_key); |
219 | if(sctx->derived_conf_key) | 219 | kfree(sctx->share_key.data); |
220 | crypto_free_tfm(sctx->derived_conf_key); | 220 | kfree(sctx->mech_used.data); |
221 | if(sctx->share_key.data) | ||
222 | kfree(sctx->share_key.data); | ||
223 | if(sctx->mech_used.data) | ||
224 | kfree(sctx->mech_used.data); | ||
225 | kfree(sctx); | 221 | kfree(sctx); |
226 | } | 222 | } |
227 | 223 | ||
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 5c8fe3bfc494..e3308195374e 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
@@ -250,6 +250,7 @@ out: | |||
250 | } | 250 | } |
251 | 251 | ||
252 | static struct cache_detail rsi_cache = { | 252 | static struct cache_detail rsi_cache = { |
253 | .owner = THIS_MODULE, | ||
253 | .hash_size = RSI_HASHMAX, | 254 | .hash_size = RSI_HASHMAX, |
254 | .hash_table = rsi_table, | 255 | .hash_table = rsi_table, |
255 | .name = "auth.rpcsec.init", | 256 | .name = "auth.rpcsec.init", |
@@ -436,6 +437,7 @@ out: | |||
436 | } | 437 | } |
437 | 438 | ||
438 | static struct cache_detail rsc_cache = { | 439 | static struct cache_detail rsc_cache = { |
440 | .owner = THIS_MODULE, | ||
439 | .hash_size = RSC_HASHMAX, | 441 | .hash_size = RSC_HASHMAX, |
440 | .hash_table = rsc_table, | 442 | .hash_table = rsc_table, |
441 | .name = "auth.rpcsec.context", | 443 | .name = "auth.rpcsec.context", |
@@ -1074,7 +1076,9 @@ gss_svc_init(void) | |||
1074 | void | 1076 | void |
1075 | gss_svc_shutdown(void) | 1077 | gss_svc_shutdown(void) |
1076 | { | 1078 | { |
1077 | cache_unregister(&rsc_cache); | 1079 | if (cache_unregister(&rsc_cache)) |
1078 | cache_unregister(&rsi_cache); | 1080 | printk(KERN_ERR "auth_rpcgss: failed to unregister rsc cache\n"); |
1081 | if (cache_unregister(&rsi_cache)) | ||
1082 | printk(KERN_ERR "auth_rpcgss: failed to unregister rsi cache\n"); | ||
1079 | svc_auth_unregister(RPC_AUTH_GSS); | 1083 | svc_auth_unregister(RPC_AUTH_GSS); |
1080 | } | 1084 | } |
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 900f5bc7e336..f509e9992767 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
@@ -177,7 +177,7 @@ void cache_register(struct cache_detail *cd) | |||
177 | cd->proc_ent = proc_mkdir(cd->name, proc_net_rpc); | 177 | cd->proc_ent = proc_mkdir(cd->name, proc_net_rpc); |
178 | if (cd->proc_ent) { | 178 | if (cd->proc_ent) { |
179 | struct proc_dir_entry *p; | 179 | struct proc_dir_entry *p; |
180 | cd->proc_ent->owner = THIS_MODULE; | 180 | cd->proc_ent->owner = cd->owner; |
181 | cd->channel_ent = cd->content_ent = NULL; | 181 | cd->channel_ent = cd->content_ent = NULL; |
182 | 182 | ||
183 | p = create_proc_entry("flush", S_IFREG|S_IRUSR|S_IWUSR, | 183 | p = create_proc_entry("flush", S_IFREG|S_IRUSR|S_IWUSR, |
@@ -185,7 +185,7 @@ void cache_register(struct cache_detail *cd) | |||
185 | cd->flush_ent = p; | 185 | cd->flush_ent = p; |
186 | if (p) { | 186 | if (p) { |
187 | p->proc_fops = &cache_flush_operations; | 187 | p->proc_fops = &cache_flush_operations; |
188 | p->owner = THIS_MODULE; | 188 | p->owner = cd->owner; |
189 | p->data = cd; | 189 | p->data = cd; |
190 | } | 190 | } |
191 | 191 | ||
@@ -195,7 +195,7 @@ void cache_register(struct cache_detail *cd) | |||
195 | cd->channel_ent = p; | 195 | cd->channel_ent = p; |
196 | if (p) { | 196 | if (p) { |
197 | p->proc_fops = &cache_file_operations; | 197 | p->proc_fops = &cache_file_operations; |
198 | p->owner = THIS_MODULE; | 198 | p->owner = cd->owner; |
199 | p->data = cd; | 199 | p->data = cd; |
200 | } | 200 | } |
201 | } | 201 | } |
@@ -205,7 +205,7 @@ void cache_register(struct cache_detail *cd) | |||
205 | cd->content_ent = p; | 205 | cd->content_ent = p; |
206 | if (p) { | 206 | if (p) { |
207 | p->proc_fops = &content_file_operations; | 207 | p->proc_fops = &content_file_operations; |
208 | p->owner = THIS_MODULE; | 208 | p->owner = cd->owner; |
209 | p->data = cd; | 209 | p->data = cd; |
210 | } | 210 | } |
211 | } | 211 | } |
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index fe1a73ce6cff..ded6c63f11ec 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Userland/kernel interface for rpcauth_gss. | 4 | * Userland/kernel interface for rpcauth_gss. |
5 | * Code shamelessly plagiarized from fs/nfsd/nfsctl.c | 5 | * Code shamelessly plagiarized from fs/nfsd/nfsctl.c |
6 | * and fs/driverfs/inode.c | 6 | * and fs/sysfs/inode.c |
7 | * | 7 | * |
8 | * Copyright (c) 2002, Trond Myklebust <trond.myklebust@fys.uio.no> | 8 | * Copyright (c) 2002, Trond Myklebust <trond.myklebust@fys.uio.no> |
9 | * | 9 | * |
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 9b67dc19944c..4979f226e285 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c | |||
@@ -35,13 +35,13 @@ static int rpc_proc_show(struct seq_file *seq, void *v) { | |||
35 | int i, j; | 35 | int i, j; |
36 | 36 | ||
37 | seq_printf(seq, | 37 | seq_printf(seq, |
38 | "net %d %d %d %d\n", | 38 | "net %u %u %u %u\n", |
39 | statp->netcnt, | 39 | statp->netcnt, |
40 | statp->netudpcnt, | 40 | statp->netudpcnt, |
41 | statp->nettcpcnt, | 41 | statp->nettcpcnt, |
42 | statp->nettcpconn); | 42 | statp->nettcpconn); |
43 | seq_printf(seq, | 43 | seq_printf(seq, |
44 | "rpc %d %d %d\n", | 44 | "rpc %u %u %u\n", |
45 | statp->rpccnt, | 45 | statp->rpccnt, |
46 | statp->rpcretrans, | 46 | statp->rpcretrans, |
47 | statp->rpcauthrefresh); | 47 | statp->rpcauthrefresh); |
@@ -50,10 +50,10 @@ static int rpc_proc_show(struct seq_file *seq, void *v) { | |||
50 | const struct rpc_version *vers = prog->version[i]; | 50 | const struct rpc_version *vers = prog->version[i]; |
51 | if (!vers) | 51 | if (!vers) |
52 | continue; | 52 | continue; |
53 | seq_printf(seq, "proc%d %d", | 53 | seq_printf(seq, "proc%u %u", |
54 | vers->number, vers->nrprocs); | 54 | vers->number, vers->nrprocs); |
55 | for (j = 0; j < vers->nrprocs; j++) | 55 | for (j = 0; j < vers->nrprocs; j++) |
56 | seq_printf(seq, " %d", | 56 | seq_printf(seq, " %u", |
57 | vers->procs[j].p_count); | 57 | vers->procs[j].p_count); |
58 | seq_putc(seq, '\n'); | 58 | seq_putc(seq, '\n'); |
59 | } | 59 | } |
@@ -83,13 +83,13 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) { | |||
83 | int i, j; | 83 | int i, j; |
84 | 84 | ||
85 | seq_printf(seq, | 85 | seq_printf(seq, |
86 | "net %d %d %d %d\n", | 86 | "net %u %u %u %u\n", |
87 | statp->netcnt, | 87 | statp->netcnt, |
88 | statp->netudpcnt, | 88 | statp->netudpcnt, |
89 | statp->nettcpcnt, | 89 | statp->nettcpcnt, |
90 | statp->nettcpconn); | 90 | statp->nettcpconn); |
91 | seq_printf(seq, | 91 | seq_printf(seq, |
92 | "rpc %d %d %d %d %d\n", | 92 | "rpc %u %u %u %u %u\n", |
93 | statp->rpccnt, | 93 | statp->rpccnt, |
94 | statp->rpcbadfmt+statp->rpcbadauth+statp->rpcbadclnt, | 94 | statp->rpcbadfmt+statp->rpcbadauth+statp->rpcbadclnt, |
95 | statp->rpcbadfmt, | 95 | statp->rpcbadfmt, |
@@ -99,9 +99,9 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) { | |||
99 | for (i = 0; i < prog->pg_nvers; i++) { | 99 | for (i = 0; i < prog->pg_nvers; i++) { |
100 | if (!(vers = prog->pg_vers[i]) || !(proc = vers->vs_proc)) | 100 | if (!(vers = prog->pg_vers[i]) || !(proc = vers->vs_proc)) |
101 | continue; | 101 | continue; |
102 | seq_printf(seq, "proc%d %d", i, vers->vs_nproc); | 102 | seq_printf(seq, "proc%d %u", i, vers->vs_nproc); |
103 | for (j = 0; j < vers->vs_nproc; j++, proc++) | 103 | for (j = 0; j < vers->vs_nproc; j++, proc++) |
104 | seq_printf(seq, " %d", proc->pc_count); | 104 | seq_printf(seq, " %u", proc->pc_count); |
105 | seq_putc(seq, '\n'); | 105 | seq_putc(seq, '\n'); |
106 | } | 106 | } |
107 | } | 107 | } |
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 62a073495276..ed48ff022d35 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c | |||
@@ -176,8 +176,10 @@ cleanup_sunrpc(void) | |||
176 | { | 176 | { |
177 | unregister_rpc_pipefs(); | 177 | unregister_rpc_pipefs(); |
178 | rpc_destroy_mempool(); | 178 | rpc_destroy_mempool(); |
179 | cache_unregister(&auth_domain_cache); | 179 | if (cache_unregister(&auth_domain_cache)) |
180 | cache_unregister(&ip_map_cache); | 180 | printk(KERN_ERR "sunrpc: failed to unregister auth_domain cache\n"); |
181 | if (cache_unregister(&ip_map_cache)) | ||
182 | printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n"); | ||
181 | #ifdef RPC_DEBUG | 183 | #ifdef RPC_DEBUG |
182 | rpc_unregister_sysctl(); | 184 | rpc_unregister_sysctl(); |
183 | #endif | 185 | #endif |
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c index bde8147ef2db..dda4f0c63511 100644 --- a/net/sunrpc/svcauth.c +++ b/net/sunrpc/svcauth.c | |||
@@ -143,6 +143,7 @@ static void auth_domain_drop(struct cache_head *item, struct cache_detail *cd) | |||
143 | 143 | ||
144 | 144 | ||
145 | struct cache_detail auth_domain_cache = { | 145 | struct cache_detail auth_domain_cache = { |
146 | .owner = THIS_MODULE, | ||
146 | .hash_size = DN_HASHMAX, | 147 | .hash_size = DN_HASHMAX, |
147 | .hash_table = auth_domain_table, | 148 | .hash_table = auth_domain_table, |
148 | .name = "auth.domain", | 149 | .name = "auth.domain", |
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index d6baf6fdf8a9..cac2e774dd81 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c | |||
@@ -242,6 +242,7 @@ static int ip_map_show(struct seq_file *m, | |||
242 | 242 | ||
243 | 243 | ||
244 | struct cache_detail ip_map_cache = { | 244 | struct cache_detail ip_map_cache = { |
245 | .owner = THIS_MODULE, | ||
245 | .hash_size = IP_HASHMAX, | 246 | .hash_size = IP_HASHMAX, |
246 | .hash_table = ip_table, | 247 | .hash_table = ip_table, |
247 | .name = "auth.unix.ip", | 248 | .name = "auth.unix.ip", |